Forum: Mikrocontroller und Digitale Elektronik Nötige Takte für Codeabschnitt herausfinden


von AVR (Gast)


Lesenswert?

Hallo!

Bin auf der Suche nach einer (möglichst einfachen) Möglichkeit, 
herauszufinden, wie viele Takte ein bestimmter Code-Abschnitt eines 
Programms für einen ATmega8 oder ATmega328P Prozessor braucht.

Ich programmiere unter Linux auf Eclipse.

Am liebsten wäre es mir, wenn ich einfach einen Code-Abschnitt markieren 
würde und dann nach ein paar Klicks die Zahl der benötigten Takte hätte.

Bin aber auch für jede andere Möglichkeit offen. (Sollte aber unter 
Linux funktionieren...)

Danke im Voraus!

Gruß

von W.A. (Gast)


Lesenswert?

AVR schrieb im Beitrag #4740875:
> Bin auf der Suche nach einer (möglichst einfachen) Möglichkeit,

Nimm einen Simulator. Das ging z.B. AvrStudio 4.19 schon vor etliche 
Jahren. Dort bekam man während des Debuggings direkt die Takte 
angezeigt, auch zwischen Breakpoints. Keine Ahnung, wie sich die Dinge 
bei den aufgebohrten VisualStudio/Eclipse Umgebungen entwickelt haben.

von Daniel A. (daniel-a)


Lesenswert?

AVR schrieb im Beitrag #4740875:
> Am liebsten wäre es mir, wenn ich einfach einen Code-Abschnitt markieren
> würde und dann nach ein paar Klicks die Zahl der benötigten Takte hätte.

Das geht nicht einfach so, weil ein Codeabschnitt nicht immer gleich 
viele takte braucht, folgenden Gründen:
 1) Verschiedene Compiler optionen führen zu unterschiedlichem code
 2) Der Compiler kann sich jederzeit Entscheiden, den code zur 
abwechslung mal zu Inlinen, etc.
 3) Sobald Schleifen oder Bedingungen, etc. vorhanden sind, sind die 
Anzahl takte von den Eingangswerten aghängig.

Deshalb muss man sich entweder mit dem Assembler listing 
auseinandersetzen, oder man nutzt einen Profiler um die durchschnittlich 
dort verbratene Zeit zu ermitteln oder einen Debugger.

von AVR (Gast)


Lesenswert?

Danke für eure Rückmeldungen!

Mir wäre es schon Recht, wenn ich zu einem bestimmten Abschnitt C-Code 
den Assembler Code angezeigt bekommen könnte. (Dann könnte ich natürlich 
mit Hilfe einer Tabelle schauen, wie lang die einzelnen Befehle brauchen 
und es addieren)

Gibt es dazu eine (einfache) Möglichkeit?

von Karl M. (Gast)


Lesenswert?

Hallo,

der avr gcc kann eine *.lss Datei erstellen, die dann die Assembler 
Mnemonic enthalten.


Siehe unter *Resources*:
http://www.csee.umbc.edu/~alnel1/cmpe311/notes/AVRAssemblerExamples.pdf

von Wolfgang (Gast)


Lesenswert?

AVR schrieb im Beitrag #4740875:
> Am liebsten wäre es mir, wenn ich einfach einen Code-Abschnitt markieren
> würde

Setze davor und danach einen Befehl zum Tooglen eine IO-Pins. Dann 
kannst du auf einem Oszi oder LA zusehen, wann sich das Programm in dem 
Code-Abschnitt rumtreibt.

von db8fs (Gast)


Lesenswert?

Wolfgang schrieb:
> Setze davor und danach einen Befehl zum Tooglen eine IO-Pins. Dann
> kannst du auf einem Oszi oder LA zusehen, wann sich das Programm in dem
> Code-Abschnitt rumtreibt.

Jo, das ist ne gute Variante. Oder halt im AVR-Simulator den Zeitpunkt 
vor Eintritt der Routine messen bis zum Abschluss davon.

