9

我正在尝试提出一个具有高缓存未命中率的示例程序。我想我可以尝试像这样逐列访问矩阵:

#include <stdlib.h>

int main(void)
{
    int i, j, k;

    int w = 1000;
    int h = 1000;

    int **block = malloc(w * sizeof(int*));
    for (i = 0; i < w; i++) {
        block[i] = malloc(h * sizeof(int));
    }

    for (k = 0; k < 10; k++) {
        for (i = 0; i < w; i++) {
            for (j = 0; j < h; j++) {
                block[j][i] = 0;
            }
        }
    }

    return 0;
}

当我用-O0标志编译它并使用它运行时,perf stat -r 5 -B -e cache-references,cache-misses ./a.out它给了我:

 Performance counter stats for './a.out' (5 runs):

    715,463 cache-references                                      ( +-  0.42% )
    527,634 cache-misses          #   73.747 % of all cache refs  ( +-  2.53% )

0.112001160 seconds time elapsed                                  ( +-  1.58% )

这对我的目的来说已经足够好了。但是,如果我继续并将矩阵大小更改为2000x2000它给出:

 Performance counter stats for './a.out' (5 runs):

  6,364,995 cache-references                                      ( +-  2.32% )
  2,534,989 cache-misses          #   39.827 % of all cache refs  ( +-  0.02% )

0.461104903 seconds time elapsed                                  ( +-  0.92% )

如果我进一步增加它,3000x3000我会得到:

 Performance counter stats for './a.out' (5 runs):

 59,204,028 cache-references                                      ( +-  1.36% )
  5,662,629 cache-misses          #    9.565 % of all cache refs  ( +-  0.11% )

1.116573625 seconds time elapsed                                  ( +-  0.32% )

这很奇怪,因为随着大小的增加,我希望获得更多的缓存未命中率。我需要尽可能独立于平台的东西。计算机体系结构课很久以前,所以任何见解都会受到欢迎。

笔记

我说我需要一些相对独立于平台的东西,但这些仍然是我的规格:

  • 英特尔® 酷睿™ i5-2467M
  • 4 GiB 内存
  • 64 位 Ubuntu 12.04
4

2 回答 2

9

当心现代 CPU 中的自动预取 - 它通常可以检测跨步访问。也许尝试随机访问模式,例如:

int main(void)
{
    int i;

    int n = 1000 * 1000;

    int *block = malloc(n * sizeof(int));

    for (i = 0; i < n / 10; i++) {
         int ri = rand() % n;
         block[ri] = 0;
    }

    return 0;
}
于 2013-01-31T21:44:41.007 回答
2

我不完全确定您可以比较这些程序或真正保证任何事情,因为这取决于操作系统如何分配单个内存块。

您至少应该将所有内存分配为单个块,然后索引到该块以获取所有数组(int*int)。这样你就有一个一致的起点。您可能希望将数组大小作为参数传递,而不是每次都重新编译。

您还可以对其进行调整,以便分配比您需要的内存更多的内存并放置每一行(或列,您编写它的方式),以保证矩阵的只有一行(列)将在任何时候加载到缓存中一度。 找出缓存的大小,并将每个块至少分开那么多字节。

请注意,您应该free在退出之前真正记住您的记忆。

正如其他人已经指出的那样,随机化您的访问模式是一个好主意。

于 2013-01-31T22:00:06.110 回答