Autor |
Beitrag |
Hochhaus
Beiträge: 662
Erhaltene Danke: 8
Windows 7
Delphi XE2
|
Verfasst: Di 17.12.13 09:49
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
Beiträge: 305
Erhaltene Danke: 61
Win 7
Delphi 10.2 Tokyo Enterprise
|
Verfasst: Di 17.12.13 09:59
- Bereichs- und Überlaufprüfung : FALSE
- Optimierung : TRUE
- Vollständige Boolesche Auswertung : FALSE (außer du brauchst das unbedingt)
Für diesen Beitrag haben gedankt: Hochhaus
|
|
Hochhaus
Beiträge: 662
Erhaltene Danke: 8
Windows 7
Delphi XE2
|
Verfasst: Di 17.12.13 10: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
Beiträge: 305
Erhaltene Danke: 61
Win 7
Delphi 10.2 Tokyo Enterprise
|
Verfasst: Di 17.12.13 10: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.
Für diesen Beitrag haben gedankt: Hochhaus
|
|
jfheins
Beiträge: 918
Erhaltene Danke: 158
Win 10
VS 2013, VS2015
|
Verfasst: Di 17.12.13 11:14
Ich bin mal gespannt ob das Programm damit merklich/messbar schneller wird. Falls nicht bietet es sich an, einen Profiler zu benutzen.
Für diesen Beitrag haben gedankt: Hochhaus
|
|
Hochhaus
Beiträge: 662
Erhaltene Danke: 8
Windows 7
Delphi XE2
|
Verfasst: Di 17.12.13 11: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
Beiträge: 918
Erhaltene Danke: 158
Win 10
VS 2013, VS2015
|
Verfasst: Di 17.12.13 13: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)
Für diesen Beitrag haben gedankt: Hochhaus
|
|
Martok
Beiträge: 3661
Erhaltene Danke: 604
Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
|
Verfasst: Di 17.12.13 13: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
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
HP-Optimierung ist ein Handwerk. Intel behauptet gerne anderes, aber auch ihr Compiler vektorisiert nur das, was vorher schon vektorisierbar geschrieben wurde.
_________________ "The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
Für diesen Beitrag haben gedankt: Hochhaus
|
|
Hochhaus
Beiträge: 662
Erhaltene Danke: 8
Windows 7
Delphi XE2
|
Verfasst: Di 17.12.13 15:43
Hallo !
hier die zeitkritische Schleife in meinem Proggi:
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
Einloggen, um Attachments anzusehen!
|
|
Gammatester
Beiträge: 328
Erhaltene Danke: 101
|
Verfasst: Di 17.12.13 16: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?
Für diesen Beitrag haben gedankt: Hochhaus
|
|
Hochhaus
Beiträge: 662
Erhaltene Danke: 8
Windows 7
Delphi XE2
|
Verfasst: Di 17.12.13 16: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
Beiträge: 19272
Erhaltene Danke: 1740
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Di 17.12.13 21: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.
Für diesen Beitrag haben gedankt: Hochhaus
|
|
jfheins
Beiträge: 918
Erhaltene Danke: 158
Win 10
VS 2013, VS2015
|
Verfasst: Di 17.12.13 22: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).
Für diesen Beitrag haben gedankt: Hochhaus
|
|
Hochhaus
Beiträge: 662
Erhaltene Danke: 8
Windows 7
Delphi XE2
|
Verfasst: Mi 18.12.13 06:24
Vielen Dank für die Hilfe !!
Hochhaus
|
|
Hochhaus
Beiträge: 662
Erhaltene Danke: 8
Windows 7
Delphi XE2
|
Verfasst: Do 19.12.13 15: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
Beiträge: 173
Erhaltene Danke: 43
|
Verfasst: Fr 20.12.13 11: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.
Für diesen Beitrag haben gedankt: Hochhaus
|
|
jaenicke
Beiträge: 19272
Erhaltene Danke: 1740
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Fr 20.12.13 13:28
Das ist hier aber trotzdem nicht der Grund warum es so lange dauert. Das ändert kaum etwas.
Für diesen Beitrag haben gedankt: Hochhaus
|
|
Hochhaus
Beiträge: 662
Erhaltene Danke: 8
Windows 7
Delphi XE2
|
Verfasst: Fr 20.12.13 14: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
Beiträge: 486
Erhaltene Danke: 99
Win7, Win81, Win10
Tokyo, VS2017
|
Verfasst: Sa 21.12.13 00: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.
_________________ Lies, was da steht. Denk dann drüber nach. Dann erst fragen.
|
|
Hochhaus
Beiträge: 662
Erhaltene Danke: 8
Windows 7
Delphi XE2
|
Verfasst: Sa 21.12.13 01:17
OlafSt hat folgendes geschrieben : | Es ist doch auch möglich, das der Compiler "Schuld" daran ist. |
Ja, das vermute ich.
Hochhaus
|
|