Hi liebe Community,
aktuell programmiere ich auf einem Raspberry PI mit ARM11-Prozessor.
Laut Beschreibung besitzt dieser eine HW-FloatingPoint Unit, welche auch
vom Betriebssystem (Wheezy Raspbian) unterstützt wird.
Nun zu meiner/meinem Frage/Problem:
Bei einer Zeitmessung der Float-Multiplikation stellte sich heraus, dass
diese in etwa 50 Taktzylen benötigt. Dieser Wert erscheint mir doch sehr
utopisch. Dies entspricht nach meinen Erwartungen eher dem Wert einer
Soft-Float Multiplikation.
Ich habe darauf hin das Disassembly betrachtet um zu überprüfen ob
wirklich eine HW-Float-Multiplikation ausgeführt wird.
Dorch tauchen Assembler Befehle wie FMULS oder FLDS auf, was auf eine
HW-Multiplikation schließen lässt.
Habt ihr eine Idee ob ich irgendwas falsch mache oder ist die
Multiplikation wirklich so langsam?
Das stellt leider ein großes Problem für mich da, da ich mehrere FFTs in
"Echtzeit" verarbeiten und auswerten möchte.
Hier noch der Code, mit dem ich die Zeitmessung durchführe:
1
#include<stdlib.h>
2
#include<stdio.h>
3
#include<time.h>
4
#include<sys/time.h>
5
6
intmain(void)
7
{
8
structtimevaltim;
9
inti;
10
doublet1,t2,c;
11
floata=1.000001,b=1.00123;
12
13
gettimeofday(&tim,NULL);
14
t1=tim.tv_sec+(tim.tv_usec/1000000.0);
15
16
for(i=0;i<1e6;i++)
17
a*=b;
18
19
gettimeofday(&tim,NULL);
20
t2=tim.tv_sec+(tim.tv_usec/1000000.0);
21
22
c=t2-t1;
23
printf("%.6lf - %.6lf = %.6lf\n",t2,t1,c);
24
25
return(0);
26
}
Kompiliert habe ich das ganze mit folgendem Befehl:
Jakob K. schrieb:> for (i=0;i<1e6;i++)
Da steckt mit etwas Glück in jeder Iteration eine
Fliesskommakonvertierung drin. 1e6 ist keine Integer.
Falls das nicht ändert: Der Assembler-Code könnte helfen.
Zu erwarten wären 8 Takte für FMUL, laut Doku.
A. K. schrieb
> Da steckt mit etwas Glück in jeder Iteration eine> Fliesskommakonvertierung drin. 1e6 ist keine Integer.
Wenn ich zum Vergleich eine Integer-Variable verwende, veringert sich
die Anzahl auf etwa 30 Takte.
Wo hast du denn die Information mit den 8 Takten her? Ist dieser Wert
nur für die FMUL Anweisung oder die gesamte Multiplikation?
Die Multiplikaiton in der Schleife sieht folgendermaßen aus:
1
flds s14, [fp, #-12]
2
flds s15, [fp, #-20]
3
fmuls s15, s14, s15
Im Anhang ist der kompette Assembler-Code
Vielen Dank für die Tipps
Jakob K. schrieb:> Wenn ich zum Vergleich eine Integer-Variable verwende, veringert sich> die Anzahl auf etwa 30 Takte.
Für diesen Code sind 30 Takte eigentlich ganz ok:
1
.L3:
2
flds s14, [fp, #-12] ; a *= b;
3
flds s15, [fp, #-20]
4
fmuls s15, s14, s15
5
fsts s15, [fp, #-12]
6
7
ldr r3, [fp, #-8] ; i++
8
add r3, r3, #1
9
str r3, [fp, #-8]
10
.L2:
11
ldr r2, [fp, #-8] ; Schleife in aller Umständlichkeit
12
ldr r3, [fp, #-16]
13
cmp r2, r3
14
movge r3, #0
15
movlt r3, #1
16
uxtb r3, r3
17
cmp r3, #0
18
bne .L3
Mit Optimierung wird er entweder besser, oder - wahrscheinlicher -
verschwindet mangels verwendetem Ergebnis ganz. ;-)
A. K. schrieb:
> Mit Optimierung wird er entweder besser, oder - wahrscheinlicher -> verschwindet mangels verwendetem Ergebnis ganz. ;-)
Da bei der Optimierung die Schleife ganz raus fällt, habe ich die
Optimierung eben abgeschaltet.
Danke für den Link zum Datenblatt, hätte ich mal selber suchen sollen ;)
Berücksichtigt man neben der Multiplikation noch das Lesen/Schreiben der
Werte aus dem Speicher, kommt man schon auf ca. 20 Takte.
Ich bedanke mich für die großartige und schnelle Hilfe!
Jakob K. schrieb:> Da bei der Optimierung die Schleife ganz raus fällt, habe ich die> Optimierung eben abgeschaltet.
Es hätte ausgereicht, a im printf mit auszugeben.
Jakob K. schrieb:> Berücksichtigt man neben der Multiplikation noch das Lesen/Schreiben der> Werte aus dem Speicher, kommt man schon auf ca. 20 Takte.
Da die VFP-Unit gepipelined ist und die FLD Befehle nicht voneinander
abhängig sind brauchen die zusammen nur 5 Takte. Also FLD+FLD+FMUL+FST =
1+4+8+1=14.
Jakob K. schrieb:> Da bei der Optimierung die Schleife ganz raus fällt, habe ich die> Optimierung eben abgeschaltet.
Ohne Optimierungen brauchst du dich allerdings auch nicht zu wundern,
daß die Laufzeit sehr weit vom Optimum entfernt liegt.
So ich habe zur Vervollständigung noch mal eine Messung mit Optimierung
(und Ausgabe des Parameters) gemacht, und es ergibt sich der zuvor
erwähnte Wert von etwa 14 Zyklen.
A. K. schrieb:
>> Da die VFP-Unit gepipelined ist und die FLD Befehle nicht voneinander> abhängig sind brauchen die zusammen nur 5 Takte. Also FLD+FLD+FMUL+FST => 1+4+8+1=14.
Ok das hilft mir schon weiter, dann lässt sich zumindest ein kleiner
Teil parallelisieren. Ich hätte dazu noch ne kleine Frage. Entnehme ich
dem Handbuch des Prozessors (Seite 681) richtig, dass die CPU max. 3
Anweisungen parallel abarbeiten kann?
Jakob K. schrieb:> Entnehme ich> dem Handbuch des Prozessors (Seite 681) richtig, dass die CPU max. 3> Anweisungen parallel abarbeiten kann?
Je nach konkretem Befehlsmix scheint die VFP11 in der Lage zu sein, pro
Takt einen VFP-Befehl zu starten, auch wenn der einzelne davon 8 Takte
dauert. Wieviele Befehle das dann parallel sind bzw. im Idealfall sein
könnten, ist etwas Ansichtssache.
Lies dir das lieber mal vor vorne durch, also ab S.612. So ganz trivial
ist die VFP11-Unit nicht.
Die VFP des ARM11 implementiert keine SIMD Vektor Verabeitung wie, z.B.
NEON. Vielmehr gibt es Befehle die dazu führen, dass VFP Operationen
eigenständig in Schleifen über mehrere Register (Vektorelemente)
ausgeführt werden. Kein mir bekannter Compiler wird diese Befehle
automatisch erzeugen. Bestenfalls bekommst Du irgendwo eine Lib (z.B.
OpenMAX), die diese Funktionalität intern verwendet. Oder Du musst
selber ran :)
Ja, so hat sich mir das auch dargestellt. Der TO hat aber wahrscheinlich
erst einmal genug damit zu tun, die Arbeitsweise der Skalaroperationen
zu verstehen und einzuschätzen. ;-)