Nur so interessehalber würde mich allerdings auch interessieren, ob man 
das mit den Mitteln vom AVR-GCC (bzw. GCC allgemein) über das Profiling 
lösen kann (also eher akademischer Ansatz):

Stelle mir das aber eher kompliziert vor: mit dem Profiling-Zeug vom GCC 
(gcov) da Zähler für einzelne Codeabschnitte erzeugen und bei Ausführung 
vom Simulator die Durchläufe zählen lassen. Das dann auch nur auf die 
ASM-Labels abbilden, die durch gcov auch referenziert wurden. In 
Verbindung mit 'ner Kostentabelle für jeden Mnemonic könnte dann die 
effektive Anzahl ermittelt werden.

Weiß leider nicht, ob bzw. wie gut derartiges Wissen vom Optimizer zur 
Compilezeit zu ermitteln ist. Der Satz von Rice sagt mir da: eher nicht 
(Thema Endlosschleifen/Entscheidbarkeit). Ohne Umweg über 'nen Debugger 
würde da vermutlich was fehlen.

von Sascha_ (Gast)


Lesenswert?

Der Instruction Pointer würde sich dafür anbieten, aber Google sagt mir 
dass man an den gar nicht so einfach rankommt.
Und Profiling an sich ist ist scheinbar in avr-gcc rudimentär 
implementiert, aber nicht benutzbar.

Mein Workaround wäre: 16 Bit Timer ohne Prescaler (also mit fcpu) laufen 
lassen und dann nach dem zu profilenden Codeabschnitt stoppen und Wert 
abfragen. Das sind dann die benötigten CPU Zyklen (inklusive dem, was 
für An- und Abschalten des Timers notwendig war. Es gibt also eine 
konstante Messabweichung die man bei kurzen Zeiten abziehen muss).

Den Integer kannste dir dann über UART rausschicken, sowas:

"Func1 hat 1221 Takte gebraucht"

von db8fs (Gast)


Lesenswert?

Sascha_ schrieb:
> Der Instruction Pointer würde sich dafür anbieten, aber Google
> sagt mir
> dass man an den gar nicht so einfach rankommt.
> Und Profiling an sich ist ist scheinbar in avr-gcc rudimentär
> implementiert, aber nicht benutzbar.

Hmm, sehe ich ein, dass der AVR-GCC da bezüglich Profiling/CodeCoverage 
Limitierungen hat. Wäre vielleicht für den ARM-Port ganz interessant, ob 
es da ginge.

Das mit dem IP beim AVR ist mir nicht klar, woran will man daran denn 
etwa Schleifen feststellen können?

> Mein Workaround wäre: 16 Bit Timer ohne Prescaler (also mit fcpu) laufen
> lassen und dann nach dem zu profilenden Codeabschnitt stoppen und Wert
> abfragen. Das sind dann die benötigten CPU Zyklen (inklusive dem, was
> für An- und Abschalten des Timers notwendig war. Es gibt also eine
> konstante Messabweichung die man bei kurzen Zeiten abziehen muss).
>
> Den Integer kannste dir dann über UART rausschicken, sowas:
>
> "Func1 hat 1221 Takte gebraucht"

Ok, jo, das wäre 'ne Messung ohne direkten Debugger, nur durch Tracen.

von Sascha_ (Gast)


Lesenswert?

>
> Das mit dem IP beim AVR ist mir nicht klar, woran will man daran denn
> etwa Schleifen feststellen können?

Jo, das muss man dann händisch machen. Vor jedem Jump den IP auf ne 
Variable summieren, also bei ner Schleife als letzte Anweisung innerhalb 
der Schleife.
Je nach Komplexität des Programms kann das in Arbeit ausarten.

von Sascha_ (Gast)


Lesenswert?

Meine Studienarbeit war ein Class-D Amp und da kommt man sehr schnell an 
den Punkt wo die CPU die ganze Zeit ausgelastet ist.

Mein Ansatz war einfach, den Code von Anfang an möglichst effizient zu 
schreiben.
Mein Ringpuffer hat den Wraparound 255++ = 0 ausgenutzt, alle Divisionen 
waren Shifts (FIR in Matlab entsprechend konstruiert) usw.

