1. ホーム
  2. java

マイクロベンチマークとは?

2023-10-01 12:24:02

質問

この言葉を聞いたことがありますが、意味がよくわかりませんので。

  • この用語は何を意味し、何を意味しないのでしょうか。
  • マイクロベンチマークはどのようなもので、どのようなものではないのでしょうか。
  • マイクロベンチマークにはどのような危険があり、どのようにそれを避けるのですか?
    • (あるいは良いことなのでしょうか?)

どのように解決するのですか?

これは、缶に書いてある通りの意味です。オペレーティング システムのカーネルへのシステム コールのような、何か "小さいもの" のパフォーマンスを測定しています。

危険なのは、最適化を指示するために、マイクロベンチマークから得られるどんな結果でも使用する可能性があるということです。そして、私たちが知っているように

私たちは小さな効率、たとえば 97% の時間について忘れるべきでしょう。 すべての悪の根源である。

マイクロベンチマークの結果を歪める要因はたくさんありえます。コンパイラーの最適化もその 1 つです。測定されるオペレーションが非常に短い時間で、それを測定するために使用するものが実際のオペレーション自体よりも長い時間を要する場合、マイクロベンチマークもまた歪んでしまいます。

例えば、誰かが for ループのオーバーヘッドのマイクロベンチマークを取るかもしれません。

void TestForLoop()
{
    time start = GetTime();

    for(int i = 0; i < 1000000000; ++i)
    {
    }

    time elapsed = GetTime() - start;
    time elapsedPerIteration = elapsed / 1000000000;
    printf("Time elapsed for each iteration: %d\n", elapsedPerIteration);
}

明らかにコンパイラはこのループが全く何もしないことを見抜き、ループのためのコードを全く生成しないことができます。そのため elapsedelapsedPerIteration はかなり無駄です。

ループが何かしていても

void TestForLoop()
{
    int sum = 0;
    time start = GetTime();

    for(int i = 0; i < 1000000000; ++i)
    {
        ++sum;
    }

    time elapsed = GetTime() - start;
    time elapsedPerIteration = elapsed / 1000000000;
    printf("Time elapsed for each iteration: %d\n", elapsedPerIteration);
}

コンパイラは変数 sum は何にも使われないと判断し、それを最適化し、for ループも最適化します。しかし、ちょっと待ってください。こうしたらどうだろう。

void TestForLoop()
{
    int sum = 0;
    time start = GetTime();

    for(int i = 0; i < 1000000000; ++i)
    {
        ++sum;
    }

    time elapsed = GetTime() - start;
    time elapsedPerIteration = elapsed / 1000000000;
    printf("Time elapsed for each iteration: %d\n", elapsedPerIteration);
    printf("Sum: %d\n", sum); // Added
}

コンパイラは賢いので sum が常に定数値であることを認識し、そのすべてを最適化することができるかもしれません。多くの人が、最近のコンパイラーの最適化能力に驚くことでしょう。

しかし、コンパイラが最適化できないものについてはどうでしょうか?

void TestFileOpenPerformance()
{
    FILE* file = NULL;
    time start = GetTime();

    for(int i = 0; i < 1000000000; ++i)
    {
        file = fopen("testfile.dat");
        fclose(file);
    }

    time elapsed = GetTime() - start;
    time elapsedPerIteration = elapsed / 1000000000;
    printf("Time elapsed for each file open: %d\n", elapsedPerIteration);
}

これさえも有用なテストではありません! オペレーティング システムは、ファイルが非常に頻繁に開かれていることを認識し、パフォーマンスを向上させるためにそれをメモリにプリロードすることがあります。ほとんどすべてのオペレーティング システムがこのようなことをしています。同じことがアプリケーションを開くときにも起こります。オペレーティング システムは、最も頻繁に開く上位 5 つのアプリケーションを見つけ出し、コンピューターを起動するときに、アプリケーション コードをあらかじめメモリにロードしておくかもしれません!

実際には、参照の局所性 (たとえば、配列対リンク リスト)、キャッシュとメモリ帯域幅の効果、コンパイラー インライン化、コンパイラーの実装、コンパイラー スイッチ、プロセッサー コアの数、プロセッサー レベルでの最適化、オペレーティング システム スケジューラー、オペレーティング システムのバックグラウンド プロセスなど、無数の変数が出てくるのです。

ですから、マイクロベンチマークは多くの場合、必ずしも有用な測定基準ではありません。よく定義されたテストケースによるプログラム全体のベンチマーク (プロファイリング) を置き換えるものではありません。最初に読みやすいコードを書き、次に、必要なものがあれば、それを確認するためにプロファイルを作成します。

私は、マイクロベンチマークは悪ではないことを強調したいと思います。
それ自体

しかし、慎重に使用しなければなりません (これはコンピューターに関連する他の多くの事柄にも当てはまります)。