5


2

C ++で記述されLinux / OSXで実行される小さなコードパスをマイクロベンチマークする正確な方法を探しています

私は、C ++で記述したタイトループなどの小さなコードパスの非常に基本的なマイクロベンチマークを実行しようとしています。 LinuxとOSXで実行しており、GCCを使用しています。 サブミリ秒の精度のためにどのような施設がありますか? コードパスを何度も(数千万?)実行する簡単なテストで十分な整合性が得られ、良い結果が得られると考えています。 誰かが望ましい方法を知っているなら、気軽にそれらを提案してください。

4 Answer


6


x86 / x86_64で `" rdtsc "`プロセッサ命令を使用できます。 マルチコアシステムの場合、CPUIDの「constant_tsc」機能(Linuxの場合は/ proc / cpuinfo)を確認してください。これは、動的な周波数の変更とスリープ中でも、すべてのコアが同じティックカウンターを使用することを意味します。

プロセッサがconstant_tscをサポートしていない場合、必ずプログラムをコアにバインドしてください(Linuxの `taskset`ユーティリティ)。

順不同CPU(Intel Atom以外、すべて他のローエンドcpusである可能性があります)でrdtscを使用する場合、前に「ordering」命令を追加します。 「cpuid」-命令の並べ替えを一時的に無効にします。

また、MacOsXには、コード内の一部のハードウェアイベントを測定できる「Shark」があります。

「RDTSC」と異常なCPU。 最適化に関する2番目の素晴らしいFogのマニュアルのセクション18の詳細:https://www.agner.org/optimize/optimizing_assembly.pdf[アセンブリ言語のサブルーチンの最適化:x86プラットフォームの最適化ガイド](すべての5つのマニュアルはhttp://www.agner.org/optimize/です)

_ アウトオブオーダー実行を備えたすべてのプロセッサーでは、カウンターの読み取りの前後にXOR EAX、EAX / CPUIDを挿入して、カウンターが他と並行して実行されないようにする必要があります。 CPUIDはシリアル化命令です。つまり、パイプラインをフラッシュし、保留中のすべての操作が完了するまで待ってから処理を進めます。 これはテスト目的で非常に役立ちます。 _


0


これは私が過去に使用したものです:

inline double gettime ()
{
    timeval tv;
    gettimeofday (&tv, NULL);
    return double (tv.tv_sec) + 0.000001 * tv.tv_usec;
}

その後:

double startTime = gettime();
// your code here
double runTime = gettime() - startTime;

これはマイクロ秒に引用します。


0


Cachegrind / kCachegrindは非常に詳細なプロファイリングに適しています。 OS Xで利用できるとは思わないが、Linuxで得られる結果は代表的なものであるべきだ。


0


Microbenchmarkは、ループ内で同じコードを実行する必要があります(できれば多くの反復にわたって)。 以下を使用し、time(1)ユーティリティで実行しました。

次の注意事項が観察されました

  • テストが印刷された計算を生成しない場合 コードは最適化によって除去されます—​O3を付けたgccはそれを行います。

  • test()およびlookup()のテスト関数は、 反復のループとは異なるソースファイル。それらが同じファイル内にあり、ルックアップ関数が定数値を返す場合、コード最適化はそれを一度も呼び出さず、一度だけではなく、戻り値に反復回数を掛けます!

ファイルmain.c

#include

#define RUN_COUNT 10000000

void init();
int  lookup();


main()
{
  int sum = 0;
  int i;

  init();


  for(i = 0; i < RUN_COUNT; i++ ) {
    sum  += lookup();
  }

  printf("%d", sum );
}