Und dann hab ich tatsächlich im Datenblatt geguckt welche Operationen 
wie lange dauern. Das steht da ja drin, man muss nur die Wertebereiche 
kennen, in denen man unterwegs ist. 8 Bit, 16 Bit, 24 Bit machen jeweils 
riesige Unterschiede.

Warum ich das gemacht habe weiss ich nicht mehr ganz genau, aber es wird 
wohl auch damit zu tun gehabt haben dass es kein Profiling-Tool gab und 
ich noch nichtmal nen zweiten USB-UART Converter hatte. Musste für 
Seriell immer am STK500 umstecken.

Ergo: Du bist nicht der Erste mit dem Problem und vermutlich auch nicht 
der Letzte.

von db8fs (Gast)


Lesenswert?

Sascha_ schrieb:
>>
>> Das mit dem IP beim AVR ist mir nicht klar, woran will man daran denn
>> etwa Schleifen feststellen können?
>
> Jo, das muss man dann händisch machen. Vor jedem Jump den IP auf ne
> Variable summieren, also bei ner Schleife als letzte Anweisung innerhalb
> der Schleife.
> Je nach Komplexität des Programms kann das in Arbeit ausarten.

Hmm, wäre ich fast zu faul dazu. :)

<WünschDirWasModus>

Scheene wär halt, 'ne Art Testsuite zu schreiben für die Funktionen, die 
man profilen möchte, den jeweiligen Testcase durch nen Simulator jagen 
und am Ende die Laufzeitkosten pro Testcase herauszukriegen. Mit 
CTest/Boost::Test geht das ja so für Hostbuilds, und ich nehm an, mit 
QEmu auch näherungsweise für Cross-Builds. Die Abbildung auf 
ASM-Instruktionen wäre da das Tüpfelchen auf dem i - nur müsste das halt 
vermutlich in Verbindung mit gcov gelöst werden.

Könnte ich mir aber als ein nützliches Tool vorstellen, was auch 
funktionieren könnte (solange der Testcase terminiert).

</WünschDirWasModus>

von Amateur (Gast)


Lesenswert?

>Nimm einen Simulator. Das ging z.B. AvrStudio 4.19 schon vor etliche
>Jahren. Dort bekam man während des Debuggings direkt die Takte
>angezeigt, auch zwischen Breakpoints.

Die Anzeige war aber eher mittelprächtig.

Zwar zeigte der Simulator tatsächlich die "verbrauchten" Takte an, aber 
nur mit den gerade aktuellen Werten. Daher konnte der nächste Durchlauf 
bereits völlig andere Werte ergeben.
Egal wie "heutige" Simulatoren auch arbeiten, das Problem, des variablen 
Weges, lässt sich nicht unter den Tisch kehren.
Werden externe Bibliotheken, wie z.B. die Fließkommaarithmetik, 
verwendet, so können winzige Änderungen der Startvariablen, riesige 
Unterschiede bewirken.

von prg (Gast)


Lesenswert?

Es wurde schon gesagt: Assembler Code vom Compiler ausgeben lassen und 
dann via Datenblatt nachschlagen, welcher Befehl wie viele Zyklen 
braucht.

von db8fs (Gast)


Lesenswert?

Amateur schrieb:
>>Nimm einen Simulator. Das ging z.B. AvrStudio 4.19 schon vor
> etliche
>>Jahren. Dort bekam man während des Debuggings direkt die Takte
>>angezeigt, auch zwischen Breakpoints.
>
> Die Anzeige war aber eher mittelprächtig.

Na ja, aber besser als in die hohle Hand gesch*ssen.

> Zwar zeigte der Simulator tatsächlich die "verbrauchten" Takte an, aber
> nur mit den gerade aktuellen Werten. Daher konnte der nächste Durchlauf
> bereits völlig andere Werte ergeben.
> Egal wie "heutige" Simulatoren auch arbeiten, das Problem, des variablen
> Weges, lässt sich nicht unter den Tisch kehren.

