Hallo, liebe Assembler-Freunde! Ich soll im Rahmen eines Projektes versuchen, C-Code mittels Inline-Assembler Code optimieren. Da vor allem Assembler neu für mich ist (habe bereits einige Tutorials durchgearbeitet), habe ich jedoch keine Ahnung, wo ich ansetzen soll, um den Code performanter zu machen. Das Board, auf dem das ganze passieren soll, ist ein ArduinoMega2560, der C-Code ist ein Cypher. Interessant wäre deshalb vor allem die "Round-Function", also die Funktion, die oft auf den Text angewandt wird, um ihn zu verschlüsseln, da diese bei einem Verschlüsselungsvorgang mehrere hunderte Male angewandt wird und so bereits kleine Performanzverbesserungen einen großen Ausschlag geben. In dieser Funktion geht es hauptsächlich um viele Bitshifts/Rotationen und XOR/OR-Operationen. Die Worte, die geshiftet und miteinander geXORt werden, sind 16 Bit lang, belegen also jeweils zwei Register. Meine Frage wäre also, ob ihr mir Tipps geben könntet, wo ich ansetzen kann, oder ob es sowieso keinen Sinn macht zu versuchen, besser als der Compiler zu sein. Ich habe bereits gelesen, dass vor allem bei Multiplikationen Performanzgewinne gegenüber C möglich sind (z. B. bei http://stackoverflow.com/a/577856), jedoch finden in dem Cypher keine Multiplikationen statt. Eine weitere Frage wäre noch, ob es eine Möglichkeit gibt, wie ich an den kompilierten avr-gcc Assembler-Code herankommen kann. Bisher habe ich nur die Seite http://gcc.godbolt.org/ genutzt, die jedoch nicht die aktuelle Version des avr-gcc anbietet. Vielen Dank im Voraus, Thomas
:
Verschoben durch Moderator
Wenn du Atmel Studio benutzt, dann sollte bereits eine *.lss Datei mit dem generierten Assembler Code erstellt worden sein. Wenn du avr-gcc direkt benutzt dann: avr-objdump -h -S projekt.elf > projekt.lss Ein guter Anfang ist auf jeden Fall sich den generierten Assembler Code anzugucken und dann zu überlegen ob einem Stellen für Verbesserungen einfallen.
Thomas W. schrieb: > Meine Frage wäre also, ob ihr mir Tipps geben könntet, wo ich ansetzen > kann Miss die Ausführungszeiten der einzelnen Teile. Am besten geht das, wenn man noch ein paar freie IO-Pins hat, mit denen man „wackeln“ kann, wenn man bestimmte Codeteile betritt oder verlässt. Am allerbesten natürlich, wenn man das dann auf einem Logikanalysator aufzeichnen kann. Wenn du erstmal weißt, ob deine Runden-Funktion wirklich der Flaschenhals ist, dann kannst du überlegen, ob sich dort durch manuelle Optimierung wirklich nennenswert was rausholen lässt. Boris P. schrieb: > Falsches Forum... Verschoben.
Thomas W. schrieb: > Ich soll im Rahmen eines Projektes versuchen, C-Code mittels > Inline-Assembler Code optimieren. Das ist nur was für eingefleischte Masochisten. Wenn es unbedingt Assembler sein muß, dann als separates Quellfile (*.S). Aber solange Du nicht der absolute Assembler-Geek bist, sehe ich da wenig bis kaum Erfolgschancen. Welcher Hirni vergibt bloß solche Aufgaben. Hast Du ihm was getan, daß er so böse auf Dich ist.
Peter Dannegger schrieb: > Aber solange Du nicht der absolute Assembler-Geek bist, sehe ich da > wenig bis kaum Erfolgschancen. Wo ich viel mehr Erfolgschancen sehe, das ist bei der konsequente Durchsicht des C Codes. Oftmals ist es so, dass diejenigen, die nach Assembler-Optimierung rufen, haarsträubende Probleme im C Code nicht sehen. Das beginnt bei der Wahl der falschen Datentypen und geht bis zu schlechten Algorithmen bzw. schlechter Umsetzung. Um mal die Phrase "Dem Compiler Prügel zwischen die Beine zu werfen" nicht zu verwenden. Grossartige Performance Gewinne sind durch Assemblerlösungen eigentlich selten bis kaum zu erzielen. Dazu sind die Compiler schon zu gut. Bitrotation in einem Byte ist eine der Schwachpunkte in C, weil es dafür keine High-Level Entsprechung in C gibt, d.h. diese Absicht muss ein Optimizer erkennen können. Aber ansonsten? Ob man 2 Werte in C miteinander ver-xodert, oder ob man dieselbe Operation in Assembler hinschreibt kommt aufs selbe raus.
:
Bearbeitet durch User
Bevor man zu inline asm greift (und der C Code selbst bereits optimiert ist), sollte man Compiler Intrinsics in Betracht ziehen. Beispiel für armcc und Cortex-M3: 16Bit signed BE auf 32Bit signed LE (ansonsten per SHIFT, OR & MASK sowie sign extension): leVal = _REVSH(beVal); Eine gute Methode ist auch, verschiedene Ansätze in C mit dem compilat in ASM zu vergleichen, um zu schauen, was der compiler draus macht. Der Gewinn wird ggf. sogar grösser als durch pure ASM Fummelei. Schlussendlich sollte man Teile seines Programms ausmessen. Dies kann im einfachsten Fall per Pin Toggling (über eine Code Section) geschehen, oder bei grösseren µCs z.B. durch ein Virtuelles Oszilloskop in der IDE mit einem schnellen target Debugger.
Random ... schrieb: > Eine gute Methode ist auch, verschiedene Ansätze in C mit dem compilat > in ASM zu vergleichen, um zu schauen, was der compiler draus macht. Ja, die Optimierung auf C-Ebene ist deutlich einfacher. Es reicht dazu, im Assembler-Listing zu zählen, wieviel Instruktionen ein C-Ausdruck erzeugt.
Peter Dannegger schrieb: > Es reicht dazu, im Assembler-Listing zu zählen, wieviel Instruktionen > ein C-Ausdruck erzeugt. Da der Optimierer umstrukturiert, kann man selten einzelne ASM Befehle konkret einer C-Anweisung zuordnen.
> mehrere hunderte Male angewandt > Da der Optimierer umstrukturiert Wenn der Compiler da mehrere hundert Funktionsaufrufe durch Inline expansion optimiert, kann deine Assembler-optimierte Funktion insgesammt zu langsameren Code führen. Wenn der Compiler den Code nicht selbst erzeugt hat, optimiert er auch nicht.
Steffen Rose schrieb: > Da der Optimierer umstrukturiert, kann man selten einzelne ASM Befehle > konkret einer C-Anweisung zuordnen. Wenn man das Inlining abschaltet, geht das recht gut. Zumindest beim WINAVR2010. Die Quelltextkommentare sind meistens an der richtigen Stelle oder in der Nähe. Mit Inlining muß man eben an der Aufrufstelle suchen.
Auch der WinAVR2010 wird bei eingeschaltetem Optimierer Registerzuweisungen nicht mehrfach ausführen u.a. Da kann es dann vorkommen, dass manche C-Anweisung als wenig aufwändig angenommen wird. Löscht man nun die davorliegende "aufwändige" C-Anweisung, verschiebt sich das Befüllen der Register auf die nun nicht mehr einfache Anweisung. Bei -O0 kann man noch gut nachkommen, aber bei -Os muss man schon genauer kucken, welche an anderer Stelle liegenden ASM Anweisung noch dazugehören. Wie sehr WinAVR umstrukturiert, weiß ich nicht. Da wirst Du sicher recht haben.
Mal' die wichtigen bzw. zeitkritischen Stellen mit Profiling identifizieren und betrachten. Und oft sind die Compiler-Bauer die besseren Optimierer...
Mit Lötkolben sind wir Hobby-Frickler besser als die Compiler-Bauer. Wir konnen die Funktion in ein FPGA brennen - die Compiler-Bauer können das nicht :-)
Noch einer schrieb: > Wir konnen die Funktion in ein FPGA brennen Mit dem Lötkolben? Das arme FPGA. :)
Es hängt sehr von der Aufgabe ab, ob man von Hand deutlich besser optimieren kann als der Compiler. Dazu sollte man aber schon etwas Übung in ASM haben. Als Anfänger tut man sich da oft recht schwer. Gute Chancen hat man mit ASM deutlich schneller zu werden, wenn man in ASM kleinere Datentypen nutzen kann, etwa 20 Bit Zahlen oder gemischte Operationen wie 16 Bit mal 8 Bit Zahl, die die meisten C-Compiler nicht unterstützen. Auch über die direkte Nutzung des Carry flags geht es manchmal deutlich schneller als in C, weil man sich ggf. eine IF Else sparen kann. Manchmal findet aber auch GCC schon das Optimum oder ist dicht dran. Zum optimieren gibt es 2 Stufen: einmal vom ASM Code ausgehen den der Compiler erzeugt hat, und dann den zu Optimieren. Alternativ löst man das Problem gleich in ASM, ohne Code vom Compiler als Vorbild - das gibt ggf. ganz andere Ansätze wo z.B. IF ..ELSE Unterscheidungen wegfallen und stattdessen Flag Bits direkt genutzt werden. Auch Tabellen sind ggf. Effektiv. Wie lange ein Stück Code wirklich braucht, kann man ganz gut im Simulator testen: einfach vor und hinter den interessanten Teil Breakpoints setzen. Das ist einfacher als von Hand Zyklen zählen.
Vielen Dank schon mal an alle für die vielen, schnellen Antworten! Hat mir auf jeden Fall neue Ansätze gegeben. Ist echt super, dass sich hier so schnell um Probleme gekümmert wird, weiter so!
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.