Performance der Basisoperationen. Wie teuer ist...
-
volkard schrieb:
GPC schrieb:
manchmal sind echte inline-Funktionen schneller, manchmal Makros...
zeig mir ein beispiel. und nicht eins, wo die inlinefunktion so riesig ist, daß der compiler sie einfach nicht inlined.
Ein Beispiel für was? Eins bei dem Macros schneller sind als Funktionen? Ich hab grad keins parat, aber da du ja auch im Besitz von Programming Pearls bist, verweise ich dich auf Column 9, Page 89, das max(a,b) Makro ganz unten. Hier halbiert das Makro die Laufzeit.
Im gleichen Absatz befindet sich auch ein Verweis auf 8.3, Page 79-80, hier erhöht sich die Laufzeit des floatsum3 - Algos (maximalen Subvektor eines Vektors herausfinden) um den Faktor 10 000, wenn man ein Makro anstatt eine Funktion benutzt.
Es ist jetzt schon gute 10 (oder auch 20, je nach Kapitel) Jahre her, dass diese Beispiele geschrieben wurden. Die Compiler sind in dieser Zeit sicherlich den ein oder anderen Tick besser geworden, allein das dürfte schon einiges an der Grundperformance des Programms gedreht haben.
Wie auch immer, ich überlasse dem Compiler die Arbeit. Soll er doch zuerst schauen, was er für am Besten hält. Reicht es mir von der Performance noch nicht, kann ich immer noch rumexperimentieren... kommt aber äußerst selten vor, dass ich in dieser Situation lande.Erst kürzlich hab ich ein kleines Programm für's Studium geschrieben, welches den Cache analysiert. In dem Zusammenhang könnte man ja mal schauen, ob ein Makro anstatt der Funktion was verändert. Ich vermute eher nicht. Aber wie gesagt, Messergebnisse sind in solchen Fällen sinnvoller als Vermutungen.
MfG
GPC
-
GPC schrieb:
Ein Beispiel für was? Eins bei dem Macros schneller sind als Funktionen?
nee, eins wo makros schneller sind als *inline*-funktionen.
-
@jox
Optimierung ist ja schön und gut, aber dein Makro bringt dir nur Nachteile. Glaub es mir, intrinsic Funktionen wie strlen wirst du nicht besser hinbekommen als ein Compiler. Früher mag das ja ein netter Zeitvertreib gewesen sein, und hat durchaus etwas gebracht, weil man zB Befehlserweiterungen wie MMX benutzen konnte, welche Compiler nicht beherrschten. Heutzutage bringt das bei solchen Sachen aber nichts mehr.
Ich habe das Makro einfach mal durch einen einfachen Benchmark geschickt (gcc -O3), mit 5, 20 und 100 Zeichen Strings. Und bereits bei 5 Zeichen war dein Makro ca. doppelt so langsam, bei 100 Zeichen ca. 3 mal so langsam. Es wird nach oben hin also nicht besser, was auch nicht zu erwarten war. Wenn du deine Tests natürlich nur mit -O laufen lässt, ist ja klar, dass durch kaum vorhandene Optimierung handgeschriebene Algos besser zur Geltung kommen. Für aussagekräftige Ergebnisse ist dies jedoch vollkommen nutzlos.
Mir scheint einfach, dir ist das Konzept von Release und Debug Builds unbekannt.jox schrieb:
Da irrst du dich.
jox schrieb:
, die Nachteile beim Debuggen überwiegen.
Ein entsprechender Debug Build hat keine Nachteile beim Debuggen.
-
... wie gesagt, die ganzen Fragestellungen haben zwar kaum mehr etwas mit dem Ursprungsthema zu tun, aber trotzdem eine interessante Diskussion.
groovemaster schrieb:
... Ein entsprechender Debug Build hat keine Nachteile beim Debuggen.
Das sehe ich anders.
Hast Du schon mal Dich gefreut, wenn mal ein sporadischen Fehler (ausgelöst durch irgendeinen äußeren Einfluss oder eine komische Lastsituation) nach 1/2 Tag oder mehr Laufzeit endlich aufgetreten ist (womöglich noch in einem produktiven Umfeld) und wenn Du dann mit dem gdb da ran konntest und den Code durchsteppen konntest? Da nützt Dir dann auch kein Debug-Build, weil Du gerade am laufenden Produktivsystem herumfummelst und einen hoch optimierten Code nicht mehr so wirklich nachvollziehen kannst...Im Prinzip stimme ich Dir vollkommen zu, das Optimieren sollte man nach Möglichkeit dem Compiler überlassen, aber es kann im wirklichen Leben durchaus Situationen geben, bei denen man zu Kompromissen gezwungen ist.
Und was spricht dagegen, wenn ein System über einen längeren Zeitraum keine Fehler mehr zeigt, dann alle für den Level -O "Hand"-optimierten Makro-Rümpfe durch "normale" Funktionsaufrufe (evtl. durch eine geänderte/andere zentrale Include-Datei) zu ersetzen und dann das System mit einem besseren Optimierungslevel zu übersetzen. Dazu müssen die zentralen häufig genutzten Makros/Funktionen natürlich ordentlich gekapselt werden, was man ja voraussetzen sollte.
groovemaster schrieb:
Ich habe das Makro einfach mal durch einen einfachen Benchmark geschickt (gcc -O3), mit 5, 20 und 100 Zeichen Strings. Und bereits bei 5 Zeichen war dein Makro ca. doppelt so langsam, bei 100 Zeichen ca. 3 mal so langsam.
... ok, ok ... Ich werde den Algorithmus nochmal in Frage stellen, bei Gelegenheit noch einmal testen und mich dann für den für die spezielle Anwendung performantesten Weg (ggf. mit den oben genannten Einschränkungen) entscheiden.
Trotzdem, nur mal so als Frage/Anregung: Mit der Option -O3 versucht der gcc, Inline-Code zu erzeugen. Ist das bei Dir passiert? Hat das ggf. auch für den besseren Benchmark geführt als wirkliche Unterprogramm-Aufrufe? Das würde nämlich genau meine Aussage (s.u.) bestätigen. Anderenfalls möchte ich sehr stark bezweifeln, dass bei einer Zeichenlänge von 5 Zeichen die ganzen Stack-Operationen zu vernachlässigen sind... Das funktioniert nicht mit Unterprogramm-Aufrufen! (ok,ok... bei längeren Zeichenketten kein Thema)
=> Und wie nochmals gesagt: mir geht es nun wirklich nicht darum, für strlen() einen BESSEREN ALGORITHMUS zu finden, d.h. nicht um irgendeine Optimierung auf Sourcecode-Level!!! Ich habe nur gesagt, dass Inline-Code evtl. Performance-Vorteile bringen kann und deshalb Prozessor-Zyklen zählen und Messungen die heutige Prozessor-Architektur berücksichtigen müssen!!!! (so, jetzt habe ich langsam aber Fusseln am Mund
-
volkard schrieb:
GPC schrieb:
Ein Beispiel für was? Eins bei dem Macros schneller sind als Funktionen?
nee, eins wo makros schneller sind als *inline*-funktionen.
Ah ja. Da beides Formen der "Textersetzung" sind, dürften die Unterschiede gering ausfallen. Gehen wir's an...
Folgender Code erstellt eine Liste mit Zufallszahlen bis 1000000. Die Anzahl der Zufallszahlen ist als Argument beim Aufruf mitanzugeben://creator.cpp #include <fstream> #include <cstdlib> #include <ctime> using namespace std; int main(int argc, char **argv) { if (argc<2) return 1; srand(time(0)); int N = atoi(argv[1]); const int MAX_VALUE = 1000000; int x[MAX_VALUE]; for (int i=0;i<MAX_VALUE;++i) x[i] = i; ofstream ofs("list.txt"); if (!ofs) return 1; //ofs<<N<<'\n'; for (int i=0;i<N;++i) { swap(x[i], x[rand()%(MAX_VALUE-1)]); ofs<<x[i]<<'\n'; } ofs.close(); return EXIT_SUCCESS; }
Das hier ist das Testprogramm. Es berechnet die maximale Summe eines Subvektors innerhalb eines Vektors. Ich habe mit Absicht eine langsamere Lösung als die optimale gewählt. Hmm.. ich merke gerade, da ist noch ein Bug in maxsum drin, aber egal, das ist in dem Fall nicht wichtig. Bei diesem Programm machen wir max(a, b) mal zur Funktion, mal zum Makro usw., um zu testen, was dabei rauskommt.
//main.c #include <stdio.h> #include <stdlib.h> /*int max(int a, int b) { return (a<b) ? b:a; };*/ //#define max(a, b) (((a) < (b)) ? (b) : (a)) int maxsum(int *arr, int n) { int maxsofar = 0; for (int i = 0; i < n; ++i) { int sum = 0; for (int j = i; j < n; ++j) { sum += arr[j]; //maxsofar = (maxsofar < sum) ? sum : maxsofar; maxsofar = max(maxsofar, sum); } } return maxsofar; }; int main() { const int NUM = 30000; //oder 40000 int index = 0; int *array = malloc(sizeof(*array) * NUM); if (!array) return 1; FILE *in = fopen("list.txt", "r"); if (!in) return 2; while (!feof(in) && index < NUM) fscanf(in, "%d", &array[index++] ); fclose(in); printf("%d\n", maxsum(array, NUM-1)); free(array); return 0; };
Kompiliert habe ich den Code mit dem gcc 3.3.6: gcc -std=c99 -O2 -o main main.c
Bei 30.000 Einträgen erhielt ich folgende Ausgabe auf meinem System:
Code direkt reingeschrieben:
real 0m1.828s user 0m1.799s sys 0m0.012s
Makro:
real 0m1.817s user 0m1.799s sys 0m0.008s
Normale Funktion:
real 0m6.662s user 0m6.533s sys 0m0.047s
inline Funktion
real 0m1.845s user 0m1.808s sys 0m0.015s
Hier schenkt sich inline und Makro wirklich nicht mehr viel... der Vorteil von inline ist jedoch, dass man vernünftige Funktionen hat und keine hässlichen und fehleranfälligen Makros, wurscht. -O3 verlangsamt den Algo interessanterweise. Wird gar nicht optimiert, ist das Makro am schnellsten^^. Die Ergebnisse variierten bei mehreren Läufen z.T. um ca 0.010 - 0.030, ein paar mal war auch die inline Funktion schneller als das Makro. Und nun... Nichts neues im Westen?
-
in wie fern sollten sich die kompilate von makro und inline-funktion (die auch tatsaechlich ge-inline't wird) ueberhaupt unterscheiden?
-
GPC schrieb:
Die Ergebnisse variierten bei mehreren Läufen z.T. um ca 0.010 - 0.030, ein paar mal war auch die inline Funktion schneller als das Makro. Und nun... Nichts neues im Westen?
nun kann ich dein "manchmal sind echte inline-Funktionen schneller, manchmal Makros" verstehen. so geringe unterschiede, daß es messfehler sein könnten oder schlechtes alignment von sprunkzielen oder sonstwas, nur kein argument, irgendwo nen makro zu nehmen.
und jox ist als ... enttarnt, da ist ja gar kein argument auch nur andeutungsweise stichhaltig, warum er makros nimmt.
und eingemischt hab ich mich, weil ihr beide empfohlen habt, unter umständen makros zu nehmen, wo inline-funktionen auch gehen. wir wollen ja nicht, daß das nachher einer glaubt und als verteidigung sagt "das hab ich bei c-plusplus.net so gelernt".
-
hellihjb schrieb:
in wie fern sollten sich die kompilate von makro und inline-funktion (die auch tatsaechlich ge-inline't wird) ueberhaupt unterscheiden?
... im Prinzip kaum, aber man beachte z.B.:
max(++a,++b)
führt als Makro und als Inline-Funktion zu unterschiedlichen Ergebnissen
Ob da wohl unterschiedlicher Code generiert wird?Aber das wissen wir ja alle....
-
volkard schrieb:
und jox ist als ... enttarnt
Na, na, wir wollen hier doch nicht persönlich werden oder uns im Ton vergreifen. Das gehört hier einfach nicht hin.
Ich seh schon, selbst gemerkt und entfernt.
Akzeptiert, und als Zitat "... damit ist die Sache für mich erledigt".
-
volkard schrieb:
GPC schrieb:
Die Ergebnisse variierten bei mehreren Läufen z.T. um ca 0.010 - 0.030, ein paar mal war auch die inline Funktion schneller als das Makro. Und nun... Nichts neues im Westen?
nun kann ich dein "manchmal sind echte inline-Funktionen schneller, manchmal Makros" verstehen. so geringe unterschiede, daß es messfehler sein könnten oder schlechtes alignment von sprunkzielen oder sonstwas,
ach so, du dachtest ich meine richtige Performanceunterschiede zw. Makros und Inline-Funktionen? Da haben wir wohl zu Beginn aneinandervorbeigeredet. Sorry, hätte mich deutlicher ausdrücken sollen
nur kein argument, irgendwo nen makro zu nehmen.
ACK.
und eingemischt hab ich mich, weil ihr beide empfohlen habt, unter umständen makros zu nehmen, wo inline-funktionen auch gehen. wir wollen ja nicht, daß das nachher einer glaubt und als verteidigung sagt "das hab ich bei c-plusplus.net so gelernt".
^^ Um meinen Standpunkt noch mal deutlich zu machen: inline-Funktionen sind imho Makros vorzuziehen!
GPC