ACK. Daher der Vorschlag, das auf Basis von Testcases zu machen, wo im 
Testcase die Rahmenbedingungen vorher definiert werden.

> Werden externe Bibliotheken, wie z.B. die Fließkommaarithmetik,
> verwendet, so können winzige Änderungen der Startvariablen, riesige
> Unterschiede bewirken.

Jo. Daher wär so eine Tracer für die Mnemonics innerhalb eines Testcases 
schon cool. Weiß nicht, ob man die Simulatoren bzw. den GDB so umbiegen 
kann, dass der die ausgeführte Instruktion einfach in nem Trace 
wegschreibt - wertet man den Log dann aus, müsste das dann auch die 
reinen seriellen Kosten widerspiegeln.

So könnte man sich wohl auch den gcov-Kram sparen (der aber eigentlich 
auch ganz schön ist um vernachlässigte Codeabschnitte zu 
identifizieren).

von db8fs (Gast)


Lesenswert?

prg schrieb:
> Es wurde schon gesagt: Assembler Code vom Compiler ausgeben lassen
> und
> dann via Datenblatt nachschlagen, welcher Befehl wie viele Zyklen
> braucht.

Klar geht das, aber der Trick ist doch, herauszukriegen, wie man sowas 
automatisieren kann um sich diese Arbeit zu sparen oder wenigstens zu 
vereinfachen.

von db8fs (Gast)


Lesenswert?

So, antworte mir einfach mal selber.

