Wie schreibe (Test) Code, der nicht vom Compiler / JIT optimiert wird?

8

Ich weiß nicht wirklich viel über die Interna von Compiler- und JIT-Optimierungen, aber normalerweise versuche ich "gesunden Menschenverstand" zu verwenden, um zu raten, was optimiert werden könnte und was nicht. Da schrieb ich heute eine einfache Unit-Test-Methode:

%Vor%

Diese Methode ist eigentlich alles was ich brauche. Es überprüft, dass der Standardkonstruktor existiert und ohne Ausnahmen läuft.

Aber dann begann ich über die Auswirkungen von Compiler / JIT-Optimierungen nachzudenken. Könnte der Compiler / JIT diese Methode optimieren, indem er die new MyObject(); -Anweisung vollständig eliminiert? Natürlich müsste es feststellen, dass das Aufrufdiagramm keine Nebeneffekte auf andere Objekte hat, was der typische Fall für einen normalen Konstruktor ist, der einfach den internen Zustand des Objekts initialisiert.

Ich gehe davon aus, dass nur der JIT eine solche Optimierung durchführen darf. Dies bedeutet wahrscheinlich, dass ich mich nicht darum kümmern muss, weil die Testmethode nur einmal ausgeführt wird. Sind meine Annahmen richtig?

Trotzdem versuche ich über das allgemeine Thema nachzudenken. Als ich darüber nachdachte, wie ich verhindern kann, dass diese Methode optimiert wird, dachte ich, ich könnte assertTrue(new MyObject().toString() != null) , aber dies ist sehr abhängig von der tatsächlichen Implementierung der toString() -Methode, und selbst dann kann die JIT diese toString() -Methode ermitteln gibt immer eine Nicht-Null-Zeichenfolge zurück (zB wenn tatsächlich Object.toString() aufgerufen wird) und optimiert somit den gesamten Zweig. Also würde dieser Weg nicht funktionieren.

Ich weiß, dass ich in C # [MethodImpl(MethodImplOptions.NoOptimization)] verwenden kann, aber das ist nicht das, wonach ich eigentlich suche. Ich hoffe, einen (sprachunabhängigen) Weg zu finden, um sicherzustellen, dass einige spezifische Teile meines Codes tatsächlich so laufen, wie ich es erwarte, ohne dass der JIT in diesen Prozess eingreift.

Gibt es darüber hinaus typische Optimierungsfälle, die ich beim Erstellen meiner Komponententests beachten sollte?

Vielen Dank!

    
Hosam Aly 13.02.2009, 22:24
quelle

7 Antworten

4

Mach dir keine Sorgen darüber. Es ist nicht erlaubt, jemals etwas zu optimieren, das für Ihr System einen Unterschied machen kann (außer für die Geschwindigkeit). Wenn Sie ein Objekt neu erstellen, wird der Code aufgerufen, der Speicher wird zugewiesen, er muss funktionieren.

Wenn Sie es durch ein if (false) geschützt hätten, wo false ein final ist, könnte es vollständig aus dem System heraus optimiert werden, dann könnte es erkennen, dass die Methode nichts macht und das IT out (theoretisch) optimiert ).

Edit: Übrigens kann es auch schlau genug sein, diese Methode zu bestimmen:

%Vor%

wird immer nichts tun, wenn b falsch ist, und irgendwann herausfinden, dass B an einem Punkt immer falsch ist und diese Routine komplett aus diesem Code kompiliert.

Hier kann das JIT Dinge tun, die in keiner nicht verwalteten Sprache praktisch unmöglich sind.

    
Bill K 13.02.2009, 22:37
quelle
5

Ich denke, wenn du dir Sorgen machst, dass es weg optimiert wird, tust du vielleicht ein wenig Test-Overkill.

In einer statischen Sprache tendiere ich dazu, den Compiler als einen Test zu betrachten. Wenn es kompiliert wird, bedeutet das, dass bestimmte Dinge vorhanden sind (wie Methoden). Wenn Sie keinen anderen Test haben, der Ihren Standardkonstruktor ausübt (was beweisen wird, dass er keine Ausnahmen auslöst), sollten Sie sich überlegen, warum Sie diesen Standardkonstruktor an erster Stelle schreiben (YAGNI und all das).

Ich weiß, dass es Leute gibt, die mir nicht zustimmen, aber ich habe das Gefühl, dass so etwas einfach die Anzahl der Tests unnötig aufbläht, selbst wenn man es durch die TDD-Brille betrachtet. p>     

Matt Briggs 13.02.2009 22:34
quelle
2

Denken Sie darüber nach:

Nehmen wir an, dass der Compiler feststellen kann, dass der Aufrufgraph keine Nebenwirkungen hat (ich glaube nicht, dass es möglich ist, ich erinnere mich vage an etwas von P = NP aus meinen CS-Kursen). Es wird jede Methode optimieren, die keine Nebenwirkungen hat. Da die meisten Tests keine Nebenwirkungen haben und auch nicht haben sollten, kann der Compiler sie alle optimieren.

    
Alex Reitbort 13.02.2009 22:40
quelle
2

Der JIT darf nur Operationen ausführen, die die garantierte Semantik der Sprache nicht beeinflussen. Theoretisch könnte es die Zuweisung und den Aufruf an den MyObject -Konstruktor entfernen, wenn es garantieren kann, dass der Aufruf keine Nebenwirkungen hat und niemals eine Ausnahme auslösen kann (ohne OutOfMemoryError ).

Mit anderen Worten, wenn der JIT den Aufruf Ihres Tests optimiert, wäre Ihr Test trotzdem bestanden .

PS: Beachten Sie, dass dies gilt, weil Sie -Funktionalität testen, anstatt Leistung testen. Bei Leistungstests ist es wichtig sicherzustellen, dass der JIT den von Ihnen gemessenen Vorgang nicht optimiert, andernfalls werden Ihre Ergebnisse nutzlos.

    
Sam Harwell 20.05.2013 20:12
quelle
1

Es scheint, dass ich in C # das tun konnte:

%Vor%

AFAIU, die GC.KeepAlive -Methode wird nicht vom JIT eingebunden, so dass der Code erwartungsgemäß funktioniert. Allerdings kenne ich kein ähnliches Konstrukt in Java.

    
Hosam Aly 13.02.2009 22:40
quelle
0

Warum sollte das eine Rolle spielen? Wenn der Compiler / JIT statisch feststellen kann, dass keine Asserts ausgelöst werden (was zu Nebenwirkungen führen kann), dann geht es Ihnen gut.

    
MichaelGG 13.02.2009 22:37
quelle
0

Jeder I / O ist ein Nebeneffekt, also können Sie einfach

setzen %Vor%

und dir geht es gut.

    
quant_dev 14.02.2009 08:01
quelle

Tags und Links