どのように私は、コンパイラ/ JITによって最適化されることはありません(テスト)コードを書くのですか?
-
23-08-2019 - |
質問
私は本当にコンパイラとJIT最適化の内部についてあまり知らないが、私は通常、最適化され、何ができなかったことができるかを推測するために「常識」を使用してみてください。だから、私は今日、単純なユニットテストの方法を書いていた。
@Test // [Test] in C#
public void testDefaultConstructor() {
new MyObject();
}
この方法では、実際に私が必要とするすべてです。これは、デフォルトのコンストラクタが存在し、例外なしに動作することを確認します。
しかし、私は、コンパイラ/ JIT最適化の効果について考え始めました。コンパイラ/ JITは完全にnew MyObject();
文を排除することによって、この方法を最適化してもらえますか?もちろん、コールグラフは、単にオブジェクトの内部状態を初期化し、通常のコンストラクタのための典型的なケースであり、他のオブジェクトに副作用を持たないことを決定する必要がある。
私は唯一のJITは、そのような最適化を実行するために許可されるであろうと推測します。これはおそらく、試験方法は一度だけ実行されているので、それは、私が心配するべきものではないことを意味します。私の仮定が正しいですか?
それにもかかわらず、私は一般的な主題について考えるようにしようとしています。私は最適化されてから、このメソッドを防ぐ方法を考えたとき、私は私がassertTrue(new MyObject().toString() != null)
も思ったが、これはtoString()
メソッドの実際の実装に非常に依存する、そしてその後も、JITはそのtoString()
メソッドは常にnull以外を返すかを決定することができます文字列(例えば、実際Object.toString()
と呼ばれている場合)、したがって、全体の枝を最適化します。したがって、この方法では動作しないでしょう。
私はC#で、私は[MethodImpl(MethodImplOptions.NoOptimization)]
を使用できることを知っているが、これは私が実際に探しているものではありません。私は期待して私のコードのいくつかの特定の部分(s)は実際にこのプロセスに干渉するJITなしで、動作することを確認しての(言語に依存しない)方法を見つけることを期待しています。
また、私は私のユニットテストを作成する際に注意すべき任意の典型的な最適化の例があるのですか?
どうもありがとうございました!
解決
それについては心配しないでください。これまで(スピードを除く)お使いのシステムに違いを作ることができる何かを最適化するために、許可されていません。あなたがオブジェクトを新しい場合は、コードが呼び出される、メモリが割り当てられます、それが動作する必要があります。
あなたはそれがあれば(偽)で保護されていた場合、それは完全にシステムのうち、最終的に最適化することができている場合はfalse、それは方法は理論的には(何かをし、ITを最適化していないことを検出することができました)。
編集:
:ところで、また、この方法を決定するのに十分にスマートすることができnewIfTrue(boolean b) {
if(b)
new ThisClass();
}
bがfalseの場合、常に何もしない、そして最終的にはあなたのコードのB内の1つのポイントで常に偽であることを把握し、完全にそのコードのうち、このルーチンをコンパイルします。
これは、JITは、任意の非管理言語では事実上不可能だものを行うことができる場所です。
他のヒント
私はあなたがそれを離れて最適化されたばかり心配しているならば、あなたはテストやり過ぎのビットをやっているかもしれないと思う。
静的言語で、私はテストとして、コンパイラと考える傾向にあります。それがコンパイルを通過した場合、それは、特定の物事が(メソッドのような)があることを意味します。あなたが(それは文句を言わない例外をスロー証明します)あなたのデフォルトコンストラクタを行使する別のテストを持っていない場合は、あなたが最初の場所で(YAGNIをし、すべてのこと)がデフォルトコンストラクタを書いている理由について考えてほしいことがあります。
私は私と一緒に同意しない人がいるけど、私はこの種のもののように感じても、TDDゴーグルを通してそれを見ていない便利な理由のためのテストあなたの数を膨張させてしまいますだけで何か、です。
それについてこのように考えてみます:
(私はそれが可能だとは思わない、私は漠然と私のCSコースからP = NPについて何かを覚えている)そのコンパイラは、コールグラフは、任意の副作用を持っていないと判断することができると仮定します。それは副作用を持たない任意の方法を最適化します。ほとんどのテストはありませんし、任意の副作用を持つべきではないので、コンパイラはそれらをすべて離れて最適化することができます。
JITは、言語だけの保証セマンティクスには影響しません操作を実行するために許可されています。理論的には、割り当てを削除することもできますし、の場合MyObject
コンストラクタにを呼び出すには、呼び出しは副作用を持たないと(OutOfMemoryError
を数えていない)例外をスローすることはできないことを保証することができます。
つまり、JITは、あなたのテストのうちの呼び出しを最適化した場合の、その後、あなたのテストはとにかく合格しているだろうの。
PS:のパフォーマンスのテストとは対照的に、あなたは、の機能のテストを行っているので、これが適用されることに注意してください。パフォーマンステストでは、JITがあなたの結果は無用になる他、あなたが測定されている操作を離れて最適化していないことを確認することが重要です。
C#で、私はこれを行うことができると思わます:
[Test]
public void testDefaultConstructor() {
GC.KeepAlive(new MyObject());
}
AFAIU、GC.KeepAlive
法は、JITによってインライン化されないので、コードが期待どおりに動作することが保証されます。しかし、私はJavaで同様の構造を知りません。
なぜそれは問題でしょうか?コンパイラ/ JITを静的にNOが(副作用を引き起こす可能性がある)ヒットしようとしているアサート決定できる場合は、罰金だ。
すべてのI / Oは、副作用であるので、あなただけ置くことができます。
Object obj = new MyObject();
System.out.println(obj.toString());
、あなたは罰金だ。