Ich würde gerne wissen wie schnell mein AVR rechnen kann und habe auch
schon ein Testprogramm für eine Floatmultiplikation geschrieben. Doch
wenn ich die Compileroptimierung einschalte, dann wird meine Berechnung
wegoptimiert. Wie kann ich aber trotzdem herausfinden wie schnell mein
AVR mit eingeschalteter Optimierung rechnet? Vielleicht ist diese Frage
für einige trivial, aber ich bin noch Anfänger .....
Hier noch mein Testprogramm
WOW! Das ging aber schnell :)
Habe jetzt das Programm mit volatile geändert. Doch jetzt bin ich
verwirrter als vorher. Irgendwie ist mir das Ergebnis nicht ganz klar.
Folgende Szenarien habe ich getestet:
Optimierung most: -O3
float x,y
float erg
=> Dauer: 2µs
float x,y
volatile float erg
=> Dauer: 1,1ms
volatile float x,y
volatile float erg
=> Dauer: 38,0ms
volatile float x,y
float erg
=> Dauer: 1,9ms
Wie lange dauert denn nun eine float Multiplikation auf einem AVR? Gibt
es dafür vielleicht ein standadisiertes Messverfahren? z.B. einen AVR
Speedtest?
Der compiler koennte auch smart sein. Eine Multiplikation mit 2^N, resp
2^-N ist auch nur ein Shift, dh ein Exponent. Daher sollte man die Daten
per Kommunikation einspeisen.
ber luska schrieb:> verwirrter als vorher. Irgendwie ist mir das Ergebnis nicht ganz klar.
Du musst dir im klaren sein, welche Optimierungen du dem COmpiler
jeweils offen lässt. Und du musst dir im klaren sein, dass der COmpiler
jede Möglichkeit ausnutzen wird, die du ihm lässt.
In
1
floatx=9876.54321;
2
floaty=1234.56789;
3
volatilefloaterg=0;
4
5
...
6
erg=x*y;
... muss da tatsächlich multipliziert werden? x ändert sich nicht, y
ändert sich nicht, die Zahlenwerte sind bekannt. D.h. der Compiler kann
das Ergebnis für x*y bereits ausrechnen und das ganze kürzen zu
1
erg=12193263.1112635269;
d.h. wenn der Compiler diese Optimierung gemacht hat, was man im
Assembler-Code sehen würde) dann hast du wegen den volatile erg
gemessen, wie lange 100 float Zuweisungen dauern.
Der Compiler ist nicht völlig Doof. Bei deinem ersten Beispiel "merkt"
er, dass Du zwar rechnest, das Ergebnis aber nicht verwendest: Also raus
damit.
Die Laufzeit von Fließkommaberechnungen ist ganz schwer einzuschätzen,
da sie zum Teil von den Zahlen selbst abhängt und natürlich vom Typ der
Operation.
Verglichen mit normaler Ganzzahlarithmetik heiß das: Ewig und drei Tage
bzw. vermeide sie.
ber luska schrieb:> Zusammenfassend kann ich also sagen, dass mein AVR für eine float> Multiplikation mit den oben gewählten Zahlen 380µs benötigt?!?
So ungefähr.
Denn du hast ja nicht nur die Multiplikation gemessen.
Du hast ja auch gemessen, wie lange die Zuweisung dauert und in der Zeit
ist auch die Schleifensteuerung der for-Schleife drinnen.
ber luska schrieb:> Zusammenfassend kann ich also sagen, dass mein AVR für eine float> Multiplikation mit den oben gewählten Zahlen 380µs benötigt?!?
Im Prinzip ja.
Wenn du es ganz genau haben möchtest, musst du noch den Overhead durch
die Schleife und die RAM-Zugriffe für die drei Variablen herausrechnen.
Das geht folgendermaßen:
1
#include<stdint.h>
2
#include<avr/io.h>
3
4
intmain(void)
5
{
6
DDRA=0xFF;
7
PORTA=0x00;
8
volatilefloatx=9876.54321;
9
volatilefloaty=1234.56789;
10
volatilefloaterg;
11
uint8_ti;
12
13
while(1)
14
{
15
PORTA|=(1<<PINA0);
16
for(i=0;i<100;i++)
17
{
18
erg=x*y;
19
}
20
PORTA&=~(1<<PINA0);
21
22
PORTA|=(1<<PINA1);
23
for(i=0;i<100;i++)
24
{
25
erg=x,y;
26
}
27
PORTA&=~(1<<PINA1);
28
}
29
}
Die Dauer der reinen Multiplikation (also die Ausführung von call
__mulsf3) ist
Edit:
Die Zeit von 380µs erscheint mir etwas lang. Welchen AVR und welche
Taktfrequenz verwendest du? Hast du die Option -lm angegeben (bei
AVR-GCC 4.8 nicht mehr nötig)?
Danke Yalu X. für die professionelle Antwort. Ich habe hier nur einen
kleinen ATtiny der mit einem internen Oszi auf 8MHz läuft.
Sollte dieser wohl schneller rechnen? Bin leider noch nicht ganz so tief
in der Materie. Was sich aber bald ändern wird, bei soviel Kompetenz
hier im Board :)
Noch 2 Fragen auf die ich keine Antwort im Netz fand:
Was macht die Codezeile erg = x , y; Im Debugger wird erg nur der Wert
von x zugewiesen.
Was bewirkt die Compileroption -lm? Verwende Atmel Studio 6.1
Siebzehn mal Fuenfzehn schrieb:> Fuer eine Steuerung sollte man Floating point vermeiden, fuer ein> langsames Benutzerinterface ist Float akzeptierbar
Immer wieder die gleichen Vorurteile.
Als Faustformel für FMUL und FDIV auf einem AVR mit 16MHz nehme ich
20-30µs an. Von der Ausführungszeit besteht kein großer Unterschied ob
man MUL mit zwei int32_t oder zwei float-Varialen rechnen läßt, sofern
man die Sonderfälle wie 0, 1 oder -1 als Multipli/-kator -kant mal außen
vor läßt.
In der Codesammlung iat ein Beitrag
Beitrag "Frequenz / Drehzahl, 4-stell. 7-Segm.-LCD, ATtiny45" wo ich zunächst mit
int32_t gerechnet habe, weil ich dachte, float würde zu umfangreich
werden.
Zuletzt habe ich dann doch float-Berechnungen genommen, die wesentlich
einfacher und transparenter sind.
Fazit: wenn man float braucht, soll man auch float verwenden.
Beim AVR-Studio muß man unter "Project -> configuration options ->
Libraries" die "libm.a" auswählen. Dann wird der Code nicht wesentlich
vergrößert, sodass er auch auf ATtinyxx paßt.
ber luska schrieb:> Ich habe hier nur einen kleinen ATtiny der mit einem internen Oszi auf> 8MHz läuft.
Ok, der ATtiny hat keinen Multiplizierer an Bord, dann darf er auch
etwas länger brauchen. Ein ATmega sollte die Multiplikation bei gleicher
Taktfrequenz ein ganzes Stück schneller als ein ATtiny ausführen.
> Sollte dieser wohl schneller rechnen? Bin leider noch nicht ganz so tief> in der Materie. Was sich aber bald ändern wird, bei soviel Kompetenz> hier im Board :)>> Noch 2 Fragen auf die ich keine Antwort im Netz fand:> Was macht die Codezeile erg = x , y; Im Debugger wird erg nur der Wert> von x zugewiesen.
Der Kommaoperator wertet zuerst den linken Operanden (in diesem Fall x)
aus, dann den rechten (y). Das Gesamtergebnis ist das Ergebnis des
rechten Operanden, das Ergebnis des linken Operanden wird
weggeschmissen.
In diesem Fall soll einfach nur erreicht werden, dass x und y gelesen
und erg geschrieben wird. Bei erg=x*y passiert genau das Gleiche, nur
dass zusätzlich noch die Multiplikation ausgeführt wird. Die Differenz
der beiden Ausführungszeiten ist somit die für die Multiplikation
benötigte Zeit. Auch der Schleifenoverhead ist in beiden Fällen
derselbe, so dass durch die Defferenzbildung auch dieser herausgerechnet
wird.
> Was bewirkt die Compileroption -lm? Verwende Atmel Studio 6.1
Es gibt in der AVR-GCC-Toolchain zwei Bibliotheken mit
FP-Grundrechenarten: Eine wird mit dem GCC mitgeliefert und eine mit der
AVR-Libc. Letztere ist stark optimiert, erstere nicht. Die
Ausführungszeiten und der Programmspeicherplatzbedarf sind bei der
AVR-Libc-Variante deutlich geringer. Die AVR-Libc-FP-Bibliothek kommt
aber bis GCC 4.6.x und teilweise 4.7.x nur durch explizites Linken der
libm zum Einsatz, und das geschieht durch die Angabe von -lm im
GCC-Aufruf. Werden Funktionen wie sqrt, sin, log usw. benutzt, braucht
man die libm (also -lm) sowieso, da diese Funktionen in der
GCC_Bibliothek nicht vorhanden sind.
Ab AVR-GCC 4.8 werden die FP-Routinen defaultmäßig aus der AVR-Libc
genommen, weswegen hier das -lm nur dann benötigt wird, wenn man
zusätzlich zu den Grundrechenarten die o. g. mathematischen Funktionen
verwendet.
Je nach Entwicklungsumgebung wird die Verwendung der libm evtl. anders
eingestellt, siehe hier:
M. N. schrieb:> Beim AVR-Studio muß man unter "Project -> configuration options ->> Libraries" die "libm.a" auswählen. Dann wird der Code nicht wesentlich> vergrößert, sodass er auch auf ATtinyxx paßt.