www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik MSP430 MSGCC Performance


Autor: Thomas (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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

Autor: SupaChris (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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)

Autor: SupaChris (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sollte natürlich "Floating-Point..." heißen. Vertippt nochmal.

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Dirk Dörr (dirkd)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: SupaChris (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: SupaChris (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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).

Autor: A.K. (Gast)
Datum:

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

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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).

Autor: Thomas (Gast)
Datum:

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

danke Thomas

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Thomas (Gast)
Datum:

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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.