Was ist am schnellste?
-
#include <iostream> #include <windows.h> using namespace std; int main() { LARGE_INTEGER start_ticks, ende_ticks, frequenz; double tick_diff = 0; start_ticks.QuadPart = 0; ende_ticks.QuadPart = 0; nochmal: cin.get(); QueryPerformanceCounter(&start_ticks); QueryPerformanceFrequency(&frequenz); for (int i = 0; i < 80000000; ++i) { // ... hier deinen code testen ob er lahm oder schnell ist ... } // ... Ende der Geschwindigkeits-Tests! QueryPerformanceCounter(&ende_ticks); tick_diff = ((double) ende_ticks.QuadPart - (double) start_ticks.QuadPart) / frequenz.QuadPart; cout << tick_diff << endl; goto nochmal;hinweis: nur auf release testen. debug gibt ganz andere ergebnisse
-
nochmal: // ... goto nochmal;Wieso das? Hier könnte man wirklich ohne Probleme eine Schleife verwenden.
-
Nexus schrieb:
nochmal: // ... goto nochmal;Wieso das? Hier könnte man wirklich ohne Probleme eine Schleife verwenden.
Endlosschleife, ohne goto - sehr schön!

-
Alter Schwede schrieb:
Endlosschleife, ohne goto - sehr schön!

Normalerweise hat die Schleife eine Abbruchbedingung.
Und ja, eine Endlosschleife ist immer noch besser als
goto, da weiss man wenigstens, was passiert. Man hat einen separaten Block mit eigenem Gültigkeitsbereich und kann das Verhalten des Programms überblicken. Es gibt schon wenige berechtigte Anwendungsbereiche fürgoto, aber sicher nicht in Situationen, in denen eine Schleife nur Vorteile hat.
-
@Nexus
goto gehoert zur Sprache - und es bereichert sie**.**
-
for (;;) { /*...*/ }ist viel hübscher als goto und labels...
-
Alter Schwede schrieb:
goto gehoert zur Sprache - und es bereichert sie**.**

Natürlich. Nebenbei gehören sowohl Casts von konstanten Klasseninstanzen zu Non-Const-Referenzen auf
double-Arrays als auch Zeiger mit siebenfacher Indirektion ebenfalls zur Sprache. Ich hoffe, du siehst den Punkt.
-
xBlackKnightx schrieb:
#include <iostream> #include <windows.h> using namespace std; int main() { LARGE_INTEGER start_ticks, ende_ticks, frequenz; double tick_diff = 0; start_ticks.QuadPart = 0; ende_ticks.QuadPart = 0; nochmal: cin.get(); QueryPerformanceCounter(&start_ticks); QueryPerformanceFrequency(&frequenz); for (int i = 0; i < 80000000; ++i) { // ... hier deinen code testen ob er lahm oder schnell ist ... } // ... Ende der Geschwindigkeits-Tests! QueryPerformanceCounter(&ende_ticks); tick_diff = ((double) ende_ticks.QuadPart - (double) start_ticks.QuadPart) / frequenz.QuadPart; cout << tick_diff << endl; goto nochmal;hinweis: nur auf release testen. debug gibt ganz andere ergebnisse
Damit misst du schnell Mist.
Der "hier deinen code testen" Bereich muss nämlich so ausgelegt sein, dass der Compiler ihn nicht wegoptimieren kann (ein paar Berechnungen, deren Ergebnis dann nirgends verwendet wird, sind nämlich im Release ganz schnell einfach nichtmehr da). Und auch keine Optimierungen vornehmen, die unter realen Einsatzbedingungen nichtmehr möglich wären. Aber auch keine "nicht-wegoptimier" Hilfskonstrukte enthält, die zuviel Optimierungen verhindern, oder einfach selbst zuviel Overhead machen.
Profilen ist eben nicht so einfach wie klein Erna sich das vorstellt.
Zum "richtig" Profilen muss man das fertige Programm profilen. Oder zumindest ausreichend grosse Programmabschnitte. Und das geht oft nur vernünftig ... mit einem Profiler

-
hustbaer schrieb:
Zum "richtig" Profilen muss man das fertige Programm profilen. Oder zumindest ausreichend grosse Programmabschnitte. Und das geht oft nur vernünftig ... mit einem Profiler

