Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Codeoptimierung lieber abschalten (https://www.delphipraxis.net/212195-codeoptimierung-lieber-abschalten.html)

Michael Ebner 3. Jan 2023 10:20

Codeoptimierung lieber abschalten
 
In der Hilfe zu Delphi findet man zur Optimierung die folgenden Aussagen:

Zitat:

Die Direktive $O steuert die Codeoptimierung. Im Status {$O+} führt der Compiler eine Anzahl von Codeoptimierungen durch, indem er beispielsweise Variablen in CPU-Registern platziert, doppelte Teilausdrücke eliminiert und Induktionsvariablen generiert. Im Status {$O-} werden diese Optimierungen nicht durchgeführt.

Außer in bestimmten Testsituationen sollte die Codeoptimierung immer aktiviert sein. Die Optimierungen des Delphi-Compilers führen zu keinerlei Änderungen der Funktionsweise des Programms. Der Compiler führt also keine "unsicheren" Optimierungen durch, die die besondere Aufmerksamkeit des Programmierers erfordern.
Die Aussage, dass die Optimierung des Delphi-Compilers zu keinerlei Änderungen führen, entspricht nicht der Wahrheit. (Konkret Delphi 11, Update 1, kompiliert für WIN 32)

Das Bemerkenswerte daran: Das trat jetzt gerade nicht in einem Fall auf, in dem Timing-Geschichten oder so etwas $DINGE beeinflussen könnten, nicht um Threads, nicht um irgendwelche eingebundenen Bibliotheken, die möglicherweise sehr krude programmiert wurden. Sondern um simple String-Bearbeitung mit den Delphi-Standard-Units.

Von daher meine Empfehlung: Die Codeoptimierung sollte immer deaktiviert sein.

Daniel 3. Jan 2023 11:49

AW: Codeoptimierung lieber abschalten
 
hm. Kann ich in der Pauschalität nicht bestätigen. Man mag dem Delphi-Compiler einiges vorwerfen können, doch die klassischen String-Operationen hat er definitiv gut im Griff.
Kannst Du dies auf ein handhabbares Beispiel reduzieren?

mjustin 3. Jan 2023 12:48

AW: Codeoptimierung lieber abschalten
 
Zitat:

Zitat von Michael Ebner (Beitrag 1516895)
Das Bemerkenswerte daran: Das trat jetzt gerade nicht in einem Fall auf, in dem Timing-Geschichten oder so etwas $DINGE beeinflussen könnten, nicht um Threads, nicht um irgendwelche eingebundenen Bibliotheken, die möglicherweise sehr krude programmiert wurden. Sondern um simple String-Bearbeitung mit den Delphi-Standard-Units.

Kann dies in einem einfachen Code-Beispiel reproduziert werden?

Ich vermute, der Fehler wurde innerhalb einer bestehenden Anwendung beobachtet, die möglicherweise bereits Fehler enthält, die zu einem Seiteneffekt geführt haben.
Das ist in der Praxis leicht möglich, wenn z.B. Speicherkorruption ausgelöst wird, oder Speichermangel besteht.

Sherlock 3. Jan 2023 13:29

AW: Codeoptimierung lieber abschalten
 
FUD.

Sherlock

himitsu 3. Jan 2023 14:14

AW: Codeoptimierung lieber abschalten
 
Ja, es kann natürlich sein, dass die Optimierung irgendwo einen Bug hat
und dann doch dadurch etwas kapput geht.

"vorübergehend" kann man dann die Optimierung global oder besser nur lokal abschalten
und wendet sich dann dann an den Support -> quality.embarcadero.com .

Aber auch kann es ein Bug in Funktionen von Delphi sein, also RTL, VCL, usw. (wäre nicht das erste Mal), wo man dann eben auf andere Funktionen ausweichen könnte.



So lange es keinen halbwegs reproduzierbaren Testfall gibt, oder jemand überhaupt erstmal verrät, was eigentlich das Problem sein soll, kann aber schlecht irgendjemand eine Lösung finden.


Zitat:

Von daher meine Empfehlung: Die Codeoptimierung sollte immer deaktiviert sein.
Grundsätzlich, wie bereits mehrfach gesagt wurde:
NEIN

dummzeuch 3. Jan 2023 14:39

AW: Codeoptimierung lieber abschalten
 
Ich hatte das definitiv schon mehrfach, dass ich für einige Codezeilen die Optimierung ausschalten musste, weil der Compiler sonst fehlerhaften Code erzeugte. Das war reproduzierbar:
  1. Debug-Build ohne Optimierung: Kein Fehler
  2. Release-Build mit Optimierung: Fehler (z.B. Access Violation)
  3. Release-Build mit Optimierung aber an einer bestimmten Stelle ausgeschaltet: Kein Fehler

Solche Fälle hatte ich bei Delphi 2006, 2007, XE2 und Delphi 10.2, wenn auch nicht notwendigerweise an denselben Code-Stellen.

Da ich Delphi 11 so gut wie nicht benutze, kann ich dazu nichts sagen.

Ich habe keine Bugreports geschrieben, da es sich nie um die aktuelle Delphi-Version handelte und meiner Erfahrung nach Bugreports für ältere Versionen einfach ignoriert werden. Keiner prüft, ob der Fehler bei der aktuellen Version vielleicht auch noch auftritt.

freimatz 3. Jan 2023 15:58

AW: Codeoptimierung lieber abschalten
 
Zitat:

Zitat von mjustin (Beitrag 1516906)
Ich vermute, der Fehler wurde innerhalb einer bestehenden Anwendung beobachtet, die möglicherweise bereits Fehler enthält, die zu einem Seiteneffekt geführt haben.
Das ist in der Praxis leicht möglich, wenn z.B. Speicherkorruption ausgelöst wird, oder Speichermangel besteht.

Auch meine Meinung. Zu 99% macht der Compiler keinen Fehler.

jaenicke 3. Jan 2023 16:13

AW: Codeoptimierung lieber abschalten
 
Zitat:

Zitat von dummzeuch (Beitrag 1516926)
Ich hatte das definitiv schon mehrfach, dass ich für einige Codezeilen die Optimierung ausschalten musste, weil der Compiler sonst fehlerhaften Code erzeugte. Das war reproduzierbar:

Solche Fälle habe ich schon mehrfach zugetragen bekommen. In den meisten Fällen zeigte sich in der Analyse des generierten Assemblercodes aber, dass der generierte Code korrekt war, nur wurden z.B. Variablen anders initialisiert. Solche und andere ähnliche Effekte führten dann zu den Problemen. Bevor es eine entsprechende Warnung gab, gab es z.B. auch Fälle, in denen jemand nach dem Ende der Schleife noch auf die Schleifenvariable zugegriffen hatte, diese mit Optimierung aber schon überschrieben war.

Ein paarmal waren es aber echte Compilerprobleme, die aber alle schnell behoben wurden, und auch alle die jeweils aktuelle Version betrafen.

himitsu 3. Jan 2023 16:31

AW: Codeoptimierung lieber abschalten
 
Zitat:

Zitat von jaenicke (Beitrag 1516933)
nach dem Ende der Schleife noch auf die Schleifenvariable zugegriffen hatte

Da hat der Compiler aber auch das Recht jemanden für zu bestrafen. :stupid:

Bei Schleifen ist es schön, dass es nun die Inlinevariablen gibt.
Da kann man danach garnicht erst auf soeine blöde Idee kommen.
Delphi-Quellcode:
for var i: Byte := 0 to 123 do
for var i := 0 to 123 do
for var S in SL do
...
Jo, auch zwinschen Platformen und sogar zwischen Win32 und Win64 gibt es solche Problemchen.
Wo z.B. Result plötzlich "null" ist, wenn man es vergessen hat,
oder eben wo Variablen unterschiedliche "Initial"-Werte haben, jenachdem ob sie auf dem Stack oder in den Registern liegen, bzw. ob sie über die ganze Funktion oder nur den genutzen Zeitraum vorhanden sind usw.



Ebenso, wie bei gemangten Results, wäre es bei Schleifen gut, wenn nach dem Ende der Compiler "vergessen" würde, dass die Variable "eigentlich" schon initialisiert ist.
Dann gäbe es bei nachfolgenden Lesezugriffen auch eine entsprechende Warnung.

Benmik 4. Jan 2023 11:47

AW: Codeoptimierung lieber abschalten
 
Zitat:

Zitat von freimatz (Beitrag 1516932)
Zu 99% macht der Compiler keinen Fehler.

1% Fehlerrate? Das wäre gigantisch.
Ich finde übrigens
Delphi-Quellcode:
{$IFDEF DEBUG}
  {$OPTIMIZATION OFF}
{$ENDIF}
praktisch.

Andreas13 4. Jan 2023 12:12

AW: Codeoptimierung lieber abschalten
 
Zitat:

Zitat von Benmik
Delphi-Quellcode:
{$IFDEF DEBUG}
  {$OPTIMIZATION OFF}
{$ENDIF}

Ist das nicht zu riskant? Wir unterdrücken damit eventuelle Fehler im Debug-Modus, lassen sie jedoch in der endgültigen Release-Version zu... :gruebel:
Grüße, Andreas

dummzeuch 4. Jan 2023 12:55

AW: Codeoptimierung lieber abschalten
 
Zitat:

Zitat von Andreas13 (Beitrag 1516977)
Zitat:

Zitat von Benmik
Delphi-Quellcode:
{$IFDEF DEBUG}
  {$OPTIMIZATION OFF}
{$ENDIF}

Ist das nicht zu riskant? Wir unterdrücken damit eventuelle Fehler im Debug-Modus, lassen sie jedoch in der endgültigen Release-Version zu... :gruebel:

Aber wir haben doch gerade von allen Seiten gehört, dass der Compiler beim Optimieren keine Fehler macht. Selbst mein Hinweis, dass ich solche Fehler schon mehrfach gesehen habe, wurde abgebügelt mit "das Problem war bestimmt in Deinem Code" (nicht dass das falsch wäre, schließlich war es mein Code, der optimiert wurde, ohne ihn wäre kein Fehler aufgetreten, aber es ist nicht hilfreich). :wall:

OK, ernsthaft: Das mache ich auch so, allerdings nicht durch ifdef im Sourcecode sondern durch Setzen der Option in der Release-Config. Das ifdef hat den Nachteil, dass es nicht so simpel ist, die Optimierung einzuschalten, weil man dafür den Sourcecode ändern muss.

Uwe Raabe 4. Jan 2023 13:02

AW: Codeoptimierung lieber abschalten
 
Zitat:

Zitat von dummzeuch (Beitrag 1516979)
Das ifdef hat den Nachteil, dass es nicht so simpel ist, die Optimierung einzuschalten, weil man dafür den Sourcecode ändern muss.

Der gravierendste Nachteil ist aber wohl, dass es in jeder Unit stehen muss.

jaenicke 4. Jan 2023 13:03

AW: Codeoptimierung lieber abschalten
 
Zitat:

Zitat von dummzeuch (Beitrag 1516979)
Selbst mein Hinweis, dass ich solche Fehler schon mehrfach gesehen habe

Ich habe dazu lediglich geschrieben, wie meine Erfahrungen mit solchen Meldungen waren. Das heißt nicht, dass das bei dir kein Compilerfehler war.

Konkrete Beispiele fände ich aber interessant.

Uwe Raabe 4. Jan 2023 13:28

AW: Codeoptimierung lieber abschalten
 
Zitat:

Zitat von jaenicke (Beitrag 1516981)
Konkrete Beispiele fände ich aber interessant.

Da kann ich mich nur anschließen! Zum einen kann man testen, ob es im aktuellen Delphi noch vorhanden ist, und zum anderen einen Bugreport schreiben, damit es behoben werden kann.

dummzeuch 4. Jan 2023 13:48

AW: Codeoptimierung lieber abschalten
 
Zitat:

Zitat von jaenicke (Beitrag 1516981)
Konkrete Beispiele fände ich aber interessant.

Hm, ich habe gerade mal den Sourcecode unserer internen Bibliothek nach {$OPTIMIZATION OFF} ge-grep-t. Das einzige Beispiel, das ich dort gefunden habe ist etwas zu komplex, um es hier sinnvoll posten zu können:

Delphi-Quellcode:
finally
// Wenn Optimization on ist, gibt es in Delphi 2007 eine AccessViolation in TLaserData.Done bei
// der Freigabe von FReader. Ohne passiert das nicht.
// -- 2021-04-16 twm
{$OPTIMIZATION OFF}
    for LaserNo := Low(LaserData) to High(LaserData) do
      LaserData[LaserNo].Done;
    FreeAndNil(TrigStream);
    FreeAndNil(OutStream);
  end;
  Result := FRes;
end;
{$IFDEF OPTIMIZATION_IS_ON}
// Ab hier kann man Optimization wieder einschalten. Frueher - also z.B. direkt nach der
// for-schleife ging es nicht.
// -- 2021-04-16 twm
{$OPTIMIZATION ON}
{$ENDIF}

procedure TLaserData.Done;
begin
  FreeAndNil(FReader);
end;
Das sagt ziemlich wenig, ohne den Rest der Methode, aber selbst wenn ich die hier poste könnte, wäre sie ohne Kontext nur sehr schwer verständlich. Laserdata ist ein Array of TLaserData-Records, die optional initialisiert werden, wenn es die entsprechenden Dateien gibt. FReader wurde vor dem zugehörigen try mit NIL initializiert.

Andere Beispiele (ich meine es waren noch zwei weitere), finde ich nicht, die müssen im Source von einzelnen internen Tools gewesen sein, und davon haben wir zuviele um den mal eben zu grep-en.

Obiges Beispiel kann ich noch nicht auf Delphi 10.2 portieren, da es immernoch einen Rechner mit Windows XP gibt, auf dem es laufen muss, deshalb weiß ich nicht, ob der Fehler dort noch auftreten würde.

Sherlock 4. Jan 2023 14:01

AW: Codeoptimierung lieber abschalten
 
Also ich kann nur sagen, ich benutze die Optimierung immer und bin bisher noch nicht damit gegen eine Wand gefahren. Aber natürlich gibt es immer und überall Fehler, darum testet man ja - sowohl automatisiert als auch mit Menschen.

Hier mal ein paar Beispiele wie Fehler zu handhaben sind:
https://quality.embarcadero.com/browse/RSP-16456
https://quality.embarcadero.com/browse/RSP-34668
https://quality.embarcadero.com/browse/RSP-13831


Sherlock

Benmik 4. Jan 2023 15:44

AW: Codeoptimierung lieber abschalten
 
Zitat:

Zitat von Andreas13 (Beitrag 1516977)
Ist das nicht zu riskant? Wir unterdrücken damit eventuelle Fehler im Debug-Modus, lassen sie jedoch in der endgültigen Release-Version zu...

Ich hatte bisher ja noch nie von diesen Compiler-Fehlern gehört und um die Relevanz wird hier ja auch etwas gestritten. Was ich damit erreichen möchte, ist, dass ich nicht vergesse, die Optimierung wieder einzuschalten, was für mich persönlich das größere Problem ist. Uwe hat recht, dass man das in jede Unit eintragen muss; da es bei mir aber nahezu die Regel ist, dass mich die Optimierung schwerst beim Debuggen stört, steht das tatsächlich in sehr vielen Units drin. Aber man lernt ja dazu, zum Beispiel durch
Zitat:

Zitat von dummzeuch (Beitrag 1516979)
... durch Setzen der Option in der Release-Config.


himitsu 4. Jan 2023 15:49

AW: Codeoptimierung lieber abschalten
 
Einfach noch eine Config hinzufügen?

Release
Debug (wie Release, nur ohne Debuginfos)

Und dann kann man nochmal davon ableiten und Varianten mit/ohne Codeoptimierung hinzufügen,
oder, wie bereits erwähnt, dann das wenigstens in beiden Configs abschalten, damit man auch das debuggt, was auch der Kunde bekommt.

Alternativ mit externen Debuginfos kompilieren ... jenachdem ob die Debuginfodateien (TDS) daneben liegen, ist es mit oder ohne, aber die Programmdateien selber sind immer identisch.

TomyN 4. Jan 2023 16:41

AW: Codeoptimierung lieber abschalten
 
Ich meine gehört zu haben :?, dass im Optimierungsfalle Schleifen ggf. in die andere Richtung abgearbeitet werden, was zu 'Seiteneffekten' führen kann.

Uwe Raabe 4. Jan 2023 17:01

AW: Codeoptimierung lieber abschalten
 
Ohne einen Beleg dafür ist das nur Angstmacherei.

TurboMagic 4. Jan 2023 17:15

AW: Codeoptimierung lieber abschalten
 
Zitat:

Zitat von himitsu (Beitrag 1516998)
Einfach noch eine Config hinzufügen?

Release
Debug (wie Release, nur ohne Debuginfos)

Und dann kann man nochmal davon ableiten und Varianten mit/ohne Codeoptimierung hinzufügen,
oder, wie bereits erwähnt, dann das wenigstens in beiden Configs abschalten, damit man auch das debuggt, was auch der Kunde bekommt.

Alternativ mit externen Debuginfos kompilieren ... jenachdem ob die Debuginfodateien (TDS) daneben liegen, ist es mit oder ohne, aber die Programmdateien selber sind immer identisch.

Eine andere Alternative wäre, diese defines in eine Include Datei zu packen und diese per {$I MeineIncludeDatei.inc} in jeder Unit einzubinden.
Dann könnte man es wieder zentral ein/ausschalten.

jaenicke 4. Jan 2023 17:45

AW: Codeoptimierung lieber abschalten
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von TomyN (Beitrag 1517001)
Ich meine gehört zu haben :?, dass im Optimierungsfalle Schleifen ggf. in die andere Richtung abgearbeitet werden, was zu 'Seiteneffekten' führen kann.

Zitat:

Zitat von Uwe Raabe (Beitrag 1517004)
Ohne einen Beleg dafür ist das nur Angstmacherei.

Das ist keine Angstmacherei, das ist wirklich so. Das ist aber auch kein Problem und nur im generierten Assemblercode sichtbar, da das nur passiert, wenn man die Schleifenvariable nicht verwendet. Beispiel:
Delphi-Quellcode:
procedure Test;
var
  i: Integer;
begin
  for i := 0 to 9 do
    ShowMessage(1.ToString);
end;
Der generierte Code sieht so aus:
Anhang 55709

//EDIT:
Ach ja, wenn man im Assemblercode nicht die Variable, sondern das Register anspricht, kommt man auch dran. Das kann jeder mit Optimierung testen:
Delphi-Quellcode:
procedure Test;
var
  i, b: Integer;
begin
  for i := 0 to 9 do
  begin
    asm
      mov b, ebx
    end;
    ShowMessage(b.ToString);
  end;
end;

Uwe Raabe 4. Jan 2023 18:23

AW: Codeoptimierung lieber abschalten
 
Zitat:

Zitat von jaenicke (Beitrag 1517008)
Das ist keine Angstmacherei, das ist wirklich so. Das ist aber auch kein Problem und nur im generierten Assemblercode sichtbar, da das nur passiert, wenn man die Schleifenvariable nicht verwendet.

Ich weiß. Die Angstmacherei bezog sich auch eher auf das "Ich meine gehört zu haben" und "was zu 'Seiteneffekten' führen kann". Die Rückwärtsschleifen kommen ja nur dann zum tragen, wenn es eben keine unerwünschten Seiteneffekte dabei gibt.

himitsu 4. Jan 2023 19:12

AW: Codeoptimierung lieber abschalten
 
Zitat:

Zitat von TomyN (Beitrag 1517001)
Ich meine gehört zu haben :?, dass im Optimierungsfalle Schleifen ggf. in die andere Richtung abgearbeitet werden, was zu 'Seiteneffekten' führen kann.

Ja, die zählen manchmal rückwärts auf 0 runter, aber beim Zugriff wird das umgerechnet und schon stimmt es wieder.

Egal, ob aus dem
Delphi-Quellcode:
for i := 1 to 9 do
  Write(i);
der Compiler das macht.
Delphi-Quellcode:
for i := 8 downto 0 do
  Write(9 - i);
Am Ende kommt das Gleiche bei raus.

Aber kommt wer auf die saudumme Idee nach der Schleife auf i zugreifen zu wollen, dann ist er selbst Schuld.



@jaenicke:
Mit 64 Bit stirbt der Inline-Assembler eh aus.
Und wenn i mal nicht in ebx liegt, dann hat dein Code eh ein Problem.
Wenn du im Assembler auf "i" zugreifst, dann weiß der Compiler in welchem Register/Stack die Variable liegt und dass hier nicht optimiert werden kann/soll.

Auch mit Pointern kann man da Mist bauen.
Delphi-Quellcode:
for i := 0 to 9 { step 2 } do begin
  ShowMessage(i.ToString); // 0 2 4 6 8
  Inc(PInteger(@i)^);
end;

Sherlock 5. Jan 2023 10:30

AW: Codeoptimierung lieber abschalten
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1517004)
Ohne einen Beleg dafür ist das nur Angstmacherei.

Daher meine knappe Anmerkung in #4: FUD

Sherlock

Stevie 9. Jan 2023 12:16

AW: Codeoptimierung lieber abschalten
 
Ich korrigiere mal einige Aussagen bezüglich "rückwärts zählende Schleifen".

Sofern die Zählvariable innerhalb des Schleifenrumpfes benutzt wird, fügt der Compiler zusätzlich zu der Zählvariable, welche sich im korrekten Wertebereich bewegt zusätzlich eine Variable ein, die er nutzt, um auf 0 runter zu zählen. Diese wird aber nicht wie etwa von Himitsu skizziert für irgendetwas anderes genutzt als für den Schleifen Code an sich. Interessanterweise passiert dies in dem geposteten Code nicht mal, sondern nur, wenn lower und/oder upper bound variabel sind.

Das auf 0 runter zählen ist eine gängige Optimierung da hierbei nach dem Dekrement direkt ein bedingter Sprungbefehl stehen kann, anstatt zuerst einen Vergleich auf die obere Grenze - je nachdem wie viele Register für den Code gebraucht werden, kann das aber auch eher nachteilig sein, gerade unter 32bit hat man nur eine Handvoll davon.


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:18 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz