1

私たちは、Java Byte Code プログラムの平均的なケースのランタイム分析用のツールを構築しています。その一環として、実際の実行時間を測定しています。したがって、結果がある場合とない場合、および副作用がある場合とない場合がある任意のユーザー提供のメソッド (例には、クイックソート、階乗、ダミーのネストされたループなどがあります) を使用し、それを (リフレクションを使用して) 実行し、測定します。経過時間。(適切にベンチマークを行うかどうかは、ここでのポイントとは別です。)

ベンチマーク コードでは、結果に対して何もしていないことは明らかです (また、一部のメソッドでは結果が得られません)。したがって、JIT が何を行うかはわかりませんが、実際には、ベンチマークされたメソッド呼び出し全体が最適化されているように見えることが時々あります。ベンチマークされた方法は実際には単独で使用されないため、ベンチマークは役に立たなくなります。

JITがそれを行うのをどのように防ぐことができますか? ベンチマークには時間がかかるため、それを完全にオフにしたくはありませんが、とにかく「実際の」ランタイムをベンチマークしたい (したがって、JIT をメソッドでアクティブにする必要があります)。

この質問は承知していますが、与えられたシナリオは狭すぎます。結果の型がわからない (存在する場合) ため、JIT が役に立たないと見なすような方法で結果を使用することはできません。

4

3 に答える 3

2

簡単な解決策は、最適化されずに済むように、ほぼ有用な機能を実行する、より現実的なベンチマークを作成することです。

JIT を混乱させるいくつかのトリックがありますが、これらが役に立たない可能性があります。

メソッドがリフレクション、MethodHandle を介して呼び出され、何もコンパイルされないベンチマークの例を次に示します。

import java.lang.invoke.*;
import java.lang.reflect.*;

public class Main {
    public static void main(String... args) throws Throwable {
        for (int j = 0; j < 5; j++) {
            testViaReflection();
            testViaMethodHandle();
            testWithoutReflection();
        }
    }

    private static void testViaReflection() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        Method nothing = Main.class.getDeclaredMethod("nothing");
        int runs = 10000000; // triggers a warmup.
        long start = System.nanoTime();
        Object[] args = new Object[0];
        for (int i = 0; i < runs; i++)
            nothing.invoke(null, args);
        long time = System.nanoTime() - start;
        System.out.printf("A call to %s took an average of %.1f ns using reflection%n", nothing.getName(), 1.0 * time / runs);
    }

    private static void testViaMethodHandle() throws Throwable {
        MethodHandle nothing = MethodHandles.lookup().unreflect(Main.class.getDeclaredMethod("nothing"));
        int runs = 10000000; // triggers a warmup.
        long start = System.nanoTime();
        for (int i = 0; i < runs; i++) {
            nothing.invokeExact();
        }
        long time = System.nanoTime() - start;
        System.out.printf("A call to %s took an average of %.1f ns using MethodHandle%n", "nothing", 1.0 * time / runs);
    }

    private static void testWithoutReflection() {
        int runs = 10000000; // triggers a warmup.
        long start = System.nanoTime();
        for (int i = 0; i < runs; i++)
            nothing();
        long time = System.nanoTime() - start;
        System.out.printf("A call to %s took an average of %.1f ns without reflection%n", "nothing", 1.0 * time / runs);
    }

    public static void nothing() {
        // does nothing.
    }
}

版画

A call to nothing took an average of 6.6 ns using reflection
A call to nothing took an average of 10.7 ns using MethodHandle
A call to nothing took an average of 0.4 ns without reflection
A call to nothing took an average of 4.5 ns using reflection
A call to nothing took an average of 9.1 ns using MethodHandle
A call to nothing took an average of 0.0 ns without reflection
A call to nothing took an average of 4.3 ns using reflection
A call to nothing took an average of 8.8 ns using MethodHandle
A call to nothing took an average of 0.0 ns without reflection
A call to nothing took an average of 5.4 ns using reflection
A call to nothing took an average of 13.2 ns using MethodHandle
A call to nothing took an average of 0.0 ns without reflection
A call to nothing took an average of 4.9 ns using reflection
A call to nothing took an average of 8.7 ns using MethodHandle
A call to nothing took an average of 0.0 ns without reflection

MethodHandles はリフレクションよりも高速であると想定していましたが、そうではないようです。

于 2012-08-29T10:48:08.853 に答える
0

一部の実験的なもの (エスケープ解析など) を除いて、JIT 最適化を選択的に無効にする方法はないと思います。

あなたはこう言います:

ベンチマークを完全にオフにしたくはありません。ベンチマークには時間がかかりますが、とにかく「実際の」ランタイムをベンチマークしたいからです。

しかし、あなたがやろうとしていることはまさにそれです。実際のランタイムでは、メソッド呼び出しインライン化れ、何もしない場合は最適化されます。したがって、これらの最適化を禁止すると、実際のプログラムで実際に発生するものと一致しないメソッド実行時間の測定値が得られます。

于 2012-08-29T10:54:31.303 に答える
0

ベンチマークの目的は、実際のパフォーマンスにできるだけ近づけることなので、ここで何が得られるかはわかりません。JIT が特定のことを行うと思われ、通常の使用では実際に無効にしたくない場合は、その前提でベンチマークを構築するのが最善の策です。プロファイラーの下でベンチマークを実行すると、効率がいつ低下するかを判断するのに役立つため、ベンチマークを作成して JIT の下でストレスを与えて非効率的に動作させる方法があれば、それも役立つ可能性があります。

于 2012-08-29T11:01:27.920 に答える