Article

2014年11月15日

rdtscp や CPU_CLK_UNHALTED は、細かい性能を計測する場合には便利ですが、大きな粒度で計測したい場合、単位の変換などが面倒です。状況に応じて、色々な方法を使い分けると良いでしょう。

以下、思い付く範囲で時間計測方法について列挙していきます。これで全てでは無いと思いますが、知っていると役に立つこともあるかもしれません。(基本的にはLinuxで説明しています。Linux以外で使えるかどうかは調査していません)

timeコマンド

コマンドの時間を計測できます。bash などで使える time コマンドは、シェルの組み込みコマンドですが、これとは別に/usr/bin/time というコマンドもあります。

/usr/bin/time コマンドに -v を付けると、もう少し色々と情報が取得できます

 $ /usr/bin/time -v sleep 1
        Command being timed: "sleep 1"
        User time (seconds): 0.00
        System time (seconds): 0.00
        Percent of CPU this job got: 0%
        Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.00
        Average shared text size (kbytes): 0
        Average unshared data size (kbytes): 0
        Average stack size (kbytes): 0
        Average total size (kbytes): 0
        Maximum resident set size (kbytes): 660
        Average resident set size (kbytes): 0
        Major (requiring I/O) page faults: 0
        Minor (reclaiming a frame) page faults: 216
        Voluntary context switches: 2
        Involuntary context switches: 1
        Swaps: 0
        File system inputs: 0
        File system outputs: 0
        Socket messages sent: 0
        Socket messages received: 0
        Signals delivered: 0
        Page size (bytes): 4096
        Exit status: 0

スワップ回数、スレッド数、メモリ使用量最大量などを簡単に知るのに便利です

perf コマンド

前回説明した、perf_event インターフェースのフロントエンドです。使いかたは色々ありますが、とりあえず、perf stat を使えば、time -v と同じような感覚でコマンドの時間を計測できます

 $ perf stat cat /dev/null

 Performance counter stats for 'cat /dev/null':

          0.395229 task-clock (msec)         #    0.026 CPUs utilized
                 0 context-switches          #    0.000 K/sec
                 0 cpu-migrations            #    0.000 K/sec
               176 page-faults               #    0.445 M/sec
         1,332,497 cycles                    #    3.371 GHz
           932,228 stalled-cycles-frontend   #   69.96% frontend cycles idle
   <not supported> stalled-cycles-backend
           829,973 instructions              #    0.62  insns per cycle
                                             #    1.12  stalled cycles per insn
           158,572 branches                  #  401.215 M/sec
             7,279 branch-misses             #    4.59% of all branches

       0.014989336 seconds time elapsed

/usr/bin/time -v とは違って、実行した命令数、分岐の回数、分岐ミス率などが取得できます。

clock_gettime

POSIX には、絶対時間を取得するgettimeofdayという関数がありますが、これはobsoleteとなっています。

計測に使う場合にも、以下のような問題が発生する可能性があります。

  • 絶対時刻なので、ntp などが動いて差分が正しく取れない可能性がある。
  • 1970年からの時間なので、世界の時間の進行にあわせて正しく表現するためのbit数が増えていく

かわりに、clock_gettime を使うことが推奨されています。clock_gettimeにCLOCK_MONOTONIC_RAWを渡すと、some unspecified starting point(?) からの時刻を取得できます。

QueryPerformanceCounter

Windows で同じように、時刻を計測するときは、QueryPerformanceCounter を使うと良いでしょう。

QueryPerformanceCounter は、なんらかの64bit カウンタ値を読めるWin32 APIです。このカウンタの増加周波数は、QueryPerformanceFrequency で取得できます。

 #include <windows.h>
#include <stdio.h>

LARGE_INTEGER start, end;

int
main()
{
    QueryPerformanceCounter(&start);
    Sleep(1000);
    QueryPerformanceCounter(&end);

    double delta = end.QuadPart - start.QuadPart;
    LARGE_INTEGER freq;

    QueryPerformanceFrequency(&freq);

    printf("%f\n", delta/ freq.QuadPart);

}

POSIXインターフェースでは、内部でカウンタ→秒へ変換されてしまうのに対し、Win32インターフェースでは、表示の直前までハードウェアカウンタ値を保持できるので、ハードウェアが同じなら取得できる値が0.5bitぐらい良くなりそうな気がしますね!(確実に無視できる誤差ですが)

Tags

About Author

nakamura

Leave a Comment

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください

Recent Comments

Social Media