56843


# 質問

rdtsc命令でクロック計測をしようと思い、調べていたところ以下の資料にたどり着きました。  
[資料](http://web.sfc.keio.ac.jp/%7Erdv/keio/sfc/teaching/system-
software/system-software-2012/lec11-io.html)

こちらのページのToolsに掲載されていたプログラムをコンパイルし実行したところ、以下の結果を得ました。

rdtsc命令でクロック計測したいのは、行列の掛け算なのですが、現在実行しているプログラムをどのように使えば計測したいプログラムの実行時間を計測することができるでしょうか。

# プログラム

### 実行結果

[code]

    value: 1392111630540 delta: 0
    value: 1392111630576 delta: 36
    value: 1392111630598 delta: 22
    value: 1392111630626 delta: 28
    value: 1392111630640 delta: 14
    value: 1392111630654 delta: 14
    value: 1392111630672 delta: 18
    value: 1392111630702 delta: 30
    value: 1392111630718 delta: 16
    value: 1392111630732 delta: 14
    value: 1392111630760 delta: 28
    value: 1392111630774 delta: 14
    value: 1392111630788 delta: 14
    value: 1392111630816 delta: 28
    value: 1392111630828 delta: 12
    value: 1392111630842 delta: 14
    value: 1392111630856 delta: 14
    value: 1392111630884 delta: 28
    value: 1392111630898 delta: 14
    value: 1392111630910 delta: 12
    value: 1392111630924 delta: 14
    (略）
    value: 1392111632012 delta: 12
    value: 1392111632038 delta: 26
    value: 1392111632052 delta: 14
    value: 1392111632064 delta: 12
    value: 1392111632076 delta: 12
    value: 1392111632106 delta: 30
    value: 1392111632118 delta: 12
    value: 1392111632130 delta: 12
    value: 1392111632142 delta: 12
    value: 1392111632170 delta: 28
    value: 1392111632182 delta: 12
    value: 1392111632196 delta: 14
    value: 1392111632224 delta: 28
    value: 1392111632238 delta: 14
    value: 1392111632250 delta: 12
    value: 1392111632262 delta: 12
    value: 1392111632290 delta: 28
    =====
    value: 1392112066122 delta: 1392112066122
    value: 1392112069948 delta: 3826
    value: 1392112073782 delta: 3834
    value: 1392112077324 delta: 3542
    (略）
    value: 1392112390816 delta: 3434
    value: 1392112394684 delta: 3868
    value: 1392112398372 delta: 3688
    value: 1392112402150 delta: 3778
    value: 1392112406074 delta: 3924
    value: 1392112409476 delta: 3402
    value: 1392112412772 delta: 3296
    value: 1392112417012 delta: 4240
    
[/code]

### 実行プログラム

[code]

    #include <stdio.h>
    
    #if defined(__i386__)
    
    static __inline__ unsigned long long rdtsc(void)
    {
      unsigned long long int x;
         __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
         return x;
    }
    #elif defined(__x86_64__)
    
    
    static __inline__ unsigned long long rdtsc(void)
    {
      unsigned hi, lo;
      __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
      return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 );
    }
    
    #elif defined(__powerpc__)
    
    
    static __inline__ unsigned long long rdtsc(void)
    {
      unsigned long long int result=0;
      unsigned long int upper, lower,tmp;
      __asm__ volatile(
                    "0:                  \n"
                    "\tmftbu   %0           \n"
                    "\tmftb    %1           \n"
                    "\tmftbu   %2           \n"
                    "\tcmpw    %2,%0        \n"
                    "\tbne     0b         \n"
                    : "=r"(upper),"=r"(lower),"=r"(tmp)
                    );
      result = upper;
      result = result<<32;
      result = result|lower;
    
      return(result);
    }
    
    #endif
    
    main()
    {
      int i;
    #define MAX 100
      unsigned long long int vals[MAX];
      unsigned long long int lastval = 0, thisval;
    
      for ( i = 0 ; i < MAX ; i++ )
          vals[i] = 1;
      for ( i = 0 ; i < MAX ; i++ )
          vals[i] = rdtsc();
      for ( i = 0 ; i < MAX ; i++ )
          printf("value: %llu delta: %llu\n",vals[i],
             i ? vals[i]-vals[i-1] : 0);
    
      printf("=====\n");
    
      for ( i = 0 ; i < 100 ; i++ ) {
          thisval = rdtsc();
          printf("value: %llu delta: %llu\n",
             thisval, thisval - lastval);
          lastval = thisval;
      }
    
    }
    
[/code]

### 実行時間を測定したいプログラム

[code]

    #include<stdio.h>
    
    #define N 2
    int main(int argc, char *argv[])
    {
        double A[N][N] = {
            {1.0, 2.0},
            {2.0, 1.0}
        };
    
        double B[N][N] = {
            {3.0, 1.0},
            {0.0, 3.0}
        };
    
        double C[N][N] = {
            {0.0, 0.0},
            {0.0, 0.0}
        };
        int i, j, k;
    
        for(i=0; i<N; i++)
            for(j=0; j<N; j++)
                for(k=0; k<N; k++)
                    C[i][j] += A[i][k]*B[k][j];
    }
    
[/code]


CC BY-SA 4.0
2019-07-23T08:42:28.997
56840
2019-07-24T07:38:02.783
2020-06-17T08:14:45.997
-1
question
c
rdtsc命令で特定のプログラムの実行時間をクロック計測で求める方法について


短い答え

`RDTSC` で時間を計ることは極めて困難です。使わないことを強く推奨します。

長い答え

  * `RDTSC` はコアごとに違う値を得る

最近の Intel / AMD x86 CPU はたいていマルチコアとなっています。 `RDTSC`
の計測起点はコアごとに違うので、１つのコアに処理を固定しない限り得た値を比較する意味は **ない** です。

  * CPU の内部クロックによって変動する

最近の CPU は省電力のために内部クロックを増減させる、というか OS が増減させている、というか。すると `RDTSC`
のカウント速度もクロック周波数に応じて変化します (Intel 系のみという記事も見ましたがオイラ個人的には未確認）。時間計測に使っても意味がありません。

  * アウトオブオーダー対象

`RDTSC` はアウトオブオーダー対象命令です。つまり `RDTSC`
の前にある命令が完了するより先にカウンタ値を得ますし、後ろにある命令が既に実行済みであることもあります。精密な計時に使うには向きません。

[windows](/questions/tagged/windows "'windows' のタグが付いた質問を表示") かつ、最近のマシンなら
`HPET` があるので `QueryPerformanceCounter` のほうがマシです。実際に計測する前に
`QueryPerformanceCounter` が `HPET` を使っているかどうかを確認してください。

* * *

<https://stackoverflow.com/questions/464618/>  
によると OSX では `mach_absolute_time` と `mach_timebase_info` が最も近い代替品だそうです（オイラ Mac
持ってませんので未確認）。

この手のフリーランカウンターを使う際にはオーバーフローに注意が必要です。  
\- 常に、「経過時間＝現在値－過去値」を計算するようにします。  
\- 絶対に「将来値＝現在値＋所定時間」を計算してはいけません。

符号なし数の減算はオーバーフローしない（かつそのときの挙動を [c](/questions/tagged/c "'c' のタグが付いた質問を表示")
言語仕様書が決めている）ので前者は安全ですが、後者はオーバーフロー後の値の解釈を意識しないと４９日問題とか４９７日問題とかを発生させてしまいます。


CC BY-SA 4.0
2019-07-23T10:05:01.853
56843
2019-07-24T07:00:30.287
2019-07-24T07:00:30.287
8589
8589
56840
answer


> 実行環境はMacなのですが、rdtsc()の代わりとしてオススメの計測方法

参考までにC言語でなくC++言語であれば、[`std::chrono::high_resolution_clock`](https://ja.cppreference.com/w/cpp/chrono/high_resolution_clock)が提供されています。処理系が提供する高分解能タイマーを簡単に使用できます。例えばWindows環境であれば774RRさんの紹介された`QueryPerformanceCounter`が内部で使われます。


CC BY-SA 4.0
2019-07-24T07:38:02.783
56861
2019-07-24T07:38:02.783
4236
56840
answer