Ich sehe bei der Art eine Funktion zu definieren nur Nachteile außer
dass sie vielleicht einen Bruchteil einer Sekunde schneller ist!!!
Jetzt meine Frage:
Gibt es irgendeineinen Grund eine Funktion so zu definieren ?
Andreas V. schrieb:> Gibt es irgendeineinen Grund eine Funktion so zu definieren ?
Wenn alle Aufruf-Parameter zur Compilezeit konstant ist, wird aus dem
Makro eine Konstante.
Timmo H. schrieb:> Andreas V. schrieb:>> A. K. schrieb:>> Inline-Funktionen sind eleganter.>>>> Inline ist doch ein C++ Keyword oder?> Nö
Sorry mein C ist ein bissl eingerostet. Liegt am Compiler bzw. an den
Einstellungen. Ich kriege es jedenfalls nur als C++ compiliert...
Ich frage mich halt nur warum man solche "#define" Definitionen für
Funktionen wie oben heute noch macht. Mal abgesehen davon dass der
Debugger streikt.
Andreas V. schrieb:>> Jetzt meine Frage:>> Gibt es irgendeineinen Grund eine Funktion so zu definieren ?
Da mpeg sicher auf diversen Plattformen laufen soll, ist das die
Variante die auf noch so alten Compilern die Multiplikation von
Komplexen Zahlen im Q1.31-Format inline ausführt.
Andreas V. schrieb:> Ich frage mich halt nur warum man solche "#define" Definitionen für> Funktionen wie oben heute noch macht. Mal abgesehen davon dass der> Debugger streikt.
Weil wegen mehr schnell!!1
:^)
Wie alt ist eigentlich die Library? Und wie alt ist der Programmierer?
Erster Verdacht ist doch - das stammt aus einer Zeit, als wir uns noch
nicht auf die Optimierung von Funktionsaufrufen verlassen konnten.
Archeologe schrieb:> Erster Verdacht ist doch - das stammt aus einer Zeit, als wir uns noch> nicht auf die Optimierung von Funktionsaufrufen verlassen konnten.
Oder - wie oben schon erwähnt wurde - es soll auch auf Compilern, die
aus dieser Zeit stammen, zu effizientem Code führen.
Andreas V. schrieb:> Ich sehe bei der Art eine Funktion zu definieren nur Nachteile außer> dass sie vielleicht einen Bruchteil einer Sekunde schneller ist!!!
Naja, wie oft wird sie denn aufgerufen? Wenn das z.B. im Dekoder für
jeden Pixel mehrmals aufgerufen wird, ist das bei einem 4k-Video mit
60fps schon verdammt viel. Da lohnt es sich ggf. auch,
> einen Bruchteil einer Sekunde
bei jedem Aufruf zu sparen!!!1einself-Ausrufezeichen
Andreas V. schrieb:> Die Frage wäre dann: Spart man mit einem modernen Compiler> wirklich> Zeit?
Bei #define: nie - sind ja nur Textersetzungen. Diese koennen zur
besseren Lesbarkeit von Code beitragen.
Bei Assembler-Code in GCC habe ich vor ca. 15 Jahren aufgegeben
haendisch einzugreifen (Tailcode-Opt., Loop-Unrolling, FP-Code, ...)
kann der GCC inzwischen besser.
Bei anderen C-Compilern wird das ca. gleich sein.
leo
Andreas V. schrieb:> Inline ist doch ein C++ Keyword oder?
Nein.
Walter T. schrieb:> Wenn alle Aufruf-Parameter zur Compilezeit konstant ist, wird aus dem> Makro eine Konstante.
Mit ganz, ganz viel Glück könnte dir der Compiler eine Funktion auch so
optimieren.
In C++ gibts constexpr dafür.
Andreas V. schrieb:> Die Frage wäre dann: Spart man mit einem modernen Compiler wirklich> Zeit?
Eher nein, wobei es natürlich auch schrottige Compiler gibt.
leo schrieb:> Bei #define: nie - sind ja nur Textersetzungen. Diese koennen zur> besseren Lesbarkeit von Code beitragen.
Er meinte ja gegenüber Funktionsaufrufen. Da spart es tatsächlich, wenn
Funktionen nicht geinlined werden (z.B. mit -O0 kompiliert).
vn n. schrieb:> Andreas V. schrieb:>> Inline ist doch ein C++ Keyword oder?>> Nein.
Um das etwas genauer zu erläutern: Es gibt in beiden Sprachen ein
Schlüsselwort "inline", allerdings nicht ganz in der selben Bedeutung.
> Walter T. schrieb:>> Wenn alle Aufruf-Parameter zur Compilezeit konstant ist, wird aus dem>> Makro eine Konstante.>> Mit ganz, ganz viel Glück könnte dir der Compiler eine Funktion auch so> optimieren.
So arg viel Glück braucht man nicht. Die Funktion muss nur inline sein,
und sofern man keine LTO hat, muss sie an der Stelle des Aufrufs der
Quellcode sichtbar sein. Und natürlich muss die Funktion auch dazu
geeignet sein (also z.B. nicht rekursiv).
> In C++ gibts constexpr dafür.
Bei GCC kann man (sowohl in C, als auch in C++) ein Inlining erzwingen
mit __attribute__((always_inline)).
> Andreas V. schrieb:>> Die Frage wäre dann: Spart man mit einem modernen Compiler wirklich>> Zeit?>> Eher nein, wobei es natürlich auch schrottige Compiler gibt.
Man braucht aber auch nicht mehr Zeit gegenüber einer Inline-Funktion.
Rolf M. schrieb:> So arg viel Glück braucht man nicht. Die Funktion muss nur inline sein,> und sofern man keine LTO hat, muss sie an der Stelle des Aufrufs der> Quellcode sichtbar sein. Und natürlich muss die Funktion auch dazu> geeignet sein (also z.B. nicht rekursiv).
Grundsätzlich ja, aber da wär halt noch das Thema "Code für
uralte/schrottige Compiler".
Aber ja, vielleicht ist auch einfach nur der Code schrottig. Wenn man
schon sowas macht, um es z.B. auch exotischen Compilern recht zu machen,
sollte man es zumindest in einem Kommentar vermerken.
Rolf M. schrieb:> Man braucht aber auch nicht mehr Zeit gegenüber einer Inline-Funktion.
Korrekt.
Wobei inline ja "erst" (oh Gott wird man alt) mit C99 Standard wurde
(vorher aber von diversen Compilern schon unterstützt wurde), womit wir
wieder beim Thema uralte/schrottige Compiler wären.
Per Makro kommt in besten Fall etwas Konstantes raus (z.B. x = 234). Mit
Inline kann es auch dynamisch sein ( x = y*203). Wenn man mit -O2 (am
schnellsten) kompiliert, dann werden Funktionen auch automatisch Inline
kompiliert wenn es schneller ist. Aber ein Makro läuft durch den
Präprozessor und erzeugt dadurch im besten Fall etwas schnelleren Code
wenn es sinnvoll eingesetzt wurde.
Ich habe noch mal die Varianten ausprobiert, weil ich mir nicht mehr
sicher war wie sich das bei aktuellen Compilern verhält. Dazu schrieb
ich folgenden Code (und ja es kommt immer das gleiche Ergebnis heraus):
Ohne dass ich jetzt groß mit Compileroptionen herumspiele bekomme ich
bei 100 Durchläufen mit jeweils 10 Mio. Berechnungen folgende
Durchschnittswerte heraus:
67,78% (Macro-Variante)
67,01% (Inline-Variante)
100,00% (Nicht optimierter Code, immer langsamer)
Wobei die Prozentzahl die Ausführzeit im Verhältnis zum nicht
optimierten Code angibt.
Andreas V. schrieb:> 67,78% (Macro-Variante)>> 67,01% (Inline-Variante)>> 100,00% (Nicht optimierter Code, immer langsamer)>> Wobei die Prozentzahl die Ausführzeit im Verhältnis zum nicht> optimierten Code angibt.
Ich frage mich, wieso dein Compiler die Rechnungen überhaupt zur
Laufzeit ausführen lässt. Mein GCC und Clang schmeißen die Rechnungen ab
-O2 einfach komplett raus.
Jemand schrieb:> Andreas V. schrieb:>> 67,78% (Macro-Variante)>>>> 67,01% (Inline-Variante)>>>> 100,00% (Nicht optimierter Code, immer langsamer)>>>> Wobei die Prozentzahl die Ausführzeit im Verhältnis zum nicht>> optimierten Code angibt.>> Ich frage mich, wieso dein Compiler die Rechnungen überhaupt zur> Laufzeit ausführen lässt. Mein GCC und Clang schmeißen die Rechnungen ab> -O2 einfach komplett raus.
Vermutlich passierte das bei obiger Messung in jedem Fall. 10^7
Schleifendurchläufe dürften wohl nur dann fast genau so schnell sein wie
(k)einer, wenn sie nicht passieren. Es ist eher so, daß -O0 50% länger
für das Zeitmessen braucht. Statt der Messung würde ich erst mal
asm volatile "nop"
um die Schleifen packen und mir den generierten Code anschauen. Mehr als
die Zuweisung von Konstanten an a und b wird da nicht stehen, wenn
überhaupt.
Eher:
Ich hätte auch den "Time"-Befehl verwenden können, aber dazu hätte ich
den Test anders aufbauen müssen!...
Die Rechnungen wurden ausgeführt. Man könnte den Durchlauf einer
Leerschleife abziehen, aber mir ging es hierbei nur darum eine
Hausnummer zu bekommen was schneller ist....
Andreas V. schrieb:> Die Rechnungen wurden ausgeführt.
Aber warum?
> mir ging es hierbei nur darum eine> Hausnummer zu bekommen was schneller ist....
Welchen Compiler verwendest du überhaupt? Eine derart schlechte
Verbesserung auf nur 67 % im Vergleich zum unoptimierten Maschinencode
bekomme ich hier mit deinem Quellcode nicht nachgestellt. (oder der
unoptimierte Maschinencode ist einfach krass gut)
Jemand schrieb:> Welchen Compiler verwendest du überhaupt? Eine derart schlechte> Verbesserung auf nur 67 % im Vergleich zum unoptimierten Maschinencode> bekomme ich hier mit deinem Quellcode nicht nachgestellt. (oder der> unoptimierte Maschinencode ist einfach krass gut)
In dem Fall nahm ich den:
VC C/C++ Optimizing Compiler Version 18.00.21005.1 for x86
Ich kann es aber auch mal mit dem IAR für MSP mal ausprobieren:
IAR 6.40.1
mh schrieb:> Andreas V. schrieb:>> (Macro-Variante) (Inline-Variante) (nicht optimiert)>> Mit "nicht optimiert" meinst du die cmuls3 Funktion und nicht -O0?
Ja. Ich meinte die Funktion cmuls3!
Ich wollte wissen ob es sich noch lohnt die Mühe zu machen den Code mit
Macros oder Inline zu optimieren oder ob die Compiler das (notfalls mit
der entsprechenden Compiler-Option) eigenständig machen.
hat es dann gebracht.
Unoptimiert brauchten sowohl gcc und VC jeweils ca. 1200ms für die
Schleifen.
Die Macros und die Inline-Funktionen brachten in etwa die gleichen
Ergebnisse wie in den Test zuvor.
Alle bekannten Compiler-Optionen brachten bei VC nicht viel. Das kenne
ich von früher her anders...
Aber mit der o. g. Option -O1 beim gcc gings dann richtig ab.
15 ms sowohl für Makro-Funktion als auch für die Inline-Funktion.
Die Ergebnisse wurden berechnet.
Das erscheint mir ein bisschen schnell...
hat es dann gebracht.
>> Unoptimiert brauchten sowohl gcc und VC jeweils ca. 1200ms für die> Schleifen.> Die Macros und die Inline-Funktionen brachten in etwa die gleichen> Ergebnisse wie in den Test zuvor.>> Alle bekannten Compiler-Optionen brachten bei VC nicht viel. Das kenne> ich von früher her anders...>> Aber mit der o. g. Option -O1 beim gcc gings dann richtig ab.> 15 ms sowohl für Makro-Funktion als auch für die Inline-Funktion.> Die Ergebnisse wurden berechnet.>> Das erscheint mir ein bisschen schnell...
Der Code sagt eigentlich nur: es wird jeweils n-mal die gleiche
Berechnung durchgeführt, die ein konstantes Ergebnis hat, das noch nicht
einmal weiterverwendet wird. Der Compiler muß noch nichtmal x auf den
Wert cmax setzen, denn x existiert ja jeweils nur innerhalb der
Schleifen. Die kürzestmögliche Übersetzung der Schleifen hat exakt 0
Byte und jeder Compiler, der mehr daraus macht, ist nicht auf der Höhe
der Zeit. Nicht umsonst gibt es mit volatile die Möglichkeit dem
Compiler mitzuteilen, daß Dinge passieren können, die er nicht sehen
kann.
N-mal konstante Werte beliebig kompliziert in ein nicht weiter
interessierendes Ergebnis zu verrechnen sollte immer exakt 0 beliebige
Zeiteinheiten dauern. Auch für sehr große N.
>> Andreas V. schrieb:>> gcc -O1 testgcc.c hat es dann gebracht.>> Warum nimmst du "-O1" und nicht "-O3" oder "-O2"?
Erst einmal wäre für mich die Frage wofür "-O1" steht?
Laut manpages gcc Option für 'Level', was immer man sich darunter
vorstellen darf - denn mehr findet man dort nicht.
Welche der rund 600 mehr oder weniger gut dokumentierten Optionen ist es
denn nun?
https://www-user.tu-chemnitz.de/~hmai/gcc/Ausarbeitung_1/options.html
Weiterhin würde mich interessieren welche Compilerversion Du unter
CodeBlocks benutzt?
Das alles 'Zufall' beim Compilieren und anschließender Ausführung sein
soll, glaube ich nämlich nicht.
Carl D. schrieb:> Der Code sagt eigentlich nur: es wird jeweils n-mal die gleiche> Berechnung durchgeführt, die ein konstantes Ergebnis hat, das noch nicht> einmal weiterverwendet wird. Der Compiler muß noch nichtmal x auf den> Wert cmax setzen, denn x existiert ja jeweils nur innerhalb der> Schleifen. Die kürzestmögliche Übersetzung der Schleifen hat exakt 0> Byte und jeder Compiler, der mehr daraus macht, ist nicht auf der Höhe> der Zeit. Nicht umsonst gibt es mit volatile die Möglichkeit dem> Compiler mitzuteilen, daß Dinge passieren können, die er nicht sehen> kann.>> N-mal konstante Werte beliebig kompliziert in ein nicht weiter> interessierendes Ergebnis zu verrechnen sollte immer exakt 0 beliebige> Zeiteinheiten dauern. Auch für sehr große N.
Ich habe noch einmal eine Operation hinzugefügt (are = are + 1;) und die
Bit-Schiebeaktion weggelassen. Es sind jetzt so oder so keine
Konstanten. Man sollte auch beachten dass die Parameter "Call by
Reference" übergeben werden und nicht "Call by Value". Die Werte werden
also weiterverwendet.
Die Zeitwerte haben sich nicht wesentlich geändert!
S. R. schrieb:> Andreas V. schrieb:>> gcc -O1 testgcc.c hat es dann gebracht.>> Warum nimmst du "-O1" und nicht "-O3" oder "-O2"?
Ich verwende solche Optionen mit Vorsicht. Da muss man aufpassen dass
nichts wegoptimiert wird. In der Praxis würde ich so etwas nur verwenden
wenn es nicht anders geht.
Ich kenne bessere Arten seine Zeit zu verbringen...
Andreas V. schrieb:> Eine Optimierung um das 1000-fache schneller. Da gibt es doch> Nebeneffekte! Oder?
Wenn du dich an die Regeln hältst, gibt es keine Nebeneffekte.
Andreas V. schrieb:> Eine Optimierung um das 1000-fache schneller. Da gibt es doch> Nebeneffekte! Oder?
Wie man in den Wald reinruft, so schallt es zurück. Bei Testcode muss
man drauf achten, dass es nicht ausreicht, den Compiler das Endergebnis
selbst ermitteln zu lassen. Sonst setzt der dieses Endergebnis in den
Code rein, nicht den Algorithmus.
Solche Optimierungen sind sinnvoller als mancher annimmt. Denn ein
Nebeneffekt von Konstanten statt Variablen als Parameter solcher Makros
oder Funktionen ist eine mögliche Vereinfachung der Berechnung. Das
kommt in realem Code öfter vor und ist genauso richtig.
Ein weiterer Nebeneffekt ist, dass bei laut Standard nicht klar
definiertem Ergebnis der Compiler etwas anders rechnen könnte als die
Maschine.
Andreas V. schrieb:> Das erscheint mir ein bisschen schnell...Andreas V. schrieb:> Da gibt es doch> Nebeneffekte! Oder?
Es ist schon erstaunlich, wie moderne Compiler optimieren können!
Im Studium habe ich mal einen Equalizer in C implementiert, der bestand
aus kaskadierten Filtern mit jeweils einigen Additionen/Multiplikationen
pro Stufe.
Während ich selbst mit allen mir bekannten Tricks die Laufzeit im
Vergleich zur nicht-optimierten Implementierung nur halbieren konnte,
hat der gcc sie mit gesetztem Optimierungsflag auf unter 1% gedrückt.
Habe ich dann ungläubig dem Prof. gezeigt, er war aber wenig überrascht
und meinte nur, dass vernünftige Compiler heutzutage besser optimieren
als die meisten "Experten".
A. K. schrieb:> Solche Optimierungen sind sinnvoller als mancher annimmt. Den ein> Nebeneffekt von Konstanten statt Variablen als Parameter solcher Makros> oder Funktionen ist eine mögliche Vereinfachung der Berechnung. Das> kommt in realem Code öfter vor und ist genauso richtig.
Hier ein Beispiel über dass ich gestern gestolpert bin:
1
// The macros below are derived from the ones above and are used to
2
// check for more specific object types.
3
// Note: these are kept as macros because inline functions sometimes use much
4
// more code space than the equivalent macros, depending on the compiler.
5
6
#define MP_OBJ_IS_TYPE(o, t) (MP_OBJ_IS_OBJ(o) && (((mp_obj_base_t*)MP_OBJ_TO_PTR(o))->type == (t))) // this does not work for checking int, str or fun; use below macros for that
mh schrieb:> Andreas V. schrieb:>> Eine Optimierung um das 1000-fache schneller. Da gibt es doch>> Nebeneffekte! Oder?>> Wenn du dich an die Regeln hältst, gibt es keine Nebeneffekte.
Wenn ich dich bisher richtig verstanden habe, benutzt du die Sprache c.
Du musst dich also an die Regeln der Sprache c halten?!?
mh schrieb:> mh schrieb:>> Andreas V. schrieb:>>> Eine Optimierung um das 1000-fache schneller. Da gibt es doch>>> Nebeneffekte! Oder?>>>> Wenn du dich an die Regeln hältst, gibt es keine Nebeneffekte.>> Wenn ich dich bisher richtig verstanden habe, benutzt du die Sprache c.> Du musst dich also an die Regeln der Sprache c halten?!?
Also ich kann mich daran erinnern dass da unter Umständen
Typenprüfungen, Overflows usw. nicht mehr geprüft werden...
Andreas V. schrieb:> Also ich kann mich daran erinnern dass da unter Umständen> Typenprüfungen, Overflows usw. nicht mehr geprüft werden...
Nur wenn du dich nicht an die Regeln hältst...
Andreas V. schrieb:> Also ich kann mich daran erinnern dass da unter Umständen> Typenprüfungen, Overflows usw. nicht mehr geprüft werden...
In C wird sowas üblicherweise vom Compiler und nicht zur Laufzeit
geprüft.
Die Zeit, die für die Kompilierung benötigt wird, ist bei einem
optimierenden Compiler vermutlich höher.
Andreas V. schrieb:> Was kann man an so einfachen Berechnungen und Schleifen> wegoptimieren> außer Überprüfungen, Exceptions, ..?
Die ganze Schleife, wenn niemand das Ergebnis anguckt.
mh schrieb:>> Was kann man an so einfachen Berechnungen und Schleifen>> wegoptimieren>> außer Überprüfungen, Exceptions, ..?>> Die ganze Schleife, wenn niemand das Ergebnis anguckt.
Ganz genau!
Andreas V. schrieb:> mh schrieb:>>> Was kann man an so einfachen Berechnungen und Schleifen>>> wegoptimieren>>> außer Überprüfungen, Exceptions, ..?>>>> Die ganze Schleife, wenn niemand das Ergebnis anguckt.>> Ganz genau!
Wo ist dann dein Problem? Die Aussagekraft deines "Benchmarks" geht auch
gegen 0, wenn die Schleife nicht wegoptimiert wird.
mh schrieb:> Wo ist dann dein Problem? Die Aussagekraft deines "Benchmarks" geht auch> gegen 0, wenn die Schleife nicht wegoptimiert wird.
Ich habe mich nur gefragt warum man C-Macros verwendet, wenn es
Inline-Funktionen und Compiler-Optionen gibt.
Das Macro ist nicht von mir und wahrscheinlich sehr alt. Außerdem
gefällt mir die (Typen-)Deklaration/Definition nicht. Das do-while
Konstrukt kann ich mir nur so erklären dass der Compiler es damals
anders nicht genommen hat. Warum das Macro schnreller ist und kleiner im
Code umgesetzt wird hängt meiner Meinung nach damit zusammen dass mit
den Typen, Überläufen, Exceptions,... weniger strict verfahren wird.
Liege ich falsch?
Andreas V. schrieb:> Das do-while> Konstukt kann ich mir nur so erklären dass der Compiler es damals anders> nicht genommen hat.
Bei
#define MACRO(x) { ... }
if (cond)
MACRO(x);
else
unsinn();
gibts einen Syntaxfehler, weil das ";" zu viel ist. Bei
#define MACRO(x) do{ ... }while(0)
passt es.
A. K. schrieb:> Andreas V. schrieb:>> Das do-while>> Konstukt kann ich mir nur so erklären dass der Compiler es damals anders>> nicht genommen hat.>> Bei> #define MACRO(x) { ... }>> if (cond)> MACRO(x);> else> unsinn();> gibts einen Syntaxfehler, weil das ";" zu viel ist. Bei> #define MACRO(x) do{ ... }while(0)> passt es.
Mir gehen Macros auch aufn Keks...
> Hier ein Beispiel über dass ich gestern gestolpert bin:>> // The macros below are derived from the ones above and are used to> // check for more specific object types.> // Note: these are kept as macros because inline functions sometimes use> much> // more code space than the equivalent macros, depending on the> compiler.>> #define MP_OBJ_IS_TYPE(o, t) (MP_OBJ_IS_OBJ(o) &&> (((mp_obj_base_t*)MP_OBJ_TO_PTR(o))->type == (t))) // this does not work> for checking int, str or fun; use below macros for that> #define MP_OBJ_IS_INT(o) (MP_OBJ_IS_SMALL_INT(o) || MP_OBJ_IS_TYPE(o,> &mp_type_int))
...
> Man beachte das Kommentar!
Typensicherheit ADE!
Wenn ich so etwas sehe dann will ich mich nur noch erschießen...
Andreas V. schrieb:> Ich habe mich nur gefragt warum man C-Macros verwendet, wenn es> Inline-Funktionen und Compiler-Optionen gibt.
Ganz einfach - weil es Menschen gibt, die wie folgt denken:
Andreas V. schrieb:>>> gcc -O1 testgcc.c hat es dann gebracht.>> Warum nimmst du "-O1" und nicht "-O3" oder "-O2"?>> Ich verwende solche Optionen mit Vorsicht.> Da muss man aufpassen dass nichts wegoptimiert wird.> In der Praxis würde ich so etwas nur verwenden> wenn es nicht anders geht.
Konkret: Wenn du Optimierungen abschaltest, weil du Angst davor hast,
dann bist du mit dem Makro deutlich besser dran als mit dem besten
Compiler der Welt, denn du hast ihm ja die Optimierungen verboten.
> Ich frage mich halt nur warum man solche "#define" Definitionen für> Funktionen wie oben heute noch macht. Mal abgesehen davon dass der> Debugger streikt.
Das geht natürlich auch als Inline Function. Inline Functions werden
allerdings wie normale Funktionen realisiert wenn man ohne Optimierungen
compiliert.
Das ganze als Macro zu definieren erzwingt das inlining und kann dadurch
auch im Debug Build eine akzeptable Geschwindigkeit erzielen.
Ja, das ist beim debuggen blöd, aber wenigstens hat man eine Chance zu
debuggen.
Andreas V. schrieb:> S. R. schrieb:>> Andreas V. schrieb:>>> gcc -O1 testgcc.c hat es dann gebracht.>>>> Warum nimmst du "-O1" und nicht "-O3" oder "-O2"?>> Ich verwende solche Optionen mit Vorsicht. Da muss man aufpassen dass> nichts wegoptimiert wird. In der Praxis würde ich so etwas nur verwenden> wenn es nicht anders geht.
Wenn was wegoptimiert wird, das eigentlich notwendig wäre, hat das
Programm einen Fehler.
Andreas V. schrieb:> mh schrieb:>> Wenn du dich an die Regeln hältst, gibt es keine Nebeneffekte.>> Welche Regeln? ;-)
Na die von C.
Andreas V. schrieb:> Ich habe keine Angst, aber nur begrenzt Zeit alle Funktionen> nachzuprüfen!> Es wäre nicht dass erste Mal dass eine Schleife wegoptimiert wird, oder> ...
Wie gesagt: Dann ist eigentlich das Programm fehlerhaft, und du hast den
Fehler durch Unterdrücken der Optimierungen nur versteckt. Das ist
meiner Meinung nach keine gute Herangehensweise.
Andreas V. schrieb:> Ich habe keine Angst, aber nur begrenzt Zeit alle Funktionen> nachzuprüfen!
Also hast du Angst, dass der Compiler irgendwas mit deinem Code macht,
was du nicht willst...
Andreas V. schrieb:> Es wäre nicht dass erste Mal dass eine Schleife wegoptimiert> wird, oder ...
...was bedeutet, dass dein Code schlicht fehlerhaft ist.
Oder bist du tatsächlich darauf angewiesen, dass überflüssige Schleifen
in deinem Code tatsächlich zur Laufzeit ausgeführt werden müssen?
Andreas V. schrieb:> Ich habe keine Angst, aber nur begrenzt Zeit alle Funktionen> nachzuprüfen!
Dann lass dir doch vom Compiler helfen und schalte alle Optimierungen
und Warnungen an. Wenn der Code dann nicht mehr funktioniert, ist er
höchstwahrscheinlich falsch. Diese Fehler könnten ja auch mit neuen
Compiler Versionen oder anderen Konstellationen auch ohne Optimierungen
doch wieder auftreten.
Code, der nur ohne Optimierung funktioniert, würde ich nie produktiv
nutzen - wer weiß wann einem diese Mine um die Ohren fliegt! Wenn
offensichtlich Fehler drin sind, kann man das doch nicht so lassen.
Rolf M. schrieb:> Wenn was wegoptimiert wird, das eigentlich notwendig wäre, hat das> Programm einen Fehler.
ACK! Ich habe sehr sehr selten bis nie ein Problem mit der Optimierung.
Ohne die wären einige Projekte garnicht vernünftig gelaufen weil einfach
keine Rechenzeit übrig war in Peak-Situationen. Gut das ist auch etwas,
was einem die Nase kraus werden lässt, ging aber nicht mehr anders. Oder
ein Requirement dass eine CPU-Load von xx% nicht überschritten werden
darf, hätte sonst nicht eingehalten werden können.
Ich habe eben folgende Zeilen im bzip2 Code gefunden:
1
static
2
intbz_config_ok(void)
3
{
4
if(sizeof(int)!=4)return0;
5
if(sizeof(short)!=2)return0;
6
if(sizeof(char)!=1)return0;
7
return;
8
}
Bei Optimierung auf Codegröße(/O1) oder Schnelligkeit (/O2) gibt die
Funktion immer 0 zurück.
sizeof(int) ergibt 0!
Ich kann also nicht mehr zippen!
;-)
Andreas V. schrieb:> Bei Optimierung auf Codegröße(/O1) oder Schnelligkeit (/O2) gibt die> Funktion immer 0 zurück.
Was sollte diese Funktion deiner Meinung nach zurück geben?
Andreas V. schrieb:> sizeof(int) ergibt 0!
Hmmm.... das halte ich für ein Gerücht.
Außerdem ist der return-Wert beim letzten Return undefiniert.
Die Routine ist buggy.
Andreas V. schrieb:> Ich habe eben folgende Zeilen im bzip2 Code gefunden:>>
1
>static
2
>intbz_config_ok(void)
3
>{
4
>if(sizeof(int)!=4)return0;
5
>if(sizeof(short)!=2)return0;
6
>if(sizeof(char)!=1)return0;
7
>return;
8
>}
9
>
>> Bei Optimierung auf Codegröße(/O1) oder Schnelligkeit (/O2) gibt die> Funktion immer 0 zurück.>> sizeof(int) ergibt 0!>> Ich kann also nicht mehr zippen!> ;-)
Die Zeile
1
return;
Sollte eine Warnung/einen Fehler produzieren.
Wenn nicht, solltest du die Compilerflags prüfen.
merciless
900ss D. schrieb:> Außerdem ist der return-Wert beim letzten Return undefiniert.> Die Routine ist buggy.
Offensichtlich hat er den Code fehlerhaft abgetippt (Copy&paste
anyone?), denn das Original lt. Sourceforge sieht anders aus:
1
static
2
intbz_config_ok(void)
3
{
4
if(sizeof(int)!=4)return0;
5
if(sizeof(short)!=2)return0;
6
if(sizeof(char)!=1)return0;
7
return1;
8
}
Schnell überflogen ist rätselhaft, was da wegoptimiert werden soll.
Andreas V. schrieb:> sizeof(int) ergibt 0!
Mit Sicherheit nicht. Woher nimmst du diese Weißheit?
Andreas V. schrieb:> Bei Optimierung auf Codegröße(/O1) oder Schnelligkeit (/O2)
O1 und O2 ist beides auf Geschwindigkeit. Os ist Codegröße, beim GCC
jedenfalls.
sorry das "return 1;" ist irgendwie beim Kopieren verlorengegangen. Da
hätte der Compiler schon angeschlagen;
Es funzt trotzdem nicht.
/O1 (auf Größe optimiert)
/O2 (auf Geschwindigkeit optimiert)
zumindest ist das beim VC so.
Andreas V. schrieb:> /O2 (auf Geschwindigkeit optimiert)
Und das stimmt nicht, es ist auch eine Laufzeitoptimierung.
Wie schon jemand Schritten -Os ist "för speed".
vn n. schrieb:> Schnell überflogen ist rätselhaft, was da wegoptimiert werden soll.
Der Compiler kann sämtliche sizeof() zur Compilezeit ausrechnen und dann
die gesamte Funktion wegoptimieren.
Auf manchen Architekturen (z.B. AVR) ist sizeof(int) == 2, dann gibt die
Funktion immer 0 zurück. Alle auch nur ansatzweise üblichen
Architekturen, wo das nicht der Fall ist, haben sizeof(int) == 4.
Wenn da was anderes rauskommt, ist höchstwahrscheinlich der Compiler
kaputt.
Aber ich glaube, der TO will uns nur ein (doofes) Beispiel für "der
Compiler optimiert meine Funktion weg und das will ich nicht" zeigen.
Was natürlich schon in sich relativ bescheuert ist, aber das ist ja
nicht mein Problem.
Andreas V. schrieb:> Ich habe es mir im Debugger ausgeben lassen.
Also du bist schrittweise durch die Funktion gesteppt?
Wenn du den Compiler optimieren läst, dann passen die
Zeileninformationen nicht mehr zum Sourcecode und es kommt erstmal
wirres beim debuggen raus.
Du müsst dir das Ergebnis von der Funktion mit printf oder sonst wie
ausgeben lassen.
Andreas V. schrieb:> A. K. schrieb:>> Inline-Funktionen sind eleganter.>> Inline ist doch ein C++ Keyword oder?
Njein,
"inline" ist relativ neu im C-Standard; es wurde eingeführt in "section
6.7.4 of the C99 standard (ISO/IEC 9899:1999)". Verschiedene Compiler
wie der gcc kannten es schon bevor es Standard wurde (1999).
Da MPEG aber älter ist (1991), könnte das der Grund sein, warum man sich
für die unelegantere aber steinzeitkompatiblevariante entschied. Falls
es mangels der "inline"-Unterstützung der damaligen Compiler überhaupt
eine Entscheidungsmöglichkeit gab.
Andreas V. schrieb:> Also habe ich auf einem X86 (32 Bit) ein Sizeof(int) von 0.> Will heißen ich habe viel Speicher gespart / optimiert!
Nö, du hast nur deine Unfähigkeit bescheinigt.
S. R. schrieb:> Der Compiler kann sämtliche sizeof() zur Compilezeit ausrechnen und dann> die gesamte Funktion wegoptimieren.
Natürlich kann er das, aber es erklärt nicht warum es dann nicht
funktionieren soll, so war das gemeint.
S. R. schrieb:> Auf manchen Architekturen (z.B. AVR) ist sizeof(int) == 2, dann gibt die> Funktion immer 0 zurück. Alle auch nur ansatzweise üblichen> Architekturen, wo das nicht der Fall ist, haben sizeof(int) == 4.
Klar, wobei das eine denkbar doofe Lösung ist, könnte man seit C99
immerhin auch einfach uint32_t nehmen.
S. R. schrieb:> Aber ich glaube, der TO will uns nur ein (doofes) Beispiel für "der> Compiler optimiert meine Funktion weg und das will ich nicht" zeigen.> Was natürlich schon in sich relativ bescheuert ist, aber das ist ja> nicht mein Problem.
Vermutlich, oder er will einfach nur trollen.
vn n. schrieb:> Er meinte ja gegenüber Funktionsaufrufen. Da spart es tatsächlich, wenn> Funktionen nicht geinlined werden (z.B. mit -O0 kompiliert).
Es es nicht nur der Aufruf der Funktion, der Compiler kann dann besser
optimieren. Das gilt sowohl für Makros und für inline.
Natürlich kann er das, aber was hat das mit meinem Posting zu tun?
Die Sache mit dem Macro ist drinnen weil damals Compiler oftmals nicht
mal inlinen konnten, da brauchte man über weitergehende Optimierungen
nicht mal nachdenken. Dass er das heute schon kann, wurde ja schon zu
genüge geklärt.
Andreas V. schrieb:> Ich habe es mir im Debugger mit und ohne Optimierung ausgeben lassen.
Gib es mit z.B. printf aus. Die Ausführung von optimiertem Code im
Debugger hat ihre Tücken.
Rolf M. schrieb:> Gib es mit z.B. printf aus.
Hatte ich oben ja schon vorgeschlagen.
Er weiss es besser und glaubt es nicht. Dabei ist das wirklich die
einfachste Art, dass zu prüfen. Lass ihn weiter alles besser wissen :)
Rolf M. schrieb:> Gib es mit z.B. printf aus. Die Ausführung von optimiertem Code im> Debugger hat ihre Tücken.
Ich lache mich tot.
Ich hatte vorher schon einen kompletten cleanup gemacht und alles neu
kompiliert. Es funzte nicht.
Nur wenn ich die Werte mit printf ausgebe springt das Programm nicht zum
Exit. Ist halt nur blöd wenn man mal ein Gerät hat das kein printf
kennt.
Ja schon klar über serial Port, aber denn will man ja vielleicht
nicht....
Die IDE war mir abgestürzt...
Andreas V. schrieb:> Rolf M. schrieb:>> Gib es mit z.B. printf aus. Die Ausführung von optimiertem Code im>> Debugger hat ihre Tücken.>> Ich lache mich tot.> Ich hatte vorher schon einen kompletten cleanup gemacht und alles neu> kompiliert. Es funzte nicht.>> Nur wenn ich die Werte mit printf ausgebe springt das Programm nicht zum> Exit. Ist halt nur blöd wenn man mal ein Gerät hat das kein printf> kennt.>> Ja schon klar über serial Port, aber denn will man ja vielleicht> nicht....
Es ist doch ganz einfach: Wenn du ein sizeof(int) machst, es aber
nirgends im Programm benutzt, dann ist es nutzlos und wird vom Compiler
wegoptimiert. Sobald du es auch benutzt, passiert das natürlich nicht
mehr. Der Optimizer ist ja gerade dafür da, alles rauszuwerfen, was
nicht benötigt wird. Deshalb kommt natürlich auch Blödsinn raus, wenn du
Code schreibst, dessen Ergebnis du im Programm gar nicht benutzt und
dann im Debugger anschaust, welcher Wert rauskommt. Für das Programm
spielt der Wert keine Rolle, da es ihn sowieso verwirft. Baust du das
printf ein, dann wird der Wert benötigt, da er ja ausgegeben werden
muss, also kann er nicht mehr wegoptimiert werden.
Bau das printf einfach an eine andere Stelle im Code ein. So hatte ich
es auch gemeint. In der Funktion bz_config_ok ... da hat Rolf schon
Recht.
Und was gibt printf dir aus? :)
Andreas V. schrieb:> Dann kann ich bz_config_ok ja auskommentieren.
Wenn du das Ergebnis eh nicht verwendest, klar. Dann ändert sich dadurch
ja auch am Programmablauf nix.
Andreas V. schrieb:> Ich lache mich tot.
Hör auf zu trollen.
Du erzeugst absichtlich Fehler, um uns dann weismachen zu wollen, dass
optimierter Code fehlerhaft ist. Dabei bist du es, der den Unsinn
verzapft.
Andreas V. schrieb:> Dann kann ich bz_config_ok ja auskommentieren.
Oder direkt zur Compile-Zeit prüfen:
1
#include<assert.h>
2
3
static_assert(sizeof(int)==4,"Int muss 4 bytes sein");
4
static_assert(sizeof(short)==2,"Short muss 2 bytes sein");
5
static_assert(sizeof(char)==1,"Char muss 1 bytes sein");
Die letzte Prüfung ist natürlich sinnlos - sizeof(char) ist immer 1,
auf jeder Plattform. Die Einheit, in der sizeof die Größe zurückgibt,
sind Vielfache von der Größe von char - und 1 char ist nunmal genau 1
char groß.
Noch besser ist aber natürlich auch die Verwendung von (u)int16_t und
(u)int32_t. sizeof() übrigens gibt nie 0 zurück.
Dr. Sommer schrieb:> Die letzte Prüfung ist natürlich sinnlos - sizeof(char) ist immer 1,> auf jeder Plattform. Die Einheit, in der sizeof die Größe zurückgibt,> sind Vielfache von der Größe von char - und 1 char ist nunmal genau 1> char groß.
Höchstens einen kaputten Compiler könnte man damit noch detektieren,
aber so dermaßen kaputt wird wohl keiner sein.
Dr. Sommer schrieb:> Noch besser ist aber natürlich auch die Verwendung von (u)int16_t und> (u)int32_t.
Heute (damals gab es die vielleicht noch nicht, je nachdem von wann der
Code ist) wäre dies sogar die einzig sinnvolle Variante.
Denn der Code macht dies ja vermutlich um sicherzustellen dass char ==
8bit, short == 16bit und int == 32bit ist. Blöderweise gibt es aber auch
Plattformen auf denen gilt char == 16bit (für so eine schreib ich
gerade). Wäre dort short == 32bit und int == 64bit (sind sie in meinem
konkreten Fall nicht, wäre aber durchaus denkbar) wäre die Bedingung der
sizeofs trotzdem erfüllt.
vn n. schrieb:> Wäre dort short == 32bit und int == 64bit (sind sie in meinem> konkreten Fall nicht, wäre aber durchaus denkbar) wäre die Bedingung der> sizeofs trotzdem erfüllt.
Richtig. Daher muss man zusätzlich prüfen ob CHAR_BIT = 8 ist. Das wäre
deutlich sinnvoller als sizeof(char)=1 zu prüfen.