Wie kann verhindert werden, dass GCC eine ausgelastete Warteschleife optimiert?
Ich will schreiben Sie ein C-code der firmware für Atmel AVR-mikrocontroller. Ich kompiliere es mit GCC. Auch ich möchte zum aktivieren der compiler Optimierungen (-Os
oder -O2
), sehe ich keinen Grund, nicht aktivieren Sie Sie, und Sie werden wahrscheinlich zu generieren, die eine bessere Montage viel schneller als das schreiben von assembly manuell.
Aber ich will ein kleines Stück code nicht optimiert. Ich will verzögern die Ausführung einer Funktion durch einige Zeit, und so wollte ich schreiben, ein do-nothing-loop einfach zu verschwenden einige Zeit. Keine Notwendigkeit, um genau zu sein, warten Sie einfach einige Zeit.
/* How to NOT optimize this, while optimizing other code? */
unsigned char i, j;
j = 0;
while(--j) {
i = 0;
while(--i);
}
Da der Speicher-Zugriff in der AVR ist viel langsamer, ich will i
und j
gehalten werden, in CPU-Register.
Update: ich habe gerade festgestellt, util/delay.h und util/delay_basic.h von AVR-Libc. Obwohl die meisten Male ist es vielleicht eine bessere Idee für die Verwendung dieser Funktionen, diese Frage bleibt gültig und interessant.
InformationsquelleAutor der Frage Denilson Sá Maia | 2011-08-16
Du musst angemeldet sein, um einen Kommentar abzugeben.
Entwickelte ich diese Antwort nach einen link von dmckee Antwortaber es braucht einen anderen Ansatz als seine/Ihre Antwort.
Funktion Attribute Dokumentation von GCC erwähnt:
Dieser gab mir eine interessante Idee... Anstatt einer
nop
Anweisung in der inneren Schleife habe ich versucht, indem Sie eine leere Assembler-code in es, wie dieser:- Und es funktionierte! Schleife wurde nicht optimiert, und keine extra
nop
Anweisungen eingefügt wurden.Was mehr ist, wenn Sie
volatile
gcc speichern diese Variablen im RAM und das hinzufügen von ein paarldd
undstd
zu kopieren, temporäre Register. Dieser Ansatz, auf der anderen Seite, nichtvolatile
und erzeugt keinen solchen overhead.Update: Wenn Sie kompilieren von code mithilfe von
-ansi
oder-std
müssen Sie ersetzen dieasm
keyword mit__asm__
als beschrieben in der GCC-Dokumentation.Darüber hinaus können Sie auch verwenden
__asm__ __volatile__("")
wenn Ihr assembly-Anweisung ausführen müssen, in dem wir, (D. H. Sie dürfen nicht verschoben werden, eine Schleife als Optimierung).InformationsquelleAutor der Antwort Denilson Sá Maia
Erklären
i
undj
Variablen alsvolatile
. Dadurch wird verhindert, compiler optimieren von code im Zusammenhang mit diesen Variablen.InformationsquelleAutor der Antwort ks1322
Ich bin mir nicht sicher, warum es nicht erwähnt wurde aber, dass dieser Ansatz ist völlig unbegründet und leicht gebrochen durch die compiler-upgrades, etc. Es würde viel mehr Sinn, um festzustellen, der Wert der Zeit, die Sie wollen, zu warten, bis spin und der Abfrage der aktuellen Zeit, bis der gewünschte Wert überschritten wird. Auf x86, die Sie nutzen könnten
rdtsc
für diesen Zweck, aber mehr tragbare Möglichkeit wäre zu nennenclock_gettime
(oder die Variante für Ihre nicht-POSIX-OS), um die Zeit zu bekommen. Aktuelle x86_64-Linux wird auch vermeiden, die syscall fürclock_gettime
und verwendenrdtsc
intern. Oder, wenn Sie behandeln können, die Kosten für eine syscall, verwenden Sie einfachclock_nanosleep
zu beginnen...InformationsquelleAutor der Antwort R..
Ich weiß nicht, aus der Spitze von meinem Kopf, wenn die avr-version der compiler unterstützt die vollständiger Satz von
#pragma
s (die interessant sind in dem link stammen alle von gcc ab version 4.4), aber das ist, wo Sie normalerweise beginnen würde.InformationsquelleAutor der Antwort dmckee
Für mich, auf GCC-4.7.0, leere asm optimiert wurde entfernt sowieso mit -O3 (nicht versuchen, mit -O2).
und mit einem i++ im register-oder flüchtige führte eine große Leistungseinbußen (in meinem Fall).
Was ich Tat, war die Verknüpfung mit anderen leeren Funktion, die der compiler konnte nicht sehen, beim kompilieren das "Hauptprogramm"
Im Grunde so aus:
Erstellt "Helfer.c") mit dieser Funktion deklariert (leere Funktion)
Dann kompiliert mit "gcc-Helfer.c -c -o helper.o"
und dann
Dieser gab mir die besten Ergebnisse (und aus meiner überzeugung, kein overhead an alle, kann Sie aber nicht testen, weil mein Programm funktioniert nicht ohne es 🙂 )
Ich denke, es sollte funktionieren, mit dem icc zu. Vielleicht nicht, wenn Sie eine Verlinkung Optimierungen, aber mit gcc tut es.
InformationsquelleAutor der Antwort BiS
setzen, dass die Schleife in einem separaten .c-Datei und nicht zu optimieren, dass eine Datei. Noch besser schreiben, dass routine in assembler und rufen Sie es von C, so oder so, der optimizer nicht engagieren.
Manchmal mache ich die flüchtige Sache, aber normalerweise ist das erstellen einer asm-Funktion, die einfach zurück
setzen Sie einen Anruf an, dass die Funktion der Optimierer wird die for - /while-Schleife fest, aber es wird nicht optimieren, weil es hat alle, die die Aufrufe der dummy-Funktion. Die nop Antwort von Denilson Sá tut die gleiche Sache, aber noch enger...
InformationsquelleAutor der Antwort old_timer
Setzen asm volatile sollte helfen.
Lesen Sie mehr dazu hier:-
http://www.nongnu.org/avr-libc/user-manual/optimization.html
Wenn Sie unter Windows arbeiten, können Sie auch versuchen, indem Sie den code unter pragmas, wie im folgenden detailliert erläutert:-
https://www.securecoding.cert.org/confluence/display/cplusplus/MSC06-CPP.+Be+aware+of+compiler+optimization+when+dealing+with+sensitive+data
Hoffe, das hilft.
InformationsquelleAutor der Antwort Groovy
Können Sie auch die registrieren keyword. Variablen, die mit register gespeichert sind, CPU-Register.
In Ihrem Fall:
InformationsquelleAutor der Antwort Michel Megens