C++ で気軽に時間測定がしたい

プログラムの一部分の所要時間をちょっと調べたいと思っても,前で時間を調べて,後ろで時間を調べて,引き算したものを出力して,と色々書かねばならず,意外と面倒です.

Rubybenchmark はいいなあと思っていたら,id:tanakh さんの PFI セミナーを思い出したので,それっぽいものを C++ で実現してみました.

(2/21 19:30 頃に「もう少し便利に」のバージョンの問題点と解決について追記しました)

int main() {
  benchmark {
    sleep(1);
  }
  benchmark {
    sleep(2);
  }
}

こんな感じで書くと

1.000013 sec
2.000009 sec

こんな感じで標準エラー出力に表示.

ソースコード

これを上に書いておけば OK です.

#include <sys/time.h>

struct __bench__ {
  double start;
  __bench__() {
    start = sec();
  }
  ~__bench__() {
    fprintf(stderr, "%.6f sec\n", sec() - start); 
  }
  double sec() {
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return tv.tv_sec + tv.tv_usec * 1e-6;
  }
  operator bool() { return false; }
};

#define benchmark if ( __bench__ __b__ = __bench__()); else

もう少し便利に

いっぱい出力すると何が何だか分からなくなりそうなので,タイトルを指定できるようにしてみました.
printf などと同様の書き方でタイトルを指定することができます.

#include <sys/time.h>

struct __bench__ {
  double start;
  __bench__(int dummy) {
    start = sec();
  }
  ~__bench__() {
    fprintf(stderr, ": %.6f sec\n", sec() - start);
  }
  double sec() {
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return tv.tv_sec + tv.tv_usec * 1e-6;
  }
  operator bool() { return false; }
};

#define benchmark(...) \
  if (__bench__ __b__ = __bench__(fprintf(stderr, __VA_ARGS__))); else

例えば,

#include <unistd.h>

int main() {
  for (int i = 0; i <= 3; i++) {
    benchmark("sleep(%d)", i) {
      sleep(i);
    }
  }
}

というように書くと

sleep(0): 0.000003 sec
sleep(1): 1.000013 sec
sleep(2): 2.000012 sec
sleep(3): 3.000011 sec

というように出力されます.

追記(2/21 19:30 頃)

「もう少し便利に」のバージョンは,ブロック内で標準エラー出力へ出力していたり,入れ子的に使ったりすると,表示がおかしなことになってしまうという問題があります.

それについてつぶやいたところ,id:qnighy が対策したコードを書いてくれました.