Forum: Mikrocontroller und Digitale Elektronik MSP430 MSGCC Performance


von Thomas (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Zusammen,

Ich messe gerade die Ausfürhrungszeit einer ISR (siehe Anhang).

timer_akt und timer_bak sind long (4bit) Variablen
Wenn ich die Anweisung

if(timer_akt<timer_bak)

auskommentiere, wird das Programm halb so gross (von 3kb auf 1.5),
und die ISR wird in 5 microsekunden statt in 300 ausgefürt.

Wie ist das zu erklären? Irgendwie stehe ich vor einem Rätsel,ich habe
zwar geschaut aber ich kann nichts darüber finden wie der Compiler das
ummsetzt.
Kann mir jemand auf Anhieb sagen wie mann das in assembler schreibt?

danke, gruss Thomas

von SupaChris (Gast)


Lesenswert?

Wenn die if-Anweisung nicht drin ist, lässt der Compiler die *1,5
Multiplikation weg. Solche Operationen dauern lange, und der
Mehrverbrauch an Speicher kommt sicherlich vom Einbinden einer
Gloating-Point-Lib.
Besser wäre es, die Multiplikation über den Hardwaremultiplizierer zu
machen, oder einfach die Hälfte des Timer-Wertes drauf addieren. Das
geht viel schneller.

z.B. so: timer_bak += (timer_bak/2);
oder timer_bak += (timer_bak >> 8); (wenn timer_bak eine 16-Bit
Variable ist)

von SupaChris (Gast)


Lesenswert?

Sollte natürlich "Floating-Point..." heißen. Vertippt nochmal.

von Thomas (Gast)


Lesenswert?

Hallo, danke für die Antwort,
aber die Multiplikation findet vor der If Abfrage statt.
Es besteht zwar auch ein unterschied ob ich die Multiplikation
auskommentiere oder nicht, aber der löwenanteil ist die

timer_akt*=1.5;  //ca 2 microsekunden
if(timer_akt<timer_bak)...  //ca. 250 Microsekunden

ich überlege die ganze Zeit wie ich die Abfrage mit jeweils 2 16bit
Variablen machen könnte statt der 32Bit.

gruss Thomas

von Dirk D. (dirkd)


Lesenswert?

Wenn Du sagst, daß Du die if Abfrage auskommentierst, sieht der Code
dann so aus?

timer_bak*=1.5;

/*
if (timer
...

else

...
*/
timer_bak=timer_akt;

In dem Fall würde ein Compiler die Multiplikation vermutlich
wegoptimieren, da timer_bak gleich danach mit einem anderen Wert
überschrieben wird.

Wie hast Du die Zeiten ermittelt?

Kannst Du Dir den generierten Assembler-Code ansehen? (Mit und ohne
If-Abfrage)

Laß mal die If-Abfrage drin und ersetz die Multiplikation durch ein
timer_bak *=2; und schau Dir dann die Code-Größe und die
Ausführungszeiten an.

von SupaChris (Gast)


Lesenswert?

Ja so meinte ich das auch. Wenn die If-Bedingung fehlt, ist die
Multiplikation sinnlos, deswegen lässt der Compiler die weg. So schlau
ist der schon.

von SupaChris (Gast)


Lesenswert?

Achso, jetzt les ich erst, dass du zwei 32 Bit Zahlen vergleichen
willst. Hmm...das kann natürlich je nach Übersetzungskunst des
Copmpilers auch eine Weile dauern. Besser wäre vielleicht, den Low- und
den Hig-Teil einzeln zu vergleichen, das spart sicher eine Menge
Rechenzeit. Aber eigentlich müsste der GCC doch auch das gleiche
machen. Komisch.

von Thomas (Gast)


Lesenswert?

Stimmt da habe ich gar nicht daran gedacht, ich habe mich schon
gewundert dass wenn ich die Multiplikation 3* hinereinander laufen
lasse und das if auskommentiert ist die Zeiten nicht grösser werden.

Ich habe die if jetzt drinn und die Multiplikation schaut jetzt so aus

timer_bak+= timer_bak/2;

ich komme jetzt auf MAX 10 Microsekunden.:-)
Wenn mann sonst nur am X86 Programiert macht mann sich um solche
"Kleinigkeiten" keinen Kopf g

