Forum: Compiler & IDEs Takte pro Befehl


von Diddi (Gast)


Lesenswert?

Servus,
Ich programmiere gerade ein sehr "hochfrequentes" Programm.
Ich würde gerne wissen wieviel Takte bzw. Instruktionen für eine 
if-Abfrage und eine hochzählende for-Schleife benötigt werden.
Hier die Codeschnipsel:
1
if(abl2_A <= 0.005 && abl2_B <= 0.005){
abl2_A und abl2_B sind vom Typ double.
Und die for-Schleife:
1
for(i=0;i<=16;i++){
2
  data[i] = data[i+1];
3
}
i und data sind beide integer.

von Diddi (Gast)


Lesenswert?

Achso ich habe vergessen zu erwähnen, dass ich auf einem AVR mega8 mit 
16Mhz programmiere.
lg
Diddi

von Floh (Gast)


Lesenswert?

Methodisch:
Schau dir das Assemblerlisting an und zähle laut Datenblatt die 
benötigten Takte zusammen.
Praktisch:
Double und schnell beißt sich ganz arg.
:-)

von Peter D. (peda)


Lesenswert?

Lads in AVR-Studio, setzte Brechpunkte davor und dahinter und laß Dir 
den Zyklencounter anzeigen.


Peter

von Klaus K. (leo9)


Lesenswert?

mit cof-file ins Studio, hinsteppen, Stoppuhr auf Null, Schleife 
durchsteppen und Stoppuhr ablesen. Für Takte halt nocht durch F 
dividieren.

Grüße leo

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Diddi schrieb:

> Und die for-Schleife:
>
1
> for(i=0;i<=16;i++){
2
>   data[i] = data[i+1];
3
> }
4
>

Aha, eine pessimierte Reimplementierung von
1
memmove(data, data + 1, 16 * sizeof data[0]);

von Rolf Magnus (Gast)


Lesenswert?

Diddi schrieb:
> Ich programmiere gerade ein sehr "hochfrequentes" Programm.
> Ich würde gerne wissen wieviel Takte bzw. Instruktionen für eine
> if-Abfrage und eine hochzählende for-Schleife benötigt werden.

Die Zahl der Taktzyklen der for-Schleife dürfte im Vergleich zu den 
floating-point-Berechnungen auch nicht mehr weiter auffallen.

von Matthias L. (Gast)


Lesenswert?

Mich würde mal interessieren, was sinnvoller/effektiver ist:

[unter der Annahme das data ein 8Bit-Wert sit]

Das:
1
for(i=0;i<=16;i++)
2
{
3
  data[i] = data[i+1];
4
}

oder das:
1
i=0;
2
k=1;
3
while ( i != 16 )
4
{
5
  data[i++] = data[k++]
6
}

Also ich meine, eine Variable mit plus_eins, oder lieber zwei 
Hilfszähler..?

von Eugler (Gast)


Lesenswert?

Diddi schrieb:
> Achso ich habe vergessen zu erwähnen, dass ich auf einem AVR mega8 mit
> 16Mhz programmiere.
> lg
> Diddi

Peter Dannegger schrieb:
> Lads in AVR-Studio, setzte Brechpunkte davor und dahinter und laß Dir
> den Zyklencounter anzeigen.
>
>
> Peter

Wenn er das auf der Hardware packt .... Respekt! Geht das eigentlich 
auch im Simulator?

von Walter S. (avatar)


Lesenswert?

Jörg Wunsch schrieb:
>> Und die for-Schleife:
>>> for(i=0;i<=16;i++){
>>   data[i] = data[i+1];
>> }
>>
> Aha, eine pessimierte Reimplementierung von
> memmove(data, data + 1, 16 * sizeof data[0]);

kleine Korrektur:
memmove(data, data + 1, 17 * sizeof data[0]);

von Rolf Magnus (Gast)


Lesenswert?

Matthias Lipinsky schrieb:
> Also ich meine, eine Variable mit plus_eins, oder lieber zwei
> Hilfszähler..?

