Programm auf Geschwindigkeit optimieren
-
Hallo zusammen,
Ich habe ein Simulationsprogramm in C programmiert, das extrem auf Geschwindigkeit optimiert werden soll. Dazu benötige ich Tipps.
Eine Frage ist zum Beispiel:
Ist es für den Rechner schneller (an zu wenig RAM wirds nicht hapern) eine Rechnung, zum Beispiel sin(x) oder artan(x) von ein und der selben Variablen mehrmals durchzuführen, weil ich sie an mehreren Stellen in der Funktion brauche, oder erzeugt man besser eine neue Variable, führt die Rechnung einmal durch und schreibt dann an die entsprechneden Stellen im Code nur diese neue Variable rein. (Ich hoffe das Problem ist deutlich geworden). Bzw. ab wieviel Benutzungen dieser Variable lohnt sie sich zu erzeugen oder lohnt sich besser den Wert einfach direkt an der Stelle mehrfach zu berechnen.Ich kann auch die wichtigste Funktion (relativ kurz) posten, wenn jemand vielleicht noch andere Ratschläge hat.
Vielen Dank schonmal!!!
Philipp.
-
poste mal lieber, wenns kurz ist. dann wirds klarer, was du meinst.
-
Hier ist eine der Funktionen. Da erzeuge ich zum Beispiel die Variable sinThetaStoss und schreibe da den sinus der Größe rein, den ich dann weiter unten zweimal benutze, anstatt an den stellen unten zweimal den sinus zu berechnen und mit die Variable zu sparen.
void IonenStoss(ergebnisstruct* ergebnis, double* v1x, double* v1y, double* v1z, int CEint) { double ux,uy,uz; double v2x,v2y,v2z; double u1; double Theta; double Phi; double ThetaStoss; double PhiStoss; double u2sx, u2sy, u2sz; double u2x,u2y,u2z; double sinThetaStoss; double cosThetaStoss; double cosPhi; double sinPhi; double cosTheta; double sinTheta; geschwindigkeit(&v2x,&v2y,&v2z, ergebnis); ux = (*v1x)-v2x; uy = (*v1y)-v2y; uz = (*v1z)-v2z; u1 = sqrt(sqr(ux)+sqr(uy)+sqr(uz)); Theta = atan2(sqrt(sqr(ux)+sqr(uy)),uz); Phi = atan2(uy,ux); ThetaStoss = asin(sqrt(drand48())); PhiStoss = drand48()*2.0*M_PI; sinThetaStoss = sin(ThetaStoss); cosThetaStoss = cos(ThetaStoss); cosPhi = cos(Phi); sinPhi = sin(Phi); cosTheta = cos(Theta); sinTheta = sin(Theta); u2sx = u1*sinThetaStoss*cos(PhiStoss)*cosThetaStoss; u2sy = u1*sinThetaStoss*sin(PhiStoss)*cosThetaStoss; u2sz = u1*sqr(cosThetaStoss); u2x = cosPhi*(cosTheta*u2sx + sinTheta*u2sz) - sinPhi*u2sy; u2y = sinPhi*(cosTheta*u2sx + sinTheta*u2sz) + cosPhi*u2sy; u2z = -1.0*sinTheta*u2sx + cosTheta*u2sz; //Rücktransformation: if(CEint == 0) //elastischer Stoß { (*v1x) -= u2x; //Rückgabe ist Geschw. von Teilchen 1 (*v1y) -= u2y; (*v1z) -= u2z; } else //CE Stoß { (*v1x) = v2x+u2x; //Rückgabe ist Geschw. von Teilchen 2 (*v1y) = v2y+u2y; (*v1z) = v2z+u2z; } }
-
Verwende dafür am besten ein Profiler-Programm. Es wird dir dann schon sagen, welche Funktionen noch optimiert werden sollen.
Generell kann man natürlich sagen, daß es immer schneller ist, wenn man Werte nur einmal berechnet (solange keine Speicherplatz-Probleme vorliegen, aber selbst dann kann man für große Daten immer noch Caching betreiben).Bei deinem Code sehe ich diesbezüglich nur noch, daß du die Ausdrücke "sinTheta*u2sx" und "cosTheta*u2sx" noch vorher abspeichern könntest.
Aber etwas anderes ist viel mehr zu optimieren:
im Falle von "(CEint == 0) //elastischer Stoß" brauchst du doch gar nicht vorher die Variablen "v2x", "v2y", "v2z" zu berechnen, da du sie ja nicht mehr verwendest.Du solltest bei Optimierungen daher auch schauen, ob du unnötige Berechnungen vornimmst.
-
Hi, danke für den ersten Tipp, habs direkt eingebaut! Der zweite Hinweis... also die v2x usw. benötige ich ja um an ux usw. zu kommen (Zeile 25-27) die muss ich also schon setzen.
-
Am wichtigsten ist wie gesagt ein Profiler, der dir sagt wo dein Programm wirklich Optimiert werden muss. eine Lookup-Table fuer trigonometrische Funktionen lohnt sich ab ca. 100.000 - 1.000.000 Aufrufe pro Sekunde, wenn ueberhaupt - aktuelle CPUs sind relativ fix was sowas angeht, schlimmstenfalls zerschiesst dir so eine LUT nur den Cache und dann verlierst du Geschwindigkeit, anstatt sie zu gewinnen.
Also, Profile erstmal und zeig uns dann die relevanten Codeteile.
-
Anstatt
double ux,uy,uz; ux = (*v1x)-v2x; uy = (*v1y)-v2y; uz = (*v1z)-v2z;
Ist es sinnvoller das so zu machen:
double ux = (*v1x)-v2x; double uy = (*v1y)-v2y; double uz = (*v1z)-v2z;
1. Ist es einfach übersichtlicher
2. Kann der Compiler das u.U. zusäztlich optimieren weil er die Variable gleich mit dem Wert initialisiert.Grundsätzlich MUSST Du aber vorher/nachher immer mittels Profiler vergleichen, sonst läufst Du Gefahr das eine vermeitliche Optimierung tatsächlich den Code langsamer macht.
Gerade das Beispiel der Lookup-Tables ist ein sehr gutes dafür. Moderne Systeme können sehr viele Berechnungen Parallelisieren, wodurch ein "on-the-spot" berrechnen sehr schnell werden kann. Bei einem LOokup-Table läufst Du dagegen ab einer bestimmten Größe Gefahr das der Table nicht mehr komplett in den Cache des Prozessors passt, was zu enormen Performance-Einbussen führen kann.
-
noch 2 sachen
2.0 * M_PI
=> wenn da noch keine fertige Konstante von gibt, kannst du dir selber ein anlegen-1.0*sinTheta
=> ist doch das gleich wie -sinTheta
-
loks schrieb:
2. Kann der Compiler das u.U. zusäztlich optimieren weil er die Variable gleich mit dem Wert initialisiert.
Ich glaube wirklich nicht, dass das den Compiler juckt.
Oberoptimierer schrieb:
2.0 * M_PI
=> wenn da noch keine fertige Konstante von gibt, kannst du dir selber ein anlegenDadurch dass es ein konstanter Ausdruck ist, wird das ohnehin zur Compilezeit ausgewertet.
Oberoptimierer schrieb:
-1.0*sinTheta
=> ist doch das gleich wie -sinThetaDürft für die Performance nichts ausmachen.