Geschwindigkeit einiger Operationen
-
Das geht auch mit den Referenzen:
Da ist auch die Referenz um ca. ein fünftel schneller;
int addVal(int a, int b) { return (a + b); } int addRef(int& a, int& b { return (a + b); }
-
dann vertausch mal oben und unten. dann ist schon wieder das untere schneller. oder?
zum messen solltest du alle optimierungen anmachen und von hunderten von messungen diejenige mit der kleinsten zeit nehmen.
-
hab ich gerade gemacht. Kein Unterschied.
Auch mit den Optimierungen ein (da sind natürlich jetzt wahrscheinlich keine MMX, SSE-Optimierungen drin).
Messungen hab ich so an die zehn gemacht, aber das Ergebnis ist immer ungefähr das gleiche.
-
volkard schrieb:
und von hunderten von messungen diejenige mit der kleinsten zeit nehmen.
Wäre es nicht sinnvoller, den Mittelwert zu nehmen? Ausreisser gibt es immer, und die sind nicht praxisrelevant.
Ich habe die Messung wegen < und == übrigens auch gemacht, mit anderen Zeitmessungs-Funktionen. Beides war ziemlich genau gleich schnell. Gleiches gilt für Referenz und Kopie. Wahrscheinlich kann das der Compiler gut optimieren.
Senfer schrieb:
Das mit den Referenzen mach ich selber gerade. Hab ich aber von hier:
http://www.mathematik.uni-marburg.de/~cpp/referenzen/
Kapitel Referenzübergabe. Der Funktionsaufruf kostet natürlich Zeit, da hast Du recht.Nicht der Aufruf, die Dereferenzierung. Und schau mal, was dort steht:
3. Da nichts kopiert und vor allem kein Konstruktor aufgerufen werden muß, entsteht ein Laufzeitvorteil.
Bei Klassentypen lohnt sich eine Const-Referenz-Übergabe schon von der Performance her. Da skalare Typen aber so klein sind und keine Konstruktoren haben, lohnt es sich nicht wirklich.
-
Die Messungen sollten richtig sein, der TickCount kann laut
MSDN:
[url]
http://msdn.microsoft.com/en-us/library/ms724408(VS.85).aspx
[/url]ca. 47 Tage lang laufen, ohne dass er auf Null zurück springt.
Aber mit dem an den Kern binden hast Du natürlich recht. Ich glaube jedoch wirklich, die Messungen einigermaßen ok sind, habe es jetzt noch mal auf 1 Mrd. erhöht und noch mal ca. 20 Messungen mit vertauschen gemacht.
Die Referenzen und der Vergleich auf 0 ist immer noch ca. 20% schneller.
Aber ich lass mich gern vom Gegenteil überzeugen.
-
Ok, wahrscheinlich hast Du recht und Du kennst Dich auch besser mit den Optimierungsfunktionalitäten der Compiler aus. Das mit C++ ist schon ne Weile her bei mir. Ich hab erst vor ein paar Wochen wieder angefangen.
-
Nexus schrieb:
volkard schrieb:
und von hunderten von messungen diejenige mit der kleinsten zeit nehmen.
Wäre es nicht sinnvoller, den Mittelwert zu nehmen? Ausreisser gibt es immer, und die sind nicht praxisrelevant.
die ausreißer liegen aber absolut nicht am eigenen code. die kommen, weil andere prozesse die cpu bekommen, die kommen, weil code eingelagert werden muss, die kommen weil der prozessorcache noch leer war, man hat den eindruck, die kämen einfach so.
mit einfach einer langen schleife und dem mittelwert fällst du ganz super auf die effekte rein, daß der rechner schneller ist, wenn er vorher ein paar sekunden ruhen durfte, daß die zweite schleife im selben prog normalerweise gewinnt (vielleicht weil keine nachwirkungen des einlagerns mehr laufen und freispeicher schon im pool ist, oder weil die anderen programme (der explorer, die ide) endlich ausgezappelt haben).
kleine sachen wie x+=(i==0) versus x+=(i<=0) kann man zuverlässig auf den takt genau ausmessen, indem man kurzlaufende schleifen nimmt (so, daß es öfters mal vorkommt, daß ein ganzer durchlauf ohne prozesswechsel klappt) und von vielen versuchen den schnellsten nimmt.andere sachen müssen anders gemessen werden, für eine new-funktion lieber mittelwert.
-
Da hast Du recht. Mit dem Mittelwert stimme ich mit Dir überein. Aber über längere Zeiträume sollten die Interrupts des Systems doch eigentlich auch rausgemittelt werden oder?
-
Ich programmier mir jetzt mal was mit 1 000 000 Messungen, die über schleifen von einmal 100 und einmal 1 000 000 000 Durchläufen gehen. Sollte etwas länger dauern, aber dann sollten sich die Interrupts eigentlich statistisch raus mitteln, wenn ich den Mittelwert bilde (und auch nichts anderes an dem Rechner mache).
-
Senfer schrieb:
Da hast Du recht. Mit dem Mittelwert stimme ich mit Dir überein. Aber über längere Zeiträume sollten die Interrupts des Systems doch eigentlich auch rausgemittelt werden oder?
nicht wirklich. ich messe 10 minuten lang variante a und alles geht gut. dann messe ich 10 minuten lang variante b und dabei kommt
- ein automatisches update übers netzwerk rein
- eine dos-attacke auch übers netz
- der indizierungsdienst indiziert was
- der prozessor wird heiß und wird runtergetaktet
- idle-defrag geht an
- teile der ide werden ausgelagert
mist. das ist einfach zu viel mist, daß man da in einigermaßen überschaubaren zeiten etwas herausmitteln könnte. mit meiner methode haste bei kleinen tests über ca 20 sek vier oder fünf gleichbleibende stellen bei der zeitmessung, mit einfachem mitteln nur eine oder zwei.
-
Stimmt, vielleicht sollte ich es aufgeben. Ich frag am Montag noch mal den Guru, warum das mit dem Vergleich so ist, dann geb ich Dir bescheid, ok?
-
Senfer schrieb:
Stimmt, vielleicht sollte ich es aufgeben. Ich frag am Montag noch mal den Guru, warum das mit dem Vergleich so ist, dann geb ich Dir bescheid, ok?
gerne.
vielleicht weiß ich, was er meint.
erstmal machen wir eine zeitreise ins jahr damals und zum 8086.
um x>y (unsigned) zu prüfen, muß ich ans carray-flag nach einer subtraktion kommen. prinzipiell mit SUB.
besser ein CMP x,y und das ist intern ein SUB x,y, nur daß das ergebnis nicht geschrieben wird, es werden nur die flags gesetzt.
wenn ich gegen 0 vergleiche, dann eben CMP x,0.mal die zeiten nehmen von http://www.tu-chemnitz.de/informatik/RA/lehre/mop/praktika/AsmBefehle8086.pdf
sub AX,0 brauchte 4 takte
und alle flags werden berechnet, auch das gewünschte carry-flag.aber für (x=0) reicht es mir ja schon, ans zero-flag zu kommen. dazu muß ich den wert bloß einmal durch die ALU schicken. das geht zum beispielschon mit
AND AX,AX
braucht nur 3 takte. also kann (x=0) zu schnellerem code gemacht werden als (x>0).ich erwarte aber, daß halbwegs moderne compiler das auch selber wissen und für mich erledigen.
-
im endeffekt ist vollkommen egal was schneller ist

BTW: ein guter compiler wird bei unsigned typen und bool den gleichen code erstellen...
-
Senfer schrieb:
Hab aber gerade einen Performancetest gemacht:
Wenn Du Windows hast und Deine Entwicklungsumgebung das unterstützt, kannst Du das auch kurz machen:
#include <cstdlib> #include <iosteam> #include <windows.h> using namespace std; int main(int argc, char *argv[]) { int iGrenze = 100000000; DWORD dwStart1 = 0; DWORD dwStart2 = 0; DWORD dwStop1 = 0; DWORD dwStop2 = 0; bool x = false; dwStart1 = GetTickCount(); for(int i = 0; i < iGrenze; i++) x = (i > 0); dwStop1 = GetTickCount(); dwStart2 = GetTickCount(); for(int i = 0; i < iGrenze; i++) x = (i == 0); dwStop2 = GetTickCount(); cout << "Test 1: " << dwStop1 - dwStart1 << endl; cout << "Test 1: " << dwStop2 - dwStart2 << endl; }Das kannst Du ein paar mal machen, kommt aber immer raus, dass das untere um ca. ein fünftel schneller ist.
(hoffe, ich hab den Code richtig abgetippt, war nämlich auf dem anderen Rechner
)Bitte mach den Debugmodus aus.

Da kannst du garnix messen, weil dir ein vernünftiger Compiler das mit x alles weg optimiert, weil du es garnicht verwendest und deine iGrenze konstant ist.Das ist wieder mal so ein premature microoptimierungs gescheiße hier.

-
Ihr seid so schlecht schrieb:
Das ist wieder mal so ein premature microoptimierungs gescheiße hier.

ach, das wort "premature" lese ich hier oft. ist das nicht seltsam?
die hardware kennenzulernen und zu lernen, was ein compiler so kann, das ist doch etwas im allerhöchsten maße positives.
-
volkard schrieb:
ach, das wort "premature" lese ich hier oft. ist das nicht seltsam?
Ne, nicht seltsam, ganz normal, dass das hier immer wieder gemacht wird, bei so vielen Anfängern
die hardware kennenzulernen und zu lernen, was ein compiler so kann, das ist doch etwas im allerhöchsten maße positives.
ja, aber wieso meinen dann immer noch so viele, dass sie es besser können als der Compiler? Wartbaren und leicht zu erweiternden Code zu schreiben ist so gut wie immer wichtiger, als solcher kleinscheiß, wie < vs. ==...
-
Ihr seid so schlecht schr schrieb:
ja, aber wieso meinen dann immer noch so viele, dass sie es besser können als der Compiler?
weil ihnen keiner zeigt, wie geil heute die compiler sind, sondern im gegenteil: wenn sie ein wenig forschen wollen, sofort mit der premature keule eins übergezogen bekommen.
Wartbaren und leicht zu erweiternden Code zu schreiben ist so gut wie immer wichtiger, als solcher kleinscheiß, wie < vs. ==...
und erzeugt sogar schnelleren code, denn oft kann man noch sehr spät seinen algorithmus tunen, zum beispiel durch auswahl einer besser angepaßten datenstruktur oder durch herauswerfen von ein paar sonderfällen. und das geht um so besser, je einfacher und klarer der code ist. aber welcher kleinscheiß ist gut und welcher böse? die doppelt verkettete liste zu tunen, daß sie zum ring wird, dabei das root-element als leeres pseudo-existent zu halten, und ruck zuck in der gesamten klasse ganz ohne fallunterscheidung auszukommen, ist was tolles. auf der jagt nach einem kleinen harmlosen if, om das loszuwerden, nur weils manchmal 13 strafzyklen kostet, eröffnet sich plötzlich das zaubertal der verketteten ringe. wie gut, daß ich gesucht habe und mich nicht davon abhalten ließ.

-
volkard schrieb:
aber welcher kleinscheiß ist gut und welcher böse?
Scheißegal, das muss man nicht wissen. Wenn das Programm fertig ist und es sich rausstellt, dass es irgendwo zu langsam ist, nimmt man einen Profiler und findet damit die richtig große Scheiße im Code und die wird dann aufgeräumt und das geht fast immer indem man irgend ein O(n) in O(log(n)) oder ähnliches umbaut. Wenn du vorher optimierst, dass sich ein Dialog nicht in 116ms sondern in 83ms öffnet, dann interessiert das keinen. Wenn aber ein User oder Tester kommt und sagt, dass er nicht immer eine Minute warten will bis die Datei geöffnet ist und du machst daraus 20 Sekunden, dann bringt das was. Vor einigen Jahren fand ich so kleinkram auch noch wichtig, bis ich dann irgendwann richtig produktiv eingesetzen Code optimiert hab. Es ehißt zwar, kleinvieh macht auch Mist, aber wenn der Compiler bereits den Mist weg räum oder wenn er sowieso wo liegt wo es keinen stört, dann ist es premature optimization. Aber ob was stört, sieht man meistens erst wenn das Programm fertig ist. Das bedeutet jetzt nicht, dass man nicht gleich nen besseren Algorithmus verwenden kann, wenn man ihn kennt, aber < oder == ist kein Algorithmus, sondern Kleinscheiß.
-
was genau hast du an meinem letzten posting nicht verstanden?
-
Ihr seid so schlecht schrieb:
volkard schrieb:
aber welcher kleinscheiß ist gut und welcher böse?
Scheißegal, das muss man nicht wissen.
Nicht alles was man tut ist zwangslaeufig produktiv auf ein fertiges Produkt abgeziehlt.
In der Tat ist es so, dass das ja Codemonkeys von Programmierern unterscheidet. Wenn du immer nur geziehlt das Programm fertig bekommen willst, dann lernst du dabei einfach nichts und entwickelst dich nicht weiter.
Deshalb ist es genauso wichtig diese Spielereien zu machen die nichts bringen ausser eben Erkenntnis, wie Meyers, Sutter, etc. zu lesen. Sonst entwickelt man sich ja nicht weiter. Viele Leute wollen das zwar nicht, aber das merkt man dann auch wenn man mit solchen Leuten dann zusammen arbeiten muss.
Ein gesundes mass an Neugier ist essentiell wenn man ein guter Programmierer werden will (das fuehrt dann ja auch dazu dass man ueber den Tellerand sieht und andere Sprachen mit anderen Konzepten lernt).