Am besten der Vorschlag von Jörg. Dann kann der Compiler sich drum 
kümmern, das möglichst effizient zu machen. Deine Schleifen werden beide 
im Bestfall vom Compiler automatisch durch memmove ersetzt, im 
schlechtesten Fall behindern sie die Optimierung.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Walter S. schrieb:

> kleine Korrektur:
> memmove(data, data + 1, 17 * sizeof data[0]);

Stimmt.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Matthias Lipinsky schrieb:
> Mich würde mal interessieren, was sinnvoller/effektiver ist:

Davon abgesehen, dass das zweite wegen eines fehlenden Semikolons
nicht compiliert und nur ein Element weniger als das erste kopiert,
erzeugt GCC ansonsten identischen Code.

von Masl (Gast)


Lesenswert?

Nur aus Interesse:
Warum ist die memmove Methode schneller?

Die wird doch intern auch mit irgend einer Art Schleife arbeiten, 
zusätzlich kommt noch der Funktionsaufruf und die sizeoff-Berechnung.

Klärt mich auf :-)

von (prx) A. K. (prx)


Lesenswert?

Masl schrieb:

> Warum ist die memmove Methode schneller?

Handoptimiert. Die sizeof() Rechnung ist kein Drama, mit 17 lässt sich 
recht effizient multiplizieren (16+1).

von X_movw (Gast)


Lesenswert?

Masl schrieb:
> Warum ist die memmove Methode schneller?

byte vs. word

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Masl schrieb:
> Warum ist die memmove Methode schneller?

Sie ist nicht per se schneller, hat aber die Chance, handoptimierten
Code zu benutzen, und sie ist halt standardisiert.  Solange du nicht
mit -ffreestanding arbeitest, darf dabei der Compiler auch statt der
Bibliotheksfunktion eine eigene Implementierung liefern, falls er der
Meinung ist, damit günstiger zu fahren.

Im vorliegenden Fall ist der Compiler mit dem expliziten C-Code
tatsächlich gar nicht so schlecht.

von Karl H. (kbuchegg)


Lesenswert?

Masl schrieb:
> Nur aus Interesse:
> Warum ist die memmove Methode schneller?

Ist sie nicht notwendigerweise

> Die wird doch intern auch mit irgend einer Art Schleife arbeiten,
> zusätzlich kommt noch der Funktionsaufruf und die sizeoff-Berechnung.
>
> Klärt mich auf :-)

Weil sie vom Compilerhersteller auf deine µC, dein Board, deinen 
speziellen Computer angepasst werden kann. Wenn dein Rechner über einen 
DMA Kanal verfügt, könnte der Compiler auch soweit gehen, den Transfer 
gar nicht über die CPU abzuarbeiten, sondern über DMA oder irgendwelche 
anderen Mechanismen, die du mit einer simplen Schleife nicht aktivieren 
kannst.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Karl Heinz Buchegger schrieb:

> Wenn dein Rechner über einen DMA Kanal verfügt,
> könnte der Compiler auch soweit gehen, den Transfer
> gar nicht über die CPU abzuarbeiten, sondern über DMA oder irgendwelche
> anderen Mechanismen, die du mit einer simplen Schleife nicht aktivieren
> kannst.

Es gibt Compiler, die memmove auf DMA abbilden??? Schwer vorzustellen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Johann L. schrieb:
> Es gibt Compiler, die memmove auf DMA abbilden??? Schwer vorzustellen.

Zumindest könnte eine Bibliotheksfunktion das problemlos tun.

von Karl H. (kbuchegg)


Lesenswert?

Johann L. schrieb:

>> gar nicht über die CPU abzuarbeiten, sondern über DMA oder irgendwelche
>> anderen Mechanismen, die du mit einer simplen Schleife nicht aktivieren
>> kannst.
>
> Es gibt Compiler, die memmove auf DMA abbilden??? Schwer vorzustellen.

Warum soll das schwer vorstellbar sein?
memmove ist eine Bibliotheksfunktion mit definierter Funktionalität. 
Wenn der Hersteller einen Weg findet, das schneller als mit einer 
CPU-Schleife zu machen, dann kann er das tun.

von (prx) A. K. (prx)


