1

http://igoro.com/archive/gallery-of-processor-cache-effects/によると、例 2 を試している間、オフセットがキャッシュ ライン zie に等しくなるまで時間がかかるはずです。
ただし、私のマシンでは機能しません。
コードは次のようなものです。

#define SIZE 1024*1024*64

int main()
{
struct timeval start, end;
int k;
int i;

for(k = 1; k <= 1024; k *= 2)
{

    int *arr = (int*)malloc(SIZE * sizeof(int));
    gettimeofday(&start, NULL);
    for(i = 0; i < SIZE; i += k)
        arr[i] *= 3;
    gettimeofday(&end, NULL);

    printf("K = %d, time = %d\n", k,
            (end.tv_sec - start.tv_sec)*1000000 + (end.tv_usec - start.tv_usec));

    free(arr);
}
return 0;
}

結果は次のようになります。

K = 1、時間 = 410278
K = 2、時間 = 265313
K = 4、時間 = 201540
K = 8、時間 = 169800
K = 16、時間 = 155123
K = 32、時間 = 142496
K = 64、時間 = 137967
K = 128、時間 = 135818
K = 256、時間 = 135128
K = 512、時間 = 135167
K = 1024、時間 = 135462

4

2 に答える 2

2

これは、コンパイラ(そのバージョン)、最適化レベル、および CPU によって異なります。どうやら、ほとんどの時間が費やされmallocているので、ループから移動して を増やしSIZEました。

16G バイトの RAM を搭載した i3770K プロセッサで GCC 4.8.1 を使用して Debian/Sid を試しています。

#include <stdio.h>
#include <stdlib.h> 
#include <sys/time.h>
#include <time.h>
#define SIZE 1024*1024*1024

int main ()
{
  struct timeval start, end;
  clock_t startcl, endcl;
  int k, i;

  int *arr = (int *) malloc (SIZE * sizeof (int));
  if (!arr) { perror("malloc"); exit(EXIT_FAILURE); };
  for (k = 1; k <= 1024; k *= 2)  {
      gettimeofday (&start, NULL);
      startcl = clock();
      for (i = 0; i < SIZE; i += k)
        arr[i] *= 3;
      gettimeofday (&end, NULL);
      endcl = clock();
      printf ("K = %d, time = %ld, cpu clock=%ld microsec\n", k,
              (end.tv_sec - start.tv_sec) * 1000000 
              + (end.tv_usec - start.tv_usec),
              (long) (endcl - startcl));
    }
  free (arr);
  return 0;
}   

そしてそれをコンパイルしてgcc -Wall -mtune=native -O3 ./wilsonwen.c -o ./wilsonwen-O3実行します:

K = 1, time = 696074, cpu clock=680000 microsec
K = 2, time = 361173, cpu clock=360000 microsec
K = 4, time = 341920, cpu clock=340000 microsec
K = 8, time = 341767, cpu clock=340000 microsec
K = 16, time = 342065, cpu clock=340000 microsec
K = 32, time = 224502, cpu clock=230000 microsec
K = 64, time = 119544, cpu clock=120000 microsec
K = 128, time = 51089, cpu clock=50000 microsec
K = 256, time = 26447, cpu clock=20000 microsec
K = 512, time = 14104, cpu clock=20000 microsec
K = 1024, time = 8385, cpu clock=10000 microsec

これは、あなたが言及したブログとより一致しています。malloc外側のループの外に移動することは非常に重要です (そうしないと、基盤となるシステムコールがかなりの時間を消費してkいるため、キャッシュ効果が見られません)。mallocmmap

時間がかかる理由を説明できませんk=1(おそらく、malloc-ed メモリがページ フォールトによって RAM に取り込まれるためですか?)。for (i=0; i<SIZE/1024; i++) arr[i] = i;ループの前に「ページをプリフェッチ」するループを追加しても、for (kfor の時間は for のk=1約 2 倍ですk=2。Igor Ostrovsky のブログで言及されているk=2toの高原が見られます。k=16で置き換えることはあまり重要mallocではありません。コンパイルに (4.8) の代わりに (3.2)callocを使用すると、非常に類似したタイミング結果が得られます。clanggcc

最適化は非常に重要です。 を試してgcc -Wall -O0 ./wilsonwen.c -o ./wilsonwen-O0実行すると、プラトーが表示されなくなります (これは を使用しても表示されます-O1)。gcc最適化フラグがないと非常に貧弱なマシンコードが吐き出されることはよく知られています。

ベンチマークの一般的なルールは、コンパイラの最適化を有効にすることです。

于 2013-07-29T02:35:50.967 に答える