Entwickler-Ecke
Programmierwerkzeuge - Compilerschalter ! Programm beschleunigen ?
Hochhaus - Di 17.12.13 10:49
Titel: Compilerschalter ! Programm beschleunigen ?
Hallo allerseits !
Ich habe eine mathematische Anwendung programmiert. Nun meine Frage: Mit welchen Compilerschaltern kann ich bewirken, dass mein Programm schneller ausgeführt wird ?
Danke im Voraus für jede Antwort !
Hochhaus
Moderiert von
Narses: Topic aus Sonstiges (Delphi) verschoben am Di 17.12.2013 um 10:22
baumina - Di 17.12.13 10:59
- Bereichs- und Überlaufprüfung : FALSE
- Optimierung : TRUE
- Vollständige Boolesche Auswertung : FALSE (außer du brauchst das unbedingt)
Hochhaus - Di 17.12.13 11:01
baumina hat folgendes geschrieben : |
- Bereichs- und Überlaufprüfung : FALSE
- Optimierung : TRUE
- Vollständige Boolesche Auswertung : FALSE (außer du brauchst das unbedingt) |
Wie lauten diese Schalter ? {$L-} ?
Hochhaus
baumina - Di 17.12.13 11:17
Unter Projekt/Optionen/Compilieren müssten die Schalter genau so heißen, wie ich es geschrieben habe. Zudem gibt's dort die F1-Taste, die einem dazu genaueres sagt.
jfheins - Di 17.12.13 12:14
Ich bin mal gespannt ob das Programm damit merklich/messbar schneller wird. Falls nicht bietet es sich an, einen Profiler zu benutzen.
Hochhaus - Di 17.12.13 12:19
Es ist nicht schneller geworden, sondern ziemlich genau gleich geblieben ...
Hochhaus
P.S. Mit einer älteren Delphi-Version (6 PE) ist es aber deutlich schneller.
jfheins - Di 17.12.13 14:13
In dem Fall wie gesagt profilen und vielleicht mal den kritischen Code hier posten. (Welcher Code kritisch ist, bekommt man ja gerade mit einem Profiler heraus)
Martok - Di 17.12.13 14:43
Es gibt keinen magischen Mach-das-Programm-schnell-Schalter.
Hochhaus hat folgendes geschrieben : |
Mit einer älteren Delphi-Version (6 PE) ist es aber deutlich schneller. |
Dann ist dein Code noch nicht gut. Sollte es nur noch am mathematischen hängen, sind aktuelle Delphis doch schon ganz ordentlich, jedenfalls ähnlich FPC mit allen Optimierungen (
Horst_H kann da mehr sagen). Kommt noch lange nicht an äquivalenten Code in GCC oder clang ran, aber das wird dieses Jahrzehnt vielleicht noch was. Spätestens wenn Embadingsda keine Lust mehr hat und endlich das verdammte LLVM-Frontend schreibt. Anyway, ich schweife ab :lol:
Ja, wie schon geschrieben, du solltest zuerst deinen Code vermessen und feststellen, wo die Problemstellen sind. Ich benutze da auch immer gerne AMDs CodeAnalyst (heißt jetzt anders, die neuen laufen aber nicht mehr unter XP. Ja, ich habe mir deswegen meine CPU-Definition selbst gebaut.), der gibt dir ohne Instrumentierung schonmal eine Analyse auf Instruktionsebene. Wenn du noch die PDB für dein Programm hast (
jaenicke hatte da neulich was verlinkt), bekommst du sogar direkt Zeilennummern, ansonsten macht sich da die Erfahrung bezahlt, seinen Code auch im Assembler wiederzuerkennen ;)
Dann weißt du, wo das Problem ist, und kannst erstmal prüfen was man schneller machen kann. In den allermeisten Fällen wird das ein Speicherzugriff sein, denn, festhalten - RAM ist langsam. Jedenfalls gegenüber dem L1-Cache der CPU :zwinker:
HP-Optimierung ist ein Handwerk. Intel behauptet gerne anderes, aber auch ihr Compiler vektorisiert nur das, was vorher schon vektorisierbar geschrieben wurde.
Hochhaus - Di 17.12.13 16:43
Hallo !
hier die zeitkritische Schleife in meinem Proggi:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62:
| While (I <= N) And Go Do Begin
Application.ProcessMessages; If (I Mod 100 = 0) Then Begin ZeitY := GetTickCount - ZeitX; ZeitReal := ZeitY / 1000.0; ZeitR.Text := FloatToStrF(ZeitReal, ffFixed, 6, 3) + ' sec.'; Str(I, AnzStel); StelleX.Text := AnzStel; End;
Stop.Enabled := True; Clear.Enabled := False;
For W := -1 To I Do Begin Inc(K[W + I], 2 * A[W]); End;
K[2 * I] := K[2 * I] + 1;
For W := 2 * I DownTo -1 Do Begin Z := 0; While (K[W] > 9) Do Begin Dec(K[W], 10); Inc(Z); End; Inc(K[W - 1], Z); End;
Summe1 := Round(1.0E06 * K[-2] + 1.0E05 * K[-1] + 1.0E04 * K[0] + 1000.0 * K[1]); Summe1 := Summe1 + Round(100.0 * K[2] + 10.0 * K[3] + 1.0 * K[4]); Summe2 := Round(10000.0 * ZAHL);
If (Summe1 >= Summe2) Or (A[I] = 9) Then Begin Inc(I); For W := -2 To 2 * I Do Begin K[W] := S[W]; End; End
Else Begin Inc(A[I]); For W := -2 To 2 * I Do Begin S[W] := K[W]; End;
End; End; |
In der Beilage ist das gesamte Proggi als Zip-Datei ...!
Grüsse
Hochhaus
Gammatester - Di 17.12.13 17:05
Vielleicht ist es ja ein dumme Frage, aber: Was hat Application.ProcessMessages in der zeitkritische Schleife zu suchen, bzw warum packst Du es nicht in den Teil If (I Mod 100 = 0) Then?
Hochhaus - Di 17.12.13 17:22
Weil bei EinKernProzessor-Systemen der Prozessor fast zu 100 % ausgelastet wird - und dann keine Zeit mehr für andere Tasks bleibt. Jedes Mal, wenn eine neue Stelle berechnet wird, steht gegebenfalls auch Zeit für andere Aufgaben an. Sonst "friert der PC ein".
Hochhaus
P.S. Dies ist nicht der Grund für das langsamere Rechnen. Unter Delphi 6 PE war der Code derselbe und das Proggi war schneller. Das Auskommentieren der Zeile bringt praktisch keinen Zeitgewinn.
jaenicke - Di 17.12.13 22:54
Auf den ersten Blick würde ich vermuten, dass die Arrayzugriffe erheblich Potential zur Optimierung bieten. ;-)
Delphi-Quelltext
1: 2: 3:
| For W := -1 To I Do Begin Inc(K[W + I], 2 * A[W]); End; |
Das ist ein extremer Zeitfresser. Du gehst eigentlich den Speicher byteweise durch und erhöhst die einzelnen Bytes. Trotzdem wird jedesmal aus der Summe aus w + i und der Adresse des Arrays per Multiplikation die Adresse neu berechnet. Dass dauert.
// EDIT:
Alleine durch das Austauschen von:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
| If (Summe1 >= Summe2) Or (A[I] = 9) Then Begin Inc(I); For W := -2 To 2 * I Do Begin K[W] := S[W]; End; End
Else Begin Inc(A[I]); For W := -2 To 2 * I Do Begin S[W] := K[W]; End;
End; |
gegen dies:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| if (Summe1 >= Summe2) or (A[I] = 9) then begin Inc(I); CopyMemory(@K[-2], @S[-2], 2 * I + 3); end else begin Inc(A[I]); CopyMemory(@S[-2], @K[-2], 2 * I + 3); end; |
ist das ganze bei 10000 Nachkommastellen von 7,6 Sekunden auf 5,6 runter.
jfheins - Di 17.12.13 23:55
Ich würde das Array auch noch deutlich komprimieren. Momentan werden ja in einzelnen Bytes Dezimalziffern gespeichert. Das heißt die CPU muss sich zuerst die Bytes heraus picken, dann rechnen und braucht schnell wieder neue Daten.
Ein Byte kann ja eigentlich zwei Ziffern halten - Zahlen zwischen 0 und 99. Das hat mir damals auch geholfen, als ich dieses "Basis 26 Programm" im Thread von Mathematiker gemacht habe. Da habe ich sogar int64 genommen.
Die Maßnahme erhöht die Lokalität der Daten (sagt man das so?) so dass mehr relevante Daten in den CPU Cache passen und seltener aus dem RAM nachgeladen wird.
Ach, und parallelisieren kann man da auch ne Menge. Einerseits natürlich die großen Array-Arbeiten, und andererseits auch im kleinen mit SIMD (SSE lässt grüßen).
Hochhaus - Mi 18.12.13 07:24
Vielen Dank für die Hilfe !!
Hochhaus
Hochhaus - Do 19.12.13 16:00
jaenicke hat folgendes geschrieben : |
ist das ganze bei 10000 Nachkommastellen von 7,6 Sekunden auf 5,6 runter. |
Das stimmt unter Delphi XE2 ff. Unter Delphi 6 PE wird offenbar von sich aus optimiert: Dort ist Dein Code genauso schnell wie mein ursprünglicher Code ...!
Hochhaus
Blup - Fr 20.12.13 12:53
ProzessMessages und die Zeitausgabe haben auch auf einem Einkernprozessor nichts in einer zeitkritischen Berechnungsschleife zu suchen.
Für die Berechnung startet man einen extra Thread, um die Verteilung der Rechenzeit kümmert sich das Betriebsystem.
Der Hauptthread kann dann gemütlich ProzessMessages aufrufen und den Bildschirm aktualisieren, ab und zu nach dem Status des Berechnungsthreads schaun und sich ansonsten schlafen legen.
jaenicke - Fr 20.12.13 14:28
Das ist hier aber trotzdem nicht der Grund warum es so lange dauert. Das ändert kaum etwas.
Hochhaus - Fr 20.12.13 15:07
jaenicke hat folgendes geschrieben : |
Das ist hier aber trotzdem nicht der Grund warum es so lange dauert. Das ändert kaum etwas. |
So ist es. Man kann ja den fraglichen Code auch auskommentieren, und dann schauen, ob es schneller geht ! Die Zeitfresser sind eindeutig bei den aufwändigen Array-Rechnungen zu suchen. Da ich eine Brute-Force-Variante des Wurzelziehens wählte, ist der Rechenaufwand groß. Es gäbe sicher bessere, intelligentere Methoden ...
Hochhaus
OlafSt - Sa 21.12.13 01:17
Es ist doch auch möglich, das der Compiler "Schuld" daran ist. Ist es denn so abwegig, das man die Routinen für Arrayzugriffe in laufe der Jahre verändert hat, so das *heute* gebräuchliche Zugriffsmethoden nun schneller sind, diese gezeigte Form aber nun langsamer ? Oder das die in D6 noch handoptimierten Assembler-Routinen wegen der 64-Bit-Compilergeschichten nun durch langsameren Pascalcode ersetzt wurden ? Auch am Optimizer kann herumgebastelt worden sein und und und...
Der Möglichkeiten gibt es viele und ein heutiges Delphi-Compilat ist auch nicht mehr der Weisheit letzter Schluß. Wenn ein C#-Programm, das erst noch JIT übersetzt werden muß, schneller läuft als die Delphi-Version (D2010, mit $O+, $R- und ohne jedwede DebugInfo übersetzt) des gleichen Algorithmus, dann ist da was nicht ganz optimal. Leider hab ich die beiden Progrämmchen nicht mehr, sonst würde ich es demonstrieren.
Hochhaus - Sa 21.12.13 02:17
OlafSt hat folgendes geschrieben : |
Es ist doch auch möglich, das der Compiler "Schuld" daran ist. |
Ja, das vermute ich.
Hochhaus
jaenicke - Sa 21.12.13 11:28
Ein schneller Blick zeigt, dass der generierte Assemblercode nur an einer Stelle abweicht. Es wird eine Variable auf den Stack gelegt statt sie direkt in ein Register zu packen wie es bei Delphi 6 der Fall war. Allerdings wurde bei Delphi 6 esi genutzt, was eigentlich nicht unbedingt für normale Variablen gedacht ist.
Hochhaus - Sa 21.12.13 12:33
jaenicke hat folgendes geschrieben : |
Allerdings wurde bei Delphi 6 esi genutzt |
Eine dumme Frage: Was ist esi ?
Hochhaus
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!