Lesenswert?

Johann L. schrieb:

> Es gibt Compiler, die memmove auf DMA abbilden??? Schwer vorzustellen.

Ausserdem nicht lohnend, weil eher langsamer als mit der CPU. Die 
üblichen DMA-Controller von Mikrocontrollern sind darauf nicht 
optimiert, auch wenn es funktionieren mag. Allenfalls als 
Background-Geschubse von langsamem externen Speicher kann das Sinn 
ergeben.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Jörg Wunsch schrieb:
> Johann L. schrieb:
>> Es gibt Compiler, die memmove auf DMA abbilden??? Schwer vorzustellen.
>
> Zumindest könnte eine Bibliotheksfunktion das problemlos tun.

Es geht weniger darum, ob sie es prinzipiell tun kann oder nicht, 
sondern ob es zum Standard passt, wenn die Implementierung damit 
beginnt, Hardware auf diese Weise zu verwenden und zu programmieren.

von Karl H. (kbuchegg)


Lesenswert?

Johann L. schrieb:

> Es geht weniger darum, ob sie es prinzipiell tun kann oder nicht,
> sondern ob es zum Standard passt, wenn die Implementierung damit
> beginnt, Hardware auf diese Weise zu verwenden und zu programmieren.

Johann, jetzt muss ich mich aber wundern.
Du weißt doch am allerbesten, dass der C-Standard so gut wie nichts über 
Hardware aussagt.

Aber: anderes Beispiel
Im Z80 gab es die Instruktionen LDIR, LDDR, etc. Ihre Funktion war 
prinzipiell die eines Block-Shifts. HL, DE, BC sind CPU-Register

ein LDIR machte (in relaxter Assembler / C Mischnotation)

1:  *(DE) = *(HL)
    HL++
    DE++
    BC--
    if BC == 0
      goto 1


wieviele Takte pro transferiertem Byte notwendig waren weiß ich nicht 
mehr. Es waren auf jeden Fall wesentlich weniger, als wie wenn man das 
selber ausprogrammiert.


Ob heutige Compiler eine Schleife

    for( i = 0; i < 100; i++ )
      dest[i] = src[i]

auf einem Z80 in

   LD  DE, #dest
   LD  HL, #src
   LD  BC, 100 * sizeof(*dest)
   LDIR

übersetzen würden, kann ich nicht sagen. Wohl auch deswegen, weil es 
kaum noch Z80 C-Compiler gibt. Aber in einem memmove ist das eine 
leichte Übung.

von Εrnst B. (ernst)


Angehängte Dateien:

Lesenswert?

Anderes Beispiel:

Die (alten) EZ-USB Chips hatten einen 8051er Befehlssatz, dort war das 
Speicher-Umkopieren über eine Schleife zu langsam für die erwünschte 
USB-Performance.

Deshalb gabs als Erweiterung die autopointer/autodata Register.
(siehe Datenblattschnippsel).

Der Compiler kannte die nicht und konnte die folglich auch nicht 
selbständing für die Optimierung einsetzen, aber innerhalb der lib 
konnte man die problemlos in memmove, memcpy, memset, strlen usw. 
verwursten.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Karl Heinz Buchegger schrieb:
> Johann L. schrieb:
>
>> Es geht weniger darum, ob sie es prinzipiell tun kann oder nicht,
>> sondern ob es zum Standard passt, wenn die Implementierung damit
>> beginnt, Hardware auf diese Weise zu verwenden und zu programmieren.
>
> Johann, jetzt muss ich mich aber wundern.
> Du weißt doch am allerbesten, dass der C-Standard so gut wie nichts über
> Hardware aussagt.

Der C-Standard ist eine Sache. Aber was bringt ein Compiler, der das, 
was nicht durch den Standard abgedeckt ist, zu 100% ausnutzt?

Ein Programmierer, der ein C Programm schreibt, braucht 3 Dinge:
1) Einen Sprachstandard, der Syntax und Semantik beschreibt.
2) Ein Compiler, der sich daran hält.
3) Ein Compiler, der "vernünftigen" Code erzeugt.