Im Worst-Case Fall stehen mir 83 Microsekunden zwischen den Interrupts
zur Verfügung, allerdings würde ich die Zeit gerne noch weiter
drücken.
Wie sind die long Datentypen implementiert, bzw. würde es was bringen
wenn ich die long datentypen komplett weglassen würde?

Ich könnte ja den 32 Bit Timer_Wert nicht zusammen nehmen sondern
getrennt verarbeiten:

int tmp= timer_low;
timer_low+= timer_low/2;
if(timer_low<tmp) timer_h++;
timer_h+= timer_h/2;
Würde das so gehen? also praktisch die multiplikation in 2 teilen
ausführen?

Danke schon mal für die Hilfe,

gruss Thomas

von Thomas (Gast)


Lesenswert?

hallo Zusammen,

noch einer Frage, kann ich dem kompiler sagen, er soll aus
z.b. timer_akt/2 keine floating point machen, oder gibt es pronizipiel
keine?

Aus der MSPGCC doku werde ich da nicht ganz schlau?

danke, gruss Thomas

von A.K. (Gast)


Lesenswert?

"timer_akt/2" ist genau und nur dann eine floating point Rechnung,
wenn "timer_akt" eine Variable mit einem floating point Datentyp
ist.
Ansonsten ist es üblicherweise ein etwas verzierter (mit Vorzeichen)
oder ein einfacher (ohne VZ) Schiebebefehl.

von Thomas (Gast)


Lesenswert?

Habe gerade verucht in der ISR die 32Bit Variable

timer_akt/=divisor zu teiler und schon schnellt die zeit wieder auf 90
Microsekunden? Wie ist das zu erklären?

gruss Thomas

von A.K. (Gast)


Lesenswert?

Ist "divisor" dabei eine 2er-Potenz?
Ist Optimierung eingeschaltet?

Generische Division dauert halt etwas, vor allem wenn auch noch 32bit
auf 16bit Prozessor.

Anonsten rück mal den erzeugten Assembler-Code raus (gcc -S).

von A.K. (Gast)


Lesenswert?

PS: Wenn Vorzeichen nicht gebraucht wird, dann weg damit, also
"unsigned long" statt "long".

von Thomas (Gast)


Lesenswert?

Hallo,

Alle Variablen sind unsigned (habe ih mir angewöhnt, ausser ich brauch
expliziet signed),

ich habe mir das assemler listing angesehen es wird divmodsi4
aufgerufen.

Der Divisor wird zur laufzeit berechnet ist dann aber immer gleich(
zwischen 180 und 3)
der Quotient wird dann wieder mit Divisor - Variable) multipliziert.

gibt es da eine Bessere möglichkeit?

gruss Thomas

von A.K. (Gast)


Lesenswert?

Den Algorithmus so umbauen, dass entweder garnicht, oder nur durch eine
2er-Potenz-Konstante dividiert wird. Oder du ersetzt die Division durch
eine Multiplikation mit Kehrwert*(2**N) und anschliessendem Shift um N
(gibt evtl. falsche Rundung).

von Thomas (Gast)


Lesenswert?

Was meinst du mit Kehrert? Das 1 Komplement des Divisors? Was ist N?
Kannst du das nochmal näher erleutern?

danke Thomas

von A.K. (Gast)


Lesenswert?

http://de.wikipedia.org/wiki/Kehrwert

Mir ging es um die Division durch eine Konstante. Ist es keine
Konstante, dann hilft nur, den Algorithmus entsprechend umzubauen.

N ist ein Platzhalter. Matheunterricht verpennt?

X/Y = X*(1/Y). Ganzzahlig 1/X zu rechnen ist indes wenig ergiebig.
Bei 256/X sieht es schon besser aus. Also X/Y = (X*(256/Y))/256. Aus
dem /256 wird dann >>8, und schon ist die Division weg.

von Thomas (Gast)


Lesenswert?

Das N ein Platzhalter ist ist mir schon klar ;-) ich wusste nur nicht
für was.
Jetzt habe ich es verstanden. Danke.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.