Hallo zusammen, ich suche nun schon länger nach einer Lösung für folgende Aufgabe: Ich möchte in einem C-Programm (für den ATMega2560) ermitteln, mit welchen Optimizer-Einstellungen der Code compiliert wurde. Dabei genügt es mit, -O0 bis -O3 zu erkennen. Wer hat das mal gemacht? Vielen Dank. Ich compiliere mit avr-gcc im AVR Studio. Grüße an alle Leser, RichardHi
Es gibt dafür Macros: https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html#Common-Predefined-Macros _OPTIMIZE_ _OPTIMIZE_SIZE_ _NO_INLINE_ Warum brauchst du das? Korrekter Code funktioniert immer unabhängig von der Optimierung. Wenn das bei deinem Code nicht der Fall ist, solltest du ihn reparieren.
Hallo, ja, das hatte ich auch schon gefunden. Aber den Level kann ich damit nicht abfragen - oder: Ich wüsste nicht, wie. Am Liebsten hätte ich gerne die Nummer des Levels zurück, ob Macro oder Funktion ist egal. Wofür brauche ich das? Ich möchte sicherstellen, dass ich den richtigen Optimizer-Level benutze, weil ich zum debugen und testen oft daran ändere wegen zeitkritischer Routinen, und in der Final-Version möchte ich sicher sein, dass ich mit -O2 kompiliert habe. Danke für weitere Ideen, RichardHi
RichardHi schrieb: > Ich möchte sicherstellen, dass ich den richtigen Optimizer-Level > benutze, Klingt nach einem ziemlichen Hack, im Source-Code zu prüfen ob im Build-System der "richtige" Level ausgewählt wurde! Und wie prüfst du im Code ob die Optimierungen jetzt wirklich an sein sollen oder nicht? Normalerweise macht man das so, dass man im Build System oder in der IDE zwei (oder mehr) Konfigurationen, z.B. namens "Debug" und "Release" anlegt, welche eben zum Debuggen bzw. auf Effizienz optimieren. Da kann man mit einem Klick so kompilieren wie man es braucht, und muss nicht von Hand den Optimierungs-Level umstellen.
Dr. Sommer schrieb: > Klingt nach einem ziemlichen Hack, im Source-Code zu prüfen ob im > Build-System der "richtige" Level ausgewählt wurde! Naja, ganz so abwegig scheint das erstmal nicht zu sein. Man kann ja auch Anderes aus dem Build-System in das Programm bekommen, z.B. die Compiler-Version. Warum nicht auch den Optimizer-Level - das ist Idee. Hat noch jemand einen Vorschlag ?
RichardHi schrieb: > Naja, ganz so abwegig scheint das erstmal nicht zu sein. Man kann ja > auch Anderes aus dem Build-System in das Programm bekommen, z.B. die > Compiler-Version. Warum nicht auch den Optimizer-Level - das ist Idee. > > Hat noch jemand einen Vorschlag ? Mir erscheint das schon ein wenig abwegig. Wenn man eine vernünftige Build-Umgebung hat, die einmal erzeugte Binaries reproduzierbar wieder erzeugen kann (VCS), dann braucht man so was m.E. nicht. Im Zweifel erzeugt man das Programm eben nochmal und macht einen Vergleich. Wenn's denn unbedingt sein muss, bau' dein Makefile eben entsprechend aus:
1 | .PHONY: flags |
2 | flags: |
3 | echo "const char used_flags[] = \"$(CFLAGS)\";" > flags.c |
Das Ergebnis baust Du irgendwo in dein Compilat ein und machst dir noch eine Abfragefunktion dazu.
Über die Compiler-Kommandozeile selber ein Makro definieren, in dem das Optimierungslevel drinsteht. Grob etwas in der Art:
1 | OPTIMIZATION=3 |
2 | |
3 | CFLAGS=-O$(OPTIMIZATION) -DOPTIMIZATON_LEVEL=\\"$(OPTIMIZATION)\\" # ... |
Das Escaping des Anführungszeichens ist möglicherweise nicht korrekt.
RichardHi schrieb: > und in der Final-Version möchte ich sicher > sein, dass ich mit -O2 kompiliert habe. Nur mal rein interessehalber: warum -O2 und nicht -Os ? Oliver
Oliver S. schrieb: > warum -O2 und nicht -Os ? -Os ist Optimierung nach SIZE und lässt laut Doku die Optimierungen weg, die zur Vergößerung des Binär-Codes führen würden. Das brauche ich nicht auf dem Mega. Dann lieber schnelleren Code.
Markus F. schrieb: > Wenn's denn unbedingt sein muss, bau' dein Makefile eben entsprechend > aus: > .PHONY: flags > flags: > echo "const char used_flags[] = \"$(CFLAGS)\";" > flags.c > > Das Ergebnis baust Du irgendwo in dein Compilat ein und machst dir noch > eine Abfragefunktion dazu. Ja gute Idee, das scheint prinzipiell ein Weg zu sein. Aber ich habe kein eigenes Make-File, sondern das generiert AVR Studio für mich. Kann ich das irgendwie ergänzen, so ähnlich wie ein Include-File? Ich benutze allerdings noch 4.18 (never change a running system) und bin zufrieden damit.
Markus F. schrieb: > Mir erscheint das schon ein wenig abwegig. Wenn man eine vernünftige > Build-Umgebung hat, die einmal erzeugte Binaries reproduzierbar wieder > erzeugen kann (VCS), Nur als Zwischenfrage: Welche Build-Umgebung kann aus einem bestimmten Quelltext-Stand wieder das gleiche Binary erzeugen? Bei einem Artikel über den Review von TrueCrypt wurde erwähnt, daß ein nicht unerheblicher Aufwand schon allein darin entstand, daß moderne Build-Umgebungen mit mehreren parallelen Threads aus dem gleichen Quellmaterial selten das gleiche Binary erzeugen, selbst wenn auf Konstrukte wie __DATE verzichtet wird, da hier Laufzeiteffekte zum tragen kommen.
RichardHi schrieb: > Kann ich das irgendwie ergänzen, so ähnlich wie ein > Include-File? Du kannst in Atmel-Studio Pre-Build und Post-Build Scripte definieren. Ich nutze das gerne, um die Revisionsnummer aus dem Versionsverwaltungssystem in ein *.c-File einzubauen.
RichardHi schrieb: > Oliver S. schrieb: >> warum -O2 und nicht -Os ? > > -Os ist Optimierung nach SIZE und lässt laut Doku die Optimierungen weg, > die zur Vergößerung des Binär-Codes führen würden. Das brauche ich nicht > auf dem Mega. Dann lieber schnelleren Code. Nun ja, und du hast nachgemessen, ob O2 tatsächlich schneller ist als Os? Denn ich bezweifele das ganz stark. gcc ist ein toller Compiler, der ist aber primär nicht für AVRs gemacht. Dessen Optimierungen sind vor allem für die Hauptplattformen optimiert. Und selbst auf Intels oder Arms gilt immer noch : messen, messen, messen, nicht glauben. Oliver
Oliver S. schrieb: > Nun ja, und du hast nachgemessen, ob O2 tatsächlich schneller ist als > Os? > > Denn ich bezweifele das ganz stark. gcc ist ein toller Compiler, der ist > aber primär nicht für AVRs gemacht. Dessen Optimierungen sind vor allem > für die Hauptplattformen optimiert. > > Und selbst auf Intels oder Arms gilt immer noch : messen, messen, > messen, nicht glauben. Ich habe zeitkritischen Programmcode, bei dem die Optimierungseinstellung weiterhilft oder eben nicht. Deshalb muss ich auch immer mal "an diesen Schrauben drehen". Insbesondere habe ich einen Codeabschnitt gehabt, den der Optimizer kaputt-optimiert hat. Den musste ich einklammern in #pragma GCC optimize ("-O1") <Codeabschnitt> #pragma GCC reset_options
Dr. Sommer schrieb: > Korrekter Code funktioniert immer unabhängig von > der Optimierung. Denkste. Wäre schön, ist aber wohl nicht generell so: Insbesondere habe ich einen Codeabschnitt gehabt, den der Optimizer kaputt-optimiert hat. Den musste ich einklammern in #pragma GCC optimize ("-O1") <Codeabschnitt> #pragma GCC reset_options
Walter T. schrieb: > Du kannst in Atmel-Studio Pre-Build und Post-Build Scripte definieren. Hab ich leider nicht gefunden in der IDE. Gib mir bitte mal nen Tipp.
Oliver S. schrieb: > Und selbst auf Intels oder Arms gilt immer noch : messen, messen, > messen, nicht glauben. Genau. Deshalb habe ich häufig einen Frequenzzähler an einem Pin, über den ich Loops ausmessen kann, wenn ich in der Loop das Pin toggle. Meinst du sowas?
RichardHi schrieb: > Hab ich leider nicht gefunden in der IDE. Gib mir bitte mal nen Tipp. Tut mir leid, aus Atmel Studio 4 bin ich jetzt seit 2012 heraus. Irgendwo bei den Build-Optionen.
RichardHi schrieb: > Insbesondere habe ich einen Codeabschnitt gehabt, den der Optimizer > kaputt-optimiert hat. Dann war er falsch geschrieben. ;-) Wenn du zyklengenauen Code brauchst, musst du (Inline-)Assembler benutzen. In allen anderen Fällen sollte es bestenfalls „zu schlecht optimiert“ (=> zu groß oder zu langsam für die Aufgabe) geben, aber nicht „zu gut optimiert“. Auf dem AVR ist kürzerer Code in der überwiegenden Anzahl der Fälle auch schnellerer Code¹, weshalb man mit -Os meist gar nicht so schlecht fährt. ¹Ausnahme: die aggressiven (und platzintensiven) Optimierungen von -O3 wie das Aufrollen von Schleifen bewirken tatsächlich nochmal eine Steigerung der Geschwindigkeit, allerdings für einen vergleichsweise hohen Preis.
RichardHi schrieb: > Genau. Deshalb habe ich häufig einen Frequenzzähler an einem Pin, über > den ich Loops ausmessen kann, wenn ich in der Loop das Pin toggle. > > Meinst du sowas? Das, oder ähnliches. Wenn dein Code mit O2 nachgewiesenermaßen schneller läuft als mit Os, dann ist das so. Oliver
Walter T. schrieb: > Markus F. schrieb: >> Mir erscheint das schon ein wenig abwegig. Wenn man eine vernünftige >> Build-Umgebung hat, die einmal erzeugte Binaries reproduzierbar wieder >> erzeugen kann (VCS), > > Nur als Zwischenfrage: Welche Build-Umgebung kann aus einem bestimmten > Quelltext-Stand wieder das gleiche Binary erzeugen? Bei einem Artikel > über den Review von TrueCrypt wurde erwähnt, daß ein nicht unerheblicher > Aufwand schon allein darin entstand, daß moderne Build-Umgebungen mit > mehreren parallelen Threads aus dem gleichen Quellmaterial selten das > gleiche Binary erzeugen, selbst wenn auf Konstrukte wie __DATE > verzichtet wird, da hier Laufzeiteffekte zum tragen kommen. Antwort: jede, die sorgfältig genug zusammengebaut wurde. Hier: https://reproducible-builds.org wird das Thema erschöpfend behandelt.
RichardHi schrieb: > Denkste. Wäre schön, ist aber wohl nicht generell so: Ist so, bis auf sehr seltene Compiler Fehler. > Insbesondere habe ich einen Codeabschnitt gehabt, den der Optimizer > kaputt-optimiert hat. Die Wahrscheinlichkeit, dass dein Code falsch war, ist wesentlich höher. Es gibt in C und C++ viele Möglichkeiten, solche Fehler zu machen, von denen viele Programmierer nicht wissen. Es gibt hier öfters Fragen nach solchen Problemen... Kann man in deinem alten Atmel Studio denn keine 2 Build Configurations anlegen (das neue kann's)? Da macht man einfach 2 für Debug/Release, und hat das Problem mit einem Mausklick erledigt und muss nie wieder an den Compiler Optionen rumfummeln. So ist das üblich, keiner außer dir braucht dafür Makros für den Optimizer Level.
Dr. Sommer schrieb: > Die Wahrscheinlichkeit, dass dein Code falsch war, ist wesentlich höher. > Es gibt in C und C++ viele Möglichkeiten, solche Fehler zu machen, von > denen viele Programmierer nicht wissen. Hallo zusammen, es geht hier im Grunde gar nicht um die Frage, ob irgendein Code falsch oder richtig war. Das ist ein weites Feld, das wir hier sicher nicht erschöpfend behandeln können. Darüber gibt es viele Abhandlungen, auch im Rahmen der theoretischen Informatik z.B. über Berechenbarkeit und Entscheidbarkeit. Alan Turing lässt grüßen. Für die Interessierten, was der Compiler/Optimizer wegoptimiert hat: Ich hatte zweimal kurz hintereinander den ADC abgefragt und die Werte in zwei Variable gestellt. Eine ADC-Abfrage wurde nach dem Optimieren mit -O2 oder -O3 nicht ausgeführt. Auch volatile half da nicht. Jetzt aber zurück zum eigentlichen Thread: Wer kann mir zeigen, wie ich in AVR Studio 4.18 das automatisch generierte make-File um einen Schritt ergänzen kann, in dem ich den Optimizer-Level in ein Includefile schreibe, was ich im C-Programm mitkompiliere? Das muss vor dem Kompilieren passieren.
Dr. Sommer schrieb: > Kann man in deinem alten Atmel Studio denn keine 2 Build Configurations > anlegen (das neue kann's)? Man kann. Und da die Build-Zeiten naturgemäß überschaubar sind, ist ein kompletter rebuild ja auch kein Beinbruch. Oliver
Oliver S. schrieb: > Und da die Build-Zeiten naturgemäß überschaubar sind, ist ein > kompletter rebuild ja auch kein Beinbruch. Kommt drauf an, wie viel C++ template Wahnsinn man verwendet ;-) Um die Optimierung zu ändern, muss man ja aber sowieso alles neu kompilieren. RichardHi schrieb: > Eine ADC-Abfrage wurde nach dem Optimieren > mit -O2 oder -O3 nicht ausgeführt. Auch volatile half da nicht. Klingt seltsam, bei allen Programmen bisher funktioniert das. Sicher, dass das Programm nicht einfach nur zu schnell war und die Abfragen zu schnell hintereinander ausgeführt wurden oder so? RichardHi schrieb: > Darüber gibt es viele Abhandlungen, auch > im Rahmen der theoretischen Informatik Na, mit Halteproblem & Co hat das weniger zu tun, mehr mit dem C(++)-Standard und den magischen Worten "undefined behaviour"... RichardHi schrieb: > Jetzt aber zurück zum eigentlichen Thread: Die wichtigste Frage ist noch nicht geklärt: Angenommen du hast im Code den tatsächlichen Optimizer Level abgefragt, woher weiß der Code dann welcher Level korrekt ist? Du müsstest im Code dann ja noch zusätzlich eintragen, wie du optimieren möchtest. Das ist komplizierter und fehleranfälliger als die schlichte Nutzung von 2 Build Configurations.
Dr. Sommer schrieb: > woher weiß der Code dann welcher Level korrekt ist? Vielleicht ist es keine Information, die der Quelltext auswertet, sondern der Nutzer? Ich mache bei meinen Projektchen, sobald ein LCD dran ist, auch immer eine kleine Info-Darstellungsfunktion, wo Versionsstand, Compilerversion, usw. dargestellt werden. Das hilft, wenn man die Geräte nach langer Zeit wieder in die Hand bekommt, durchaus weiter.
:
Bearbeitet durch User
Walter T. schrieb: > Vielleicht ist es keine Information, die der Quelltext auswertet, > sondern der Nutzer? Der Workflow wäre also: 1.) In den Build-Einstellungen die Optimierung auswählen 2.) flashen 3.) Im LCD schauen ob der richtige Optimierungslevel ausgewählt wurde Anstatt: 1.) Auf "Release" klicken (Siehe Anhang, Screenshot aus VS, auf dem neue Atmel Studio Versionen basieren) Klingt total praktisch...
Dr. Sommer schrieb: > Der Workflow wäre also: > 1.) In den Build-Einstellungen die Optimierung auswählen > 2.) flashen > 3.) Im LCD schauen ob der richtige Optimierungslevel ausgewählt wurde Nein, der Workflow wäre: 1.) In den Build-Einstellungen die Optimierung auswählen 2.) Flashen 3.) Erste Geräte an diejenigen verteilen, die es auch nutzen 4.) Firmware weiterentwickeln ... 5<m<n-2.) Vielleicht für einen speziellen Zweck eine Firmware-Variante stricken, die sich von den anderen unterscheidet. n-2.) Zu einem Gerät kommt eine Frage vom Benutzer n-1.) Benutzer macht Foto von Infoscreen n.) Ich weiß wieder genau, welches Gerät mit welcher Firmwarerevision überhaupt gemeint ist.
Walter T. schrieb: > Ich weiß wieder genau, welches Gerät mit welcher Firmwarerevision > überhaupt gemeint ist. Um so ein Problem ging es in diesem Thread aber überhaupt nicht: RichardHi schrieb: > Wofür brauche ich das? > Ich möchte sicherstellen, dass ich den richtigen Optimizer-Level > benutze, weil ich zum debugen und testen oft daran ändere wegen > zeitkritischer Routinen, und in der Final-Version möchte ich sicher > sein, dass ich mit -O2 kompiliert habe.
Dr. Sommer schrieb: > Um so ein Problem ging es in diesem Thread aber überhaupt nicht Ich habe keine Ahnung, was für den TO eine "finale Version" ist. Für mich ist eine "finale Version" etwas, (notwendige aber leider manchmal nicht hinreichende Bedingung), was meinen Schreibtisch vor langer Zeit verlassen hat. Nachtrag: Ausnahme sind natürlich Gadgets für meinen Schreibtisch.
:
Bearbeitet durch User
RichardHi schrieb: > Hat noch jemand einen Vorschlag ? Generier doch einfach immer beides, dauert bei heitigen PCs vielleicht maximal 1 Sekunde länger. Das eine nennst du porjekt-debug.elf und das andere projekt-release.elf. Ersteres verwendest du zum Debuggen, zweiteres zur Release. Oder gleich alle generierten Dateien in eigene Ordner: debug/projekt.elf debug/modul1.o debug/modul2.o ... release/projekt.elf release/modul1.o release/modul2.o ...
Walter T. schrieb: >> woher weiß der Code dann welcher Level korrekt ist? > > Vielleicht ist es keine Information, die der Quelltext auswertet, > sondern der Nutzer? Das denke ich auch. Wenn der Optimizer-Level beim Programmstart angezeigt wird, kann der Nutzer entscheiden: Shit happens, nochmal kompilieren. > Ich mache bei meinen Projektchen, sobald ein LCD dran ist, auch immer > eine kleine Info-Darstellungsfunktion, wo Versionsstand, > Compilerversion, usw. dargestellt werden. Das hilft, wenn man die Geräte > nach langer Zeit wieder in die Hand bekommt, durchaus weiter. Jawoll, genau so sehe ich das auch! Walter versteht mich. D A N K E Zeigst du auch Compiler-Parameter an, wie z.B. den Optimizer-Level? -- das wäre ja die Lösung --
RichardHi schrieb: > Das denke ich auch. Wenn der Optimizer-Level beim Programmstart > angezeigt wird, kann der Nutzer entscheiden: Shit happens, nochmal > kompilieren. Du willst also Walter's Ansatz, der ein ganz anderes Problem löst, nur eingeschränkt nutzbar ist (nur wenn LCD vorhanden und flashen einfach ist), auf dein Problem anwenden, für welches es bereits eine etablierte Lösung gibt, die bei Tausenden Projekten wunderbar funktioniert und gegen die bisher kein einziges Gegenargument genannt wurde? Man kann es sich auch schwer machen...
PS: Du kannst ja in der Build-Configuration so etwas wie -DCONF=\"Relase\" bzw. -DCONF=\"Debug\" übergeben, und dann im Programm auf dem LCD CONF ausgeben, da kannst du dann sehen wie es kompiliert wurde. Da du in der Build-Configuration nie den Optimierungs-Level ändern solltest, kannst du so folgern welche Optimierung angewendet wurde.
Dr. Sommer schrieb: > .., für welches es bereits eine etablierte > Lösung gibt, die bei Tausenden Projekten wunderbar funktioniert Sorry, wo ist die Lösung? Nur weil ich zwischen zwei Configurations in der IDE umschalten kann, weiß ich doch auf dem ATmega nicht, welche Build-Variante gefahren wurde, und ob die vielleicht geändert wurde, z.B. der Optimizer-Level.
RichardHi schrieb: > weiß ich doch auf dem ATmega nicht, welche > Build-Variante gefahren Musst du ja auch nicht. Du flasht grundsätzlich immer die Release-Variante, die ist immer mit Optimierungen. Da brauchst du dann auch nix mehr zu prüfen. RichardHi schrieb: > und ob die vielleicht geändert wurde, > z.B. der Optimizer-Level. Du lässt bei Release immer die Optimierung an, und bei Debug aus.
Genau. Und weil du das nicht weißt, ist der Ansatz, sich auf gar nichts zu verlassen, sondern einfach ein komplettes rebuild mit nachgeprüften und bekannten Optionen durchzuführen und zu flashen. Oliver
RichardHi schrieb: > Zeigst du auch Compiler-Parameter an, wie z.B. den Optimizer-Level? > -- das wäre ja die Lösung -- Nein, ich kenne keine Lösung für das Problem. Ich zeige einfach nur an, -ob es ein Debug-Build ist oder nicht (im Screenshot: kein Debug) und -ob der Quelltext des Builds ins Versionsverwaltungssystem eingecheckt wurde (hier: noch nicht.) Die Optimierungs-Optionen in Release ändere ich so selten, da meine Firmware immer massig Reserve hat, daß ich sie bei Bedarf mit der Kenntnis der Versionsnummer immer aus dem Makefile auslesen kann. Sprich: Für mich ist das Problem keins.
:
Bearbeitet durch User
Dr. Sommer schrieb: > Du flasht grundsätzlich immer die > Release-Variante, die ist immer mit Optimierungen Ich muss doch aber auch mal eine andere Variante flashen können, um Tests auf der echten Hardware zu machen - nicht alles geht im Debugger. Besonders nicht, wenn vom ATmega noch einiges an Elektronik gesteuert wird. Und dann habe ich die Notwendigkeit, auf der LCD-Anzeige (die ich immer dran habe) zu sehen, ob und wie optimiert wurde. Vertrauen ist gut - Kontrolle ist besser. Meistens sitzt das Problem davor.
RichardHi schrieb: > Insbesondere habe ich einen Codeabschnitt gehabt, den der Optimizer > kaputt-optimiert hat. Den musste ich einklammern in > #pragma GCC optimize ("-O1") > <Codeabschnitt> > #pragma GCC reset_options Das hättest Du auch beheben können indem Du stattdessen einfach Deinen defekten Code repariert hättest.
RichardHi schrieb: > Ich muss doch aber auch mal eine andere Variante flashen können, um > Tests auf der echten Hardware zu machen - nicht alles geht im Debugger. Kannst du ja... RichardHi schrieb: > Und dann habe ich die Notwendigkeit, auf der LCD-Anzeige (die ich immer > dran habe) zu sehen, ob und wie optimiert wurde. Statt zu prüfen, kannst du auch einfach die Release Variante drüber flashen. Wenn die schon drauf war, sollte der Programmer das merken und nichts tun, um Flash-Zyklen zu sparen.
Bernd K. schrieb: > Das hättest Du auch beheben können indem Du stattdessen einfach Deinen > defekten Code repariert hättest. Sage mal: warum behauptest du, der Code wäre defekt gewesen? Wenn du etwas Produktives beizutragen hast, kannst du dich gerne wieder melden. Aber das ist gar nix: Behauptungen aufzustellen, ohne überhaupt die Idee eines Beweises zu haben. Übrigens geht es in diesem Thread nicht um das ADC-Codestück. Es geht um was ganz anderes. "Wer lesen kann ist klar im Vorteil" So.
RichardHi schrieb: > Sage mal: warum behauptest du, der Code wäre defekt gewesen? Aus purer Neugier: Zeig den Code doch einfach mal... Wenn er wirklich korrekt ist, hattest du ja Recht ;-)
Wenn Du ständig damit beschäftigt bist immer wieder aufs Neue auf gut Glück an den Optimierungsoptionen herumzuschrauben und dann ausprobieren ob es jetzt zufällig besser oder schlechter wird oder gar nicht mehr gehtr dann ist was anderes faul (Das ganze Konzept, die gewählte Hardware, die Umsetzung, die Fertigkeiten, etc). Normalerweise hat man eine Einstellung für Release mit den üblichen empfohlenen Optionen und noch ne zweite Einstellung für Debug. Die meiste Zeit verbringt man empfohlenerweise damit sich über die Hardware und den Code und deren Zweck und Funktionsweise Gedanken zu machen anstatt dauernd blind an den Compileroptionen rumzuspielen.
Dr. Sommer schrieb: > PS: Du kannst ja in der Build-Configuration so etwas wie > -DCONF=\"Relase\" bzw. -DCONF=\"Debug\" übergeben, und dann im Programm > auf dem LCD CONF ausgeben Das möchte ich jetzt mal ausprobieren. > auf dem LCD CONF ausgeben Was kommt im Programm an? Wie greife ich darauf zu?
RichardHi schrieb: > Was kommt im Programm an? > Wie greife ich darauf zu? Einfach CONF reinschreiben. Das wird dann zu "Debug" bzw. "Release", d.h. einem schnöden String-Literal. Wie du vielleicht weißt, kann man String-Literale einfach hintereinander schreiben, um sie zu konkatenieren:
1 | int main () { |
2 | puts ("Build-Configuration: " CONF); |
3 | }
|
RichardHi schrieb: > Aber das ist gar nix: Behauptungen aufzustellen, ohne überhaupt > die Idee eines Beweises zu haben. Du hast doch angefangen zu behaupten der gcc würe Deinen Code kaputtmachen ohne den Hauch eines Beweises vorzulegen. Mein Rasiermesser sagt mir daß es überwältigend viel wahrscheinlicher ist daß Dein Code schon vorher kaputt war und der tausende von Mannjahren alte gcc alles vollkommen richtig gemacht hat.
Bernd K. schrieb: > dauernd blind an den Compileroptionen rumzuspielen Wieso behauptest du das? Du weißt doch gar nicht, ob ich weiß was ich tue. Weißt du was du schreibst? Jetzt: konkreter Vorschlag und nicht so ein "du machst es falsch"-Gesabbel.
Bernd K. schrieb: > Du hast doch angefangen zu behaupten der gcc würe Deinen Code > kaputtmachen Hab ich nie gesagt. So, und jetzt geh mal offline.
RichardHi schrieb: > Bernd K. schrieb: >> Du hast doch angefangen zu behaupten der gcc würe Deinen Code >> kaputtmachen > > Hab ich nie gesagt. So, und jetzt geh mal offline. Doch, und zwar da: Beitrag "Re: AVR GCC Optimizer Level in C-Programm abfragen" und zwar wörtlich "kaputt" soll er ihn gemacht haben, ich zitiere: > habe ich einen Codeabschnitt gehabt, den der Optimizer kaputt-optimiert hat
RichardHi schrieb: > Hab ich nie gesagt. Doch, hast du. Beitrag "Re: AVR GCC Optimizer Level in C-Programm abfragen" RichardHi schrieb: >> dauernd blind an den Compileroptionen rumzuspielen > > Wieso behauptest du das? Du weißt doch gar nicht, ob ich weiß was ich > tue. Jedenfalls irgendwas Seltsames. Ich programmiere nun schon ziemlich lange Mikrocontroller, aber ich habe eigentlich so gut wie nie die Notwendigkeit gehabt, an den Optimierungseinstellungen herumzuschrauben. Wenn ich ein Zwischenergebnis im Debugger sehen will, welches mir der Compiler ansonsten wegoptimiert, dann werf' ich mal schnell eine "volatile" deklarierte Variable da hinein, in der das Ergebnis notiert wird. Debuggt wird bei mir prinzipiell mit den Einstellungen, mit denen das am Ende im Feld laufen soll, denn ich möchte das debuggen, was dann auch benutzt wird, und nicht ein völlig anderes Compilat. Bei dieser Vorgehensweise erübrigt sich das ganze Ansinnen, das zu diesem Thread geführt hat, eigentlich von vornherein.
Dr. Sommer schrieb: > Aus purer Neugier: Zeig den Code doch einfach mal... Wenn er wirklich > korrekt ist, hattest du ja Recht ;-) Nochmal: Ich will gar nicht Recht haben. Ich zeige euch den Code, damit Ruhe ist.
1 | #define mess_delay 5 // Verzögerung vor der Messung
|
2 | #define mess_delta 50 // Differenz, die 0 und 1 unterscheidet
|
3 | #define ADC_pin_check 0 // der ADC-Channel für Pin-Kontaktmessung
|
4 | uint16_t messung0; |
5 | uint16_t messung1; |
6 | |
7 | initADC_single(); |
8 | |
9 | // Bit ausschalten
|
10 | switch (pin[k].reg) |
11 | {
|
12 | case 'A': PORTA &= ~(1<<pin[k].bit); break; |
13 | case 'B': .. hier weitere Fälle |
14 | default : error(4,tx_wrong_case); |
15 | }
|
16 | |
17 | delay_ms(mess_delay); |
18 | messung0=ADC_read_avg(ADC_pin_check,2); |
19 | |
20 | // Bit einschalten
|
21 | switch (pin[k].reg) |
22 | {
|
23 | case 'A': PORTA |= (1<<pin[k].bit); break; |
24 | case 'B': .. hier weitere Fälle |
25 | default : error(4,tx_wrong_case); |
26 | }
|
27 | |
28 | delay_ms(mess_delay); |
29 | messung1=ADC_read_avg(ADC_pin_check,2); |
30 | |
31 | iniADC_single ist: |
32 | |
33 | void initADC_single (void) |
34 | {
|
35 | ADCSRA |= ((1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)); //Prescaler at CPUclock/128 |
36 | ADMUX |= (1<<REFS0); //internal Reference |
37 | ADMUX &= ~(1<<REFS1); //Avcc(+5V) as voltage reference |
38 | //ADMUX |= (1<<ADLAR); //Ergebnis linksbündig
|
39 | ADMUX &= ~(1<<ADLAR); //Ergebnis rechtsbündig |
40 | ADCSRA |= (1<<ADEN); //ADC enable |
41 | ADCSRA |= (1<<ADSC); //Start initial conversion |
42 | while (ADCSRA & (1<<ADSC) ) {;} // auf Abschluss der Konvertierung warten |
43 | }
|
44 | |
45 | und ADC_read_avg ist: |
46 | |
47 | uint16_t ADC_read_avg (const uint8_t channel, const uint16_t times ) |
48 | {
|
49 | uint32_t sumADC=0; |
50 | for (uint8_t i=0;i<times;i++) |
51 | {sumADC += ADC_read(channel);} |
52 | return sumADC/times; // das dauert länger wegen der Division |
53 | }
|
Was ich erlebt habe ist, dass der Optimizer mit -O2 und -O3 den Code messung1=ADC_read_avg(ADC_pin_check,2); nicht ausführt. Das umgehe ich, indem ich temporär auf -O1 zurückgehe, wie bereits oben beschrieben.
:
Bearbeitet durch Moderator
Beitrag #5166565 wurde vom Autor gelöscht.
RichardHi schrieb: > Was ich erlebt habe ist, dass der Optimizer mit -O2 und -O3 den Code > messung1=ADC_read_avg(ADC_pin_check,2); > nicht ausführt. Sieht alles soweit ok aus, aber ADC_read wird nicht gezeigt :/ Und ohne den Code selbst kompilieren zu können kann ich da auch nicht wirklich was zu sagen... RichardHi schrieb: > return sumADC/times; // das dauert länger wegen der Division ... Es sei denn die Funktion wird geinlined, die Division durch 2 ist schnell (bitshift). Le X. schrieb im Beitrag #5166565: > Stelle nur kurze, präzise Fragen die sich ebenso kurz und präzise > beantworten lassen. Die kurze präzise Antwort ist "geht nicht". Das hilft ihm wenig. Daher wurden alternative bewährte Lösungsansätze geboten.
Dr. Sommer schrieb: > Sieht alles soweit ok aus, aber ADC_read wird nicht gezeigt Hier ist der ADC_read:
1 | /* ADC Einzelmessung */
|
2 | uint16_t ADC_read(const uint8_t channel ) |
3 | {
|
4 | // Kanal waehlen
|
5 | ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x07); // select channel number 0..7 |
6 | ADCSRA |= (1<<ADSC); // eine Wandlung "single conversion" |
7 | while (ADCSRA & (1<<ADSC) ) {;} // warte auf Abschluss der Konvertierung |
8 | return ADCW; // ADC auslesen und zurückgeben |
9 | }
|
:
Bearbeitet durch Moderator
Dr. Sommer schrieb: > Und ohne > den Code selbst kompilieren zu können kann ich da auch nicht wirklich > was zu sagen... Und ohne die Schaltung, die an dem ADC-Pin hängt, vielleicht auch nicht.
RichardHi schrieb: > Und ohne die Schaltung, die an dem ADC-Pin hängt, vielleicht auch nicht. Och, den Compiler anwerfen und den Assembler-Code anschauen würde gehen. Da sollten ja die zwei Aufrufe zu sehen sein. Selbst wenn ich es flashen würde, könnte ich ja das Rauschen messen...
Dr. Sommer schrieb: > Selbst wenn ich es flashen > würde, könnte ich ja das Rauschen messen... Stimmt auch wieder. Jörg W. schrieb: > Bei dieser Vorgehensweise erübrigt sich das ganze Ansinnen, das zu > diesem Thread geführt hat, eigentlich von vornherein. Wer nicht mehr mitmachen möchte, darf sich ausklinken. Und nicht vergessen: Die Spinner sind die Gewinner. War immer so. ============================== Jetzt wieder zum Thread-Thema: ============================== Dr. Sommer schrieb: >> PS: Du kannst ja in der Build-Configuration so etwas wie >> -DCONF=\"Relase\" bzw. -DCONF=\"Debug\" übergeben, und dann im Programm >> auf dem LCD CONF ausgeben > Das möchte ich jetzt mal ausprobieren. Sagte ich schon. Frage dazu: Verstehe ich es richtig? Wenn ich -DCONF=\"Relase\" in die Options schreibe (dahin wo auch sowas wie -Wstrict-prototypes oder -Wall steht), dann kann ich im C-Programm hinschreiben: char lcd[32]; strncpy(lcd,CONF,32); und in lcd steht dann "Relase"?
RichardHi schrieb: > Insbesondere habe ich einen Codeabschnitt gehabt, den der Optimizer > kaputt-optimiert hat. RichardHi schrieb: > Ich muss doch aber auch mal eine andere Variante flashen können, um > Tests auf der echten Hardware zu machen - nicht alles geht im Debugger. Was verstehst */du/* unter (un)echter Hardware und unter Debugger?
RichardHi schrieb: > Frage dazu: > Verstehe ich es richtig? Wenn ich -DCONF=\"Relase\" in die Options > schreibe (dahin wo auch sowas wie -Wstrict-prototypes oder -Wall steht), > dann kann ich im C-Programm hinschreiben: > char lcd[32]; > strncpy(lcd,CONF,32); > und in lcd steht dann "Relase"? Ja ist korrekt. Das -DCONF=\"Release\" ist äquivalent zu
1 | #define CONF "Release"
|
Somit wird aus der strncpy-Zeile einfach (simple Textersetzung durch den Präprozessor)
1 | strncpy(lcd,"Release",32); |
Einfacher & effizienter geht's mit
1 | const char lcd [] = CONF; |
Ralf G. schrieb: > RichardHi schrieb: >> Ich muss doch aber auch mal eine andere Variante flashen können, um >> Tests auf der echten Hardware zu machen - nicht alles geht im Debugger. > > Was verstehst */du/* unter (un)echter Hardware und unter Debugger? Die Vermutung liegt nahe, dass er mit "echter Hardware" den Prozessor meint (eben das, worauf man die Firmare flasht) und mit vermutlich eine Simulation des Prozessors. Dr. Sommer hatte als "Lösung" allerdings vorgeschlagen, die Debug-Version einfach gar nicht mehr auf den Prozessor zu flashen.
Rolf M. schrieb: > Die Vermutung liegt nahe, dass er mit "echter Hardware" den Prozessor > meint (eben das, worauf man die Firmare flasht) und mit "Debugger" vermutlich eine > Simulation des Prozessors. Fast richtig. Der Prozessor sitzt auf einem Prozessorboard, an das weitere Hardware angeschlossen wird, die vom Prozessorboard gesteuert wird. Die habe ich im Debugger nicht zur Verfügung. Mit Debugger meine ich den internen Debugger in AVR Studio. Das ist eine Simulation des Prozessors. Damit teste ich den Code zeilenweise, wenn er nicht das tut was ich meinte oder wollte. Falsch macht der Compiler ja nichts, wie wir gelernt haben, nur anders als man vielleicht wollte. Manchmal macht man eben selbst was falsch.
RichardHi schrieb: > Mit Debugger meine ich den internen Debugger in AVR Studio. Dacht' ich mir's. Das nennt man Simulator. Da liegt die Vermutung nahe, dass der Code auch in höheren Optimierungsstufen schon richtig ausgeführt wird, der Simulator aber die Codestellen 'nicht wiederfindet', weil durch die Programmoptimierung Zwischenergebnisse kurzzeitig in Registern gehalten werden oder sinnlose Berechnungen einfach 'wegoptimiert' sind. Es scheint dann so, dass beim Steppen durch den Quelltext Berechnungen übersprungen werden...
RichardHi schrieb: > Was ich erlebt habe ist, dass der Optimizer mit -O2 und -O3 den Code > messung1=ADC_read_avg(ADC_pin_check,2); > nicht ausführt. Wie hast Du das diagnostiziert? Hast Du das Assemblerlisting angesehen oder bist durchgesteppt? Oder bist Du nur aufgrund anderer Symptome indirekt zu einer Vermutung gelangt ohne den eigentlichen erzeugten Code zu sichten?
Bernd K. schrieb: > Wie hast Du das diagnostiziert? > Hast Du das Assemblerlisting angesehen > oder bist durchgesteppt? Ob ich das Assemblerlisting angesehen habe, weiß ich nicht mehr. Ist schon länger her, und ich habe das Problem ja gelöst. Dass beim durchsteppen Codestellen nicht gezeigt werden, weiß ich. Bernd K. schrieb: > Oder bist Du nur aufgrund anderer Symptome > indirekt zu einer Vermutung gelangt? Und zwar bin ich mit dem Degubber drangegangen, weil der Coe nicht das tat was ich wollte. Da hab ich dann bemerkt, dass die erste und zweite Messung sich nicht unterscheiden. (Oder war es so, dass die zweite Messung immer gleich war egal mit welchen Pins - das läuft nämlich in einer Loop, das hatte ich vorhin weggelassen.) Und auf dem Prozessorboard verhielt es sich ebenso. Ich will an dies Thema jetzt auch nicht mehr dran, denn es funktioniert so wie es ist. Dieser Thread geht ja um etwa ganz anderes.
Dr. Sommer schrieb: > Das -DCONF=\"Release\" ist äquivalent zu #define CONF "Release" Und B I N G O Ich habe jetzt mehrere Configurations angelegt mit identischen Einstellungen außer -Ox und -DCONF= War ein bisschen verzwickt, weil AVR Studio kein kopieren einer Configuration kann. So habe ich das XML-File <projekt>.aps manipuliert und Configurations kopiert und später in der IDE geändert. Und ein simples lcd_print("\nConfig="); lcd_print(CONF); zum Programmstart oder sowas ähnliches ist der Schlüssel zum Glück. Danke, Dr. Sommer und allen anderen für die vielen Beiträge.
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.