Je mehr Unwärbarkeiten des Standards ein Compiler ausschöpft, desto 
weniger wird 3) erfüllt sein. Der Compiler wäre dann zwar immer noch 
standardkonform, aber niemand würde ihn einsetzen, da witzlos.

Wem würde solch ein Compiler nutzen?

Beispiel: "volatile" wird durch die Implementierung definiert, mithin 
auch die Semantik von (mit der üblichen Definition von POTRC):

>> PORTC = 0;

Zunächst wird 0 nach PORTC geschrieben. Weil "PORTC = 0" ein Ausdruck 
ist, der auszuwerten ist und PORTC volatile ist, wird PORTC wieder 
zurückgelesen, analog zu

>> (void) PORTC;

oder

>> char a = PORTC = 0;

Das alles wäre durch den Standard abgedeckt. Aber würde irgendjemand das 
wollen? Ich behaupte: Nein.

Stell dir einfach vor, PORTC ist ein Latch.

Ergo: Den Standard zu erfüllen ist nicht alles. Wenn ein Compiler dabei 
rauskommt, der praktisch unbenutzbar ist, ist der Compiler zu 100% 
unbrauchbar und keinem gedient.

Nehmen wir also mal an, die Verwendung einer DMA sei transparent, d.h. 
deren Verwendung ist ausserhalb der abstrakten Maschine nicht 
wahrnehmbar. Dies bedeutet insbesondere, daß eine memmove Operation 
atomar ablaufen muss.

Ich stelle meine Frage also etwas anders: Ist eine DMA in memmove 
vorstellbar, so daß deren Verwendung nicht aus der abstrakten Maschine 
"entkommt" und zusätzlich 3) erfüllt bleibt?

von (prx) A. K. (prx)


Lesenswert?

Johann L. schrieb:

> Ich stelle meine Frage also etwas anders: Ist eine DMA in memmove
> vorstellbar, so daß deren Verwendung nicht aus der abstrakten Maschine
> "entkommt" und zusätzlich 3) erfüllt bleibt?

Atomare Ausführung aus Sicht der virtuellen Maschine ist nicht in jedem 
Fall zwingend. Die Nebenläufigkeit von DMA ist so lange kein Problem, 
wie der Compiler an passender Stelle auf dessen Beendigung wartet. Er 
könnte also den Transfer starten und mit anderem Code weiter machen, bis 
irgendwann einer der beiden Speicherbereiche benötigt wird oder er dies 
zumindest in Betracht ziehen muss.

Solange währenddessen nur lokale Daten ohne erforderliche Adresse 
verarbeitet werden ist das kein Problem, da es keine Überschneidung 
geben kann. Nur bei globalen Daten, und solchen deren Adresse irgendwo 
vorkommt, wird es komplizierter. Da besteht eine gewisse Verwandschaft 
zur Handhabung von potentiellem Aliasing bei Pointern.

Das ist im Grunde nicht viel anders als anno 8086, als der 8087 
Koprozessor seine Speicheroperationen nebenläufig durchführte und erst 
der WAIT-Befehl wieder für Ordnung sorgte (vgl. Warten auf Ende vom DMA, 
plus Barrier-Befehl).

Allerdings ist das natürlich eine sehr akademische Diskussion. Denn wer 
einigermassen bei Verstand ist, der programmiert so etwas explizit, 
statt es in einem Compiler einzubauen. Heutige und denen ähnliche 
Architekturen vorausgesetzt.

Und bei jenen Zwergen wie dem erwähten 51er, bei dem es sich ggf. lohnen 
kann weil die programmierte Version viel langsamer ist, ist eine rein 
atomare Version, also mit sofortigem Warten auf Beendigung, auch schon 
sinnvoll. Nebenläufigkeit erwartet man in solchem Kontext wohl nicht 
wirklich.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Es ist ja nicht nur Nebenläufighkeit Code <-> DMA, dondern der 
auszuführende Code kann in einer beliebig tief verschachtelten 
ISR-Hierarchie ablaufen.

von (prx) A. K. (prx)


Lesenswert?

