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
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)
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
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.
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.
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.
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
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
"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.
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
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).
PS: Wenn Vorzeichen nicht gebraucht wird, dann weg damit, also "unsigned long" statt "long".
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
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).
Was meinst du mit Kehrert? Das 1 Komplement des Divisors? Was ist N? Kannst du das nochmal näher erleutern? danke Thomas
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.