Und sag jetzt blos nicht alles andere wäre prem..opt..., sonst löscht dich volkard aus.
-
na gut das
"for (;;)"wird übernommen!
hustbaer schrieb:
Damit misst du schnell Mist.
Der "hier deinen code testen" Bereich muss nämlich so ausgelegt sein, dass der Compiler ihn nicht wegoptimieren kann (ein paar Berechnungen, deren Ergebnis dann nirgends verwendet wird, sind nämlich im Release ganz schnell einfach nichtmehr da). Und auch keine Optimierungen vornehmen, die unter realen Einsatzbedingungen nichtmehr möglich wären. Aber auch keine "nicht-wegoptimier" Hilfskonstrukte enthält, die zuviel Optimierungen verhindern, oder einfach selbst zuviel Overhead machen.
Profilen ist eben nicht so einfach wie klein Erna sich das vorstellt.
Zum "richtig" Profilen muss man das fertige Programm profilen. Oder zumindest ausreichend grosse Programmabschnitte. Und das geht oft nur vernünftig ... mit einem Profiler

naja das mag stimmen. Ich weiss nur nicht wie Compiler das wirklich "optimiert"
wenn ich die 3 hier teste
void strcpy1( char s1[], char s2[]) { int i; for( i = 0; s2[i] != '\0'; ++i) s1[i] = s2[i]; s1[i] = '\0'; } void strcpy2( char *s1, char *s2) { for( ; *s2 != '\0'; ++s1, ++s2) *s1 = *s2; *s1 = '\0'; } void strcpy3( char *s1, char *s2) { while( (*s1++ = *s2++) != '\0' ); }und dann noch ein normales strcpy testen. Ergebnis: strcpy1 geht bei mir am schnellsten. Warum optimiert der Compiler nicht so dass die anderen mindestens genauso schnell sind wie strcpy1 ? Vlt mag das auch von CPU abhängen. Man kann auch da gleich ganze Programmabschnitte in "hier deinen code testen" einfügen oder? Oder verschiedene Funktionen zusammenstellen, die ein Programm braucht, dann immer wieder in einer bestimmten Abfolge testen lassen. Die Abfolge wird durch die externe Datei bestimmt (heisst auf Deutsch ääh z.b. 3D-Weltdaten laden und die Funktionen für Vektoren, Perspektive usw berechnen werden in Geschwindigkeitstest gemessen.) - praktisch wie ein Benchmark, somit kann man sicherstellen, dass da nix optimiert wird, wenn unterschiedliche Weltdaten geladen werden. Aber gut ich gebe zu, ich habe so ein Profiler noch nie ausprobiert.
-
Konnte man sich den optimierten Code nicht nochmal ausgeben lassen? Wenn ja, wie? Würde mich mal interessieren wie der verschiedene Codezeilen zerbröselt.
-
Skalli schrieb:
Konnte man sich den optimierten Code nicht nochmal ausgeben lassen? Wenn ja, wie?
Du kannst dir den Assembler-Code anschauen. Wie, hängt von deinem Compiler ab.
-
xBlackKnightx schrieb:
strcpy1 geht bei mir am schnellsten. Warum optimiert der Compiler nicht so dass die anderen mindestens genauso schnell sind wie strcpy1 ?
ich habe bei verschiedenen messungen mit dem msvc bemerkt, daß er "normale" for-schleifen, also mit for(initialisierung;laufbedingung;weiterschaltumg) mit nur eine laufvariablen udn so, also dem üblichsten typ, daß er da machmal schnelleren code baut.
deswegen ist es keine schlechte idee, beim MSVC die natürliche for-schleife auch so zu belassen.
-
@xBlackKnightx:
Wenn du die Eingabe-Daten aus einem File holst, und die Ergebnisse auch irgendwo wirklich wider ausgibst, dann kann der Compiler zumindest mal nicht die ganze Berechnung wegoptimieren.Allerdings kann er dann u.U. sogar weniger optimieren, als in einem realen Programm.
In vielen Fällen wird sich der Test als sehr praxisnah und zuverlässig erweisen. In anderen Fällen aber nicht.
Ich meine einfach nur: wenn man nich sehr genau weiss, was und wie ein Compiler optimieren kann, und wie der Praxiseinsatz aussehen wird, dann kann man das schwer abschätzen.
Auch gibt es einige Optimierungen, die sich in bestimmten Fällen negativ auf die Laufzeit auswirken. Bei MSVC wäre das z.B. "enable intrinsic functions". Das normale memcpy ist sehr gut für grosse Blöcke optimiert. Dafür hat es mehr "per-call" Overhead als die (viel "dümmere") intrinsic Version. Die intrinsic Version ist daher schneller bei sehr vielen memcpy() Aufrufen mit sehr kleinen Blöcken, aber langsamer bei grossen Blöcken.