Das ist aber bei DMA auch nicht anders als bei CPU-Registern. Kaputt 
machen gilt nicht. Wenn DMA grad aktiv, dann verboten, andernfalls 
vorherigen Zustand sichern und später wiederherstellen.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Der Unterschied ist aber, daß ein Compiler den Worst-Case annehmen muss, 
während eine Applikation die DMA etc. verwendet viel implizites Wissen 
über deren Verwendung hat, welches einem Compiler nicht zur Verfügung 
steht.

von (prx) A. K. (prx)


Lesenswert?

Deshalb schrieb ich oben ja, dass diese Diskussion sehr akademisch sei.
Man könnte DMA zwar dazu verwenden, es ist aber kaum sinnvoll.

von Karl H. (kbuchegg)


Lesenswert?

OK, OK.
Ich gestehs dir zu: DMA war vielleicht wirklich kein sinnvoller Begriff.

Nichts desto trotz ändert das ja nix an der Aussage: memmove macht die 
Dinge nicht schlechter als eine selbst geschriebene Schleife, kann aber 
schneller sein.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Diddi schrieb:
> Servus,
> Ich programmiere gerade ein sehr "hochfrequentes" Programm.
> Ich würde gerne wissen wieviel Takte bzw. Instruktionen für eine
> if-Abfrage und eine hochzählende for-Schleife benötigt werden.
> Hier die Codeschnipsel:
>
> [...] double [...]

Diddi schrieb:
> ATmega8 mit 16Mhz

*hüstel* 

Du verwendest also double auf einem ATmega8 und machst dir nen Kopf um 
eine if-Abfrage?

Bevor du anfängst an der if-Abfrage zu knaupen solltest du dir 
überlegen, *wo* die Zeit für dein "hochfrequentes" Programm denn 
verloren geht.

Erst profilen. Dann optimiern. Und zwar das, was dir die Ressource 
frisst.

Wenn etwas im Code zB 90% der Resource braucht und das 10% besser wird, 
bringt das 9× mehr, als etwas das nur 1% braucht um 99% zu verbessern!

von Diddi (Gast)


Lesenswert?

Danke für die vielen Antworten.
Ich habe mein Programm mal analysiert mit der Stop Watch stelle aber 
keinerlei Unterschied zwischen double und float fesst. Float(4 Byte) 
müsste doch deutlich schneller sein wie double(8 Byte). Dies ist 
allerdings nicht der Fall. Leider kann ich nicht auf die Fließkomma 
Berechnungen verzichten.

von Rolf M. (rmagnus)


Lesenswert?

Diddi schrieb:
> Ich habe mein Programm mal analysiert mit der Stop Watch stelle aber
> keinerlei Unterschied zwischen double und float fesst. Float(4 Byte)
> müsste doch deutlich schneller sein wie double(8 Byte).

Das liegt daran, daß auf einem AVR double auch nur 4 Byte groß ist (auch 
wenn das eigentlich nicht ISO-konform ist).

von Helmut S. (helmuts)


Lesenswert?

> Leider kann ich nicht auf die Fließkomma
Berechnungen verzichten.

Ich gehe mal davon aus, dass du wirklich die Genauigkeit von "double" 
brauchst. Da dein AVR-Compiler gar kein "double" kann, solltest du zu 
einem anderen Prozessor greifen bei dem ein Compiler für "double" 
verfügbar ist.

von ... (Gast)


Lesenswert?

Floh schrieb:
> Schau dir das Assemblerlisting an und zähle laut Datenblatt die
> benötigten Takte zusammen.

Wenn man nicht ganz so masochistisch veranlagt ist, kann man auch die 
Stop-Watch in AVR-Studio benutzen und dort im Simulator die Anzahl der 
benötigten Taktzyklen ablesen.

von Karl H. (kbuchegg)


Lesenswert?

Diddi schrieb:

> allerdings nicht der Fall. Leider kann ich nicht auf die Fließkomma
> Berechnungen verzichten.

Das kann schon sein. Kann aber auch nicht sein.

Wenn du das Zeug mal herzeigst, kannn sich wer überlegen, ob ihm eine 
Alternative einfällt.

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.