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ß
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.
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.
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?
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
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.
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.
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"
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.
> > 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.
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.
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>
>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.
Es wurde schon gesagt: Assembler Code vom Compiler ausgeben lassen und dann via Datenblatt nachschlagen, welcher Befehl wie viele Zyklen braucht.
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).
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.
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.
...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.
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?
>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.
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.
2 Takte, einmal der Befehl selbst und dann das Ausgangsflipflop würde ich sagen.
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"
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.
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.
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?
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...
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.