10

キャッシュ サイズ (L1、L2、L3) を取得するプログラムを作成したいと考えています。私はそれの一般的な考えを知っています。

  1. 大きな配列を割り当てる
  2. 毎回異なるサイズの部分にアクセスします。

そこで、ちょっとしたプログラムを書きました。これが私のコードです:

#include <cstdio>
#include <time.h>
#include <sys/mman.h>

const int KB = 1024;
const int MB = 1024 * KB;
const int data_size = 32 * MB;
const int repeats = 64 * MB;
const int steps = 8 * MB;
const int times = 8;

long long clock_time() {
    struct timespec tp;
    clock_gettime(CLOCK_REALTIME, &tp);
    return (long long)(tp.tv_nsec + (long long)tp.tv_sec * 1000000000ll);
}

int main() {
    // allocate memory and lock
    void* map = mmap(NULL, (size_t)data_size, PROT_READ | PROT_WRITE, 
                     MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
    if (map == MAP_FAILED) {
        return 0;
    }
    int* data = (int*)map;

    // write all to avoid paging on demand
    for (int i = 0;i< data_size / sizeof(int);i++) {
        data[i]++;
    }

    int steps[] = { 1*KB, 4*KB, 8*KB, 16*KB, 24 * KB, 32*KB, 64*KB, 128*KB, 
                    128*KB*2, 128*KB*3, 512*KB, 1 * MB, 2 * MB, 3 * MB, 4 * MB, 
                    5 * MB, 6 * MB, 7 * MB, 8 * MB, 9 * MB};
    for (int i = 0; i <= sizeof(steps) / sizeof(int) - 1; i++) {
        double totalTime = 0;    
        for (int k = 0; k < times; k++) {
            int size_mask = steps[i] / sizeof(int) - 1;
            long long start = clock_time();
            for (int j = 0; j < repeats; j++) {
                ++data[ (j * 16) & size_mask ];
            }
            long long end = clock_time();
            totalTime += (end - start) / 1000000000.0;
        }
        printf("%d time: %lf\n", steps[i] / KB, totalTime);
    }
    munmap(map, (size_t)data_size);
    return 0;
}

ただし、結果は非常に奇妙です。

1 time: 1.989998
4 time: 1.992945
8 time: 1.997071
16 time: 1.993442
24 time: 1.994212
32 time: 2.002103
64 time: 1.959601
128 time: 1.957994
256 time: 1.975517
384 time: 1.975143
512 time: 2.209696
1024 time: 2.437783
2048 time: 7.006168
3072 time: 5.306975
4096 time: 5.943510
5120 time: 2.396078
6144 time: 4.404022
7168 time: 4.900366
8192 time: 8.998624
9216 time: 6.574195

私のCPUはIntel(R) Core(TM) i3-2350Mです。L1 キャッシュ: 32K (データ用)、L2 キャッシュ 256K、L3 キャッシュ 3072K。何のルールにも従わないようです。そこからキャッシュサイズやキャッシュレベルの情報を取得できません。誰か助けてくれませんか?前もって感謝します。

更新: @Leeor のアドバイスに従いj*64ますj*16。新しい結果:

1 time: 1.996282
4 time: 2.002579
8 time: 2.002240
16 time: 1.993198
24 time: 1.995733
32 time: 2.000463
64 time: 1.968637
128 time: 1.956138
256 time: 1.978266
384 time: 1.991912
512 time: 2.192371
1024 time: 2.262387
2048 time: 3.019435
3072 time: 2.359423
4096 time: 5.874426
5120 time: 2.324901
6144 time: 4.135550
7168 time: 3.851972
8192 time: 7.417762
9216 time: 2.272929
10240 time: 3.441985
11264 time: 3.094753

4096K と 8192K の 2 つのピーク。まだ奇妙です。

4

3 に答える 3

4

CPUID命令を見たほうがいいと思います。些細なことではありませんが、ウェブ上に情報があるはずです。

また、Windows を使用している場合は、GetLogicalProcessorInformation関数を使用できます。Windows XP SP3 以降にのみ存在することに注意してください。Linux/Unix については何も知りません。

于 2013-10-02T12:40:31.073 に答える
2

GNU/Linux を使用している場合は、ファイル/proc/cpuinfoの内容を読むだけでよく、詳細については/sys/devices/system/cpu/*を参照してください。UNIX では API を定義しないのが一般的であり、とにかくプレーン ファイルでその仕事を行うことができます。

util-linuxのソースも見てみましょう。これにはlscpuという名前のプログラムが含まれています。これは、必要な情報を取得する方法の例を示しているはずです。

//
http://git.kernel.org/cgit/utils/util-linux/util-linux.git/tree/sys-utils/lscpu.cを更新します

彼らのソースを見てみれば。基本的に、上記のファイルから読み取るだけです。したがって、そのファイルからも読み取ることは絶対に有効です。これらはカーネルによって提供されます。

于 2013-10-02T16:51:53.933 に答える