Scheinbar hat SimulAVR einen Schalter -t zur Ausgabe von Tracefiles 
(siehe http://www.nongnu.org/simulavr/usage.html).

Baut man sich da je eine LUT für die Mnemonics und eine für die Kosten 
pro Instruktion, wird die Sache greifbar.

Dann latscht man nämlich einfach durch den Trace, grept sich pro Zeile 
die Instruktion raus und gibt bei nem RegEx-Match die Kosten dafür aus. 
Das ganze aufakkumlieren und fertsch.

von db8fs (Gast)


Lesenswert?

...funktioniert im AVRStudio natürlich auch, solange man die zu testende 
Funktion möglichst frei von Parallelität hält. Dann macht auch der 
Zähler des Simulators Sinn. War aber afaik ganz oben 'ne Lösung für 
Linux gefragt.

von AVR (Gast)


Lesenswert?

Danke für die vielen Antworten!

Ich denke, die Methode mit dem Oszi wird der einfachste sein.

Nur wird's so sein, dass das Setzen und Rücksetzen des Pins auch eine 
Zeit in Anspruch nimmt, nicht?

von Amateur (Gast)


Lesenswert?

>Nur wird's so sein, dass das Setzen und Rücksetzen des Pins auch eine
>Zeit in Anspruch nimmt, nicht?
...deren Zeit genau definierbar/definiert ist.

von ASM Superprofi (Gast)


Lesenswert?

Auch wenns keiner der Neidhammel hier hören will, aber das erinnert mich 
an den Zeitpunkt, der für mich den Ausschlag gab, mich in Zukunft nur 
noch mit ASM zu beschäftigen.

Ich musste (und muss heute auch andauernd) eine Routine schreiben, die 
in einer vorgegebenen Anzahl Takte etwas machte. Das die Anzahl Takte 
eingehalten wurde, war elementar wichtig.

Damals habe ich noch in C programmiert. Kein Problem dachte ich, ASM 
Listing anzeigen und zählen und so lange rumoptimieren, bis die Takte 
stimmen.

Nunja nach 2 Stunden habe ich es dann hinbekommen und habe woanders 
weiterprogrammiert. Lustigerweise lief dann irgendwann die Routine nicht 
mehr. Beim Listing kam raus, dass C sich entschieden hat, die Routine 
komplett anders zu erzeugen, weil ich ganz woanders etwas geändert 
habe.

Danach hatte ich keinen Bock mehr auf C und seitdem nur noch ASM.

Aber die Lektion muss wohl jeder selbst lernen.

Und um die vorauszusehenden Argumente gleich vorweg zu entgiften:

Ja, ich kenne Inline ASM und habe es auch benutzt. Die Syntax ist 
grausam und unlesbar. So programmiert man sicher keine paar Seiten und 
behauptet hinterher, es mache auch noch Spass.

Ja, ich weiss, dass man externe Objekte einbinden kann und dadurch ASM 
und C mischen kann. Aber das ist für mich eher ein Punkt für ASM, da 
dies natürlich auch umgekehrt geht. Das Gerüst mache ich in ASM und wenn 
mal wirklich eine harte Nuss kommt (z.B. JPEG Handling, wo es nur C Libs 
gibt), dann binde ich ein C-erzeugtes Objekt ein. Für meine Steuerungen 
musste ich das jedoch noch nie machen.

Lange Rede kurzer Sinn: Du wirst NIE NIE NIEMALS garantiert und 
verlässlich in C die Takte zählen können. Was heute 24 Takte sind, sind 
beim nächsten Kompilieren dann 27 oder 23 oder sonstwas.

von Sascha_ (Gast)


Lesenswert?

2 Takte, einmal der Befehl selbst und dann das Ausgangsflipflop würde 
ich sagen.

von Horst M. (horst)


Lesenswert?

ASM Superprofi schrieb:
> Das Gerüst mache ich in ASM und wenn
> mal wirklich eine harte Nuss kommt (z.B. JPEG Handling, wo es nur C Libs
> gibt), dann binde ich ein C-erzeugtes Objekt ein.

Nur für den Fall (wenn's für AVR 8-bit sein soll):

Beitrag "Fast JPEG decoder on AT(x)mega"

von Carl D. (jcw2)


Lesenswert?

Habe schon mal ein Programm in Assembler geschrieben, das nicht 
funktioniert hat. So blöd bin ich nie mehr. Nie mehr Assembler.

(Vorsicht, kann Spuren von Ironie enthalten)

Weil ich im einem Fall das falsche Werkzeug gewählt haben, benutze ich 
das nie mehr wieder?
Klingt irgendwie nach Verdrahtungsfehler in der ALU.

von ASM Superprofi (Gast)


Lesenswert?

Es gibt ja so viele Geheimcodes in C. Gibt es eine mystische 
Deklaration, die dem C-Compiler für ein bestimmtes Codefragment 
Determinismus aufzwingt?
Ich habe nichts gegen C. Ich kann es nur für meine Zwecke meistens nicht 
einsetzen. Und für meine Spannungswandler-Module oder Motoransteuerungen 
ist ASM nunmal perfekt geeignet.

Man sollte wirklich mal eine Seite aufsetzen, die einem erklärt, wann 
ASM das richtige Werkzeug ist und wann es besser C ist. In ASM eine 
JPG-Lib zu programmieren ist zwar sportlich, aber ob es sinnvoll ist.... 
nunja. Die Zeit hätte mal besser investieren können.

von oszi40 (Gast)


Lesenswert?

AVR schrieb im Beitrag #4740875:
> nach ein paar Klicks die Zahl der benötigten Takte hätte

Was nützt die absolut genaue Zahl der Takte wenn die Taktfrequenz 
schwankt oder z.B. ein Unterprogramm plötzlich noch Zeit verplempert? 
Wahrscheinlich solltest Du Dein wahres Problem auf andere Art lösen?

von AVR (Gast)


Lesenswert?

Hallo!

ASM ist sicher interessant, werde mich auch ziemlich sicher mal damit 
beschäftigen, aber im Moment fehlt mir die Zeit dazu.

Ich möchte einfach feststellen, wie schnell eine Interrupt-Routine 
abgearbeitet wird.
Es müsste rein theoretisch auch nicht auf den Takt genau sein, nur so 
ungefähr. Also ob es 10 oder 30 oder 70 Takte sind...

von ASM Superprofi (Gast)


Lesenswert?

Am schnellsten und sichersten via Oszilloskop. Takte zählen via ASM 
Quellcode ist nichts für Anfänger.

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.