Autor Beitrag
Hochhaus
ontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic starofftopic star
Beiträge: 662
Erhaltene Danke: 8

Windows 7
Delphi XE2
BeitragVerfasst: Di 17.12.13 10: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 user profile iconNarses: Topic aus Sonstiges (Delphi) verschoben am Di 17.12.2013 um 10:22
baumina
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 305
Erhaltene Danke: 61

Win 7
Delphi 10.2 Tokyo Enterprise
BeitragVerfasst: Di 17.12.13 10: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 Threadstarter
ontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic starofftopic star
Beiträge: 662
Erhaltene Danke: 8

Windows 7
Delphi XE2
BeitragVerfasst: Di 17.12.13 11:01 
user profile iconbaumina hat folgendes geschrieben Zum zitierten Posting springen:
- 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 305
Erhaltene Danke: 61

Win 7
Delphi 10.2 Tokyo Enterprise
BeitragVerfasst: 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.

Für diesen Beitrag haben gedankt: Hochhaus
jfheins
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 918
Erhaltene Danke: 158

Win 10
VS 2013, VS2015
BeitragVerfasst: 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.

Für diesen Beitrag haben gedankt: Hochhaus
Hochhaus Threadstarter
ontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic starofftopic star
Beiträge: 662
Erhaltene Danke: 8

Windows 7
Delphi XE2
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 918
Erhaltene Danke: 158

Win 10
VS 2013, VS2015
BeitragVerfasst: 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)

Für diesen Beitrag haben gedankt: Hochhaus
Martok
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 3661
Erhaltene Danke: 604

Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
BeitragVerfasst: Di 17.12.13 14:43 
Es gibt keinen magischen Mach-das-Programm-schnell-Schalter.

user profile iconHochhaus hat folgendes geschrieben Zum zitierten Posting springen:
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 (user profile iconHorst_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 (user profile iconjaenicke 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.

_________________
"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 Threadstarter
ontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic starofftopic star
Beiträge: 662
Erhaltene Danke: 8

Windows 7
Delphi XE2
BeitragVerfasst: Di 17.12.13 16:43 
Hallo !

hier die zeitkritische Schleife in meinem Proggi:

ausblenden volle Höhe 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 = 0Then Begin
       ZeitY := GetTickCount - ZeitX;
       ZeitReal := ZeitY / 1000.0;
       ZeitR.Text := FloatToStrF(ZeitReal, ffFixed, 63) + ' sec.';
       Str(I, AnzStel);
       StelleX.Text := AnzStel;
     End;

     Stop.Enabled := True;
     Clear.Enabled := False;
     {* Ausmultiplizieren in Vektorschreibweise *}

     For W := -1 To I Do Begin
         Inc(K[W + I], 2 * A[W]);
     End;  {* For *}

     K[2 * I] := K[2 * I] + 1;


     {* Stellenübertrag *}

     For W := 2 * I DownTo -1 Do Begin
         Z := 0;
         While (K[W] > 9Do Begin
           Dec(K[W], 10);
           Inc(Z);
         End;
         Inc(K[W - 1], Z);
     End;  {* For *}


     {* 10'000 fache Eingabe und 10'000 fache Multiplikationssumme *}

     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);


     {* Grösse der Eingabe erreicht / Oder letzte Ziffer = 9 *}

     If (Summe1 >= Summe2) Or (A[I] = 9Then Begin
        Inc(I);
        For W := -2 To 2 * I Do Begin
            K[W] := S[W];
        End{* For *}
     End {* If (Summe1 ... Then *}


     {* Sonst: Letzte Ziffer um 1 erhöhen *}

     Else Begin
        Inc(A[I]);
        For W := -2 To 2 * I Do Begin
            S[W] := K[W];
        End{* For *}

     End;  {* IF (Summe1 ... Else *}
  End;  {* While I <= N *}


In der Beilage ist das gesamte Proggi als Zip-Datei ...!


Grüsse


Hochhaus
Einloggen, um Attachments anzusehen!
Gammatester
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 328
Erhaltene Danke: 101



BeitragVerfasst: 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?

Für diesen Beitrag haben gedankt: Hochhaus
Hochhaus Threadstarter
ontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic starofftopic star
Beiträge: 662
Erhaltene Danke: 8

Windows 7
Delphi XE2
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Di 17.12.13 22:54 
Auf den ersten Blick würde ich vermuten, dass die Arrayzugriffe erheblich Potential zur Optimierung bieten. ;-)
ausblenden Delphi-Quelltext
1:
2:
3:
     For W := -1 To I Do Begin
         Inc(K[W + I], 2 * A[W]);
     End;  {* For *}
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:
ausblenden 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] = 9Then Begin
        Inc(I);
        For W := -2 To 2 * I Do Begin
            K[W] := S[W];
        End{* For *}
     End {* If (Summe1 ... Then *}


     {* Sonst: Letzte Ziffer um 1 erhöhen *}

     Else Begin
        Inc(A[I]);
        For W := -2 To 2 * I Do Begin
            S[W] := K[W];
        End{* For *}

     End;  {* IF (Summe1 ... Else *}
gegen dies:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
     if (Summe1 >= Summe2) or (A[I] = 9then
     begin
        Inc(I);
        CopyMemory(@K[-2], @S[-2], 2 * I + 3);
     end {* If (Summe1 ... Then *}
     {* Sonst: Letzte Ziffer um 1 erhöhen *}
     else
     begin
        Inc(A[I]);
        CopyMemory(@S[-2], @K[-2], 2 * I + 3);
     end;  {* IF (Summe1 ... Else *}
ist das ganze bei 10000 Nachkommastellen von 7,6 Sekunden auf 5,6 runter.

Für diesen Beitrag haben gedankt: Hochhaus
jfheins
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 918
Erhaltene Danke: 158

Win 10
VS 2013, VS2015
BeitragVerfasst: 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).

Für diesen Beitrag haben gedankt: Hochhaus
Hochhaus Threadstarter
ontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic starofftopic star
Beiträge: 662
Erhaltene Danke: 8

Windows 7
Delphi XE2
BeitragVerfasst: Mi 18.12.13 07:24 
Vielen Dank für die Hilfe !!

Hochhaus
Hochhaus Threadstarter
ontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic starofftopic star
Beiträge: 662
Erhaltene Danke: 8

Windows 7
Delphi XE2
BeitragVerfasst: Do 19.12.13 16:00 
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:

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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 173
Erhaltene Danke: 43



BeitragVerfasst: 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.

Für diesen Beitrag haben gedankt: Hochhaus
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Fr 20.12.13 14: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 Threadstarter
ontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic starofftopic star
Beiträge: 662
Erhaltene Danke: 8

Windows 7
Delphi XE2
BeitragVerfasst: Fr 20.12.13 15:07 
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
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
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 486
Erhaltene Danke: 99

Win7, Win81, Win10
Tokyo, VS2017
BeitragVerfasst: 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.

_________________
Lies, was da steht. Denk dann drüber nach. Dann erst fragen.
Hochhaus Threadstarter
ontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic starofftopic star
Beiträge: 662
Erhaltene Danke: 8

Windows 7
Delphi XE2
BeitragVerfasst: Sa 21.12.13 02:17 
user profile iconOlafSt hat folgendes geschrieben Zum zitierten Posting springen:
Es ist doch auch möglich, das der Compiler "Schuld" daran ist.


Ja, das vermute ich.

Hochhaus