38

作为一项学校作业,我需要找到一种方法来获取 L1 数据缓存行大小,而无需读取配置文件或使用 api 调用。应该使用内存访问读/写时序来分析和获取此信息。那么我该怎么做呢?

在对分配的另一部分进行的不完整尝试中,为了找到缓存的级别和大小,我有:

for (i = 0; i < steps; i++) {
    arr[(i * 4) & lengthMod]++;
}

我在想也许我只需要改变第 2 行,(i * 4)部分?所以一旦我超过缓存行大小,我可能需要更换它,这需要一些时间?但就这么简单吗?所需的块可能已经在内存中的某个地方?或者,我仍然可以指望这样一个事实,即如果我有足够大的steps,它仍然会非常准确地工作?

更新

继承人在 GitHub 上的尝试 ......下面的主要部分

// repeatedly access/modify data, varying the STRIDE
for (int s = 4; s <= MAX_STRIDE/sizeof(int); s*=2) {
    start = wall_clock_time();
    for (unsigned int k = 0; k < REPS; k++) {
        data[(k * s) & lengthMod]++;
    }
    end = wall_clock_time();
    timeTaken = ((float)(end - start))/1000000000;
    printf("%d, %1.2f \n", s * sizeof(int), timeTaken);
}

问题是时间之间似乎没有太大差异。供参考。因为它用于 L1 缓存。我有 SIZE = 32 K(数组大小)

4

8 回答 8

29

分配一个 BIGchar数组(确保它太大而无法放入 L1L2 缓存)。用随机数据填充它。

n开始以字节为单位遍历数组。对检索到的字节做一些事情,比如对它们求和。

基准测试并计算您可以使用不同的值处理多少字节/秒n,从 1 开始计数到 ​​1000 左右。确保您的基准测试打印出计算的总和,因此编译器不可能优化基准测试代码。

n== 您的缓存行大小时,每次访问都需要将新行读入 L1 缓存。因此,基准测试结果在这一点上应该会变得非常缓慢。

如果数组足够大,当你到达末尾时,数组开头的数据已经再次超出缓存,这就是你想要的。因此,在您增加n并重新开始之后,结果不会受到缓存中已经存在所需数据的影响。

于 2012-10-01T14:54:11.937 回答
6

看看Calibrator,所有作品都受版权保护,但源代码是免费提供的。从它的文档想法来计算缓存行大小听起来比这里已经说过的更有教育意义。

我们的校准工具背后的想法是有一个微基准,其性能仅取决于发生的缓存未命中的频率。我们的校准器是一个简单的 C 程序,主要是一个执行一百万次内存读取的小循环。通过改变步幅(即两个后续内存访问之间的偏移量)和内存区域的大小,我们强制改变缓存未命中率。

原则上,缓存未命中的发生由数组大小决定。一旦数据加载到缓存中,适合 L1 缓存的数组大小不会产生任何缓存未命中。类似地,超过 L1 缓存大小但仍适合 L2 的数组将导致 L1 未命中但不会导致 L2 未命中。最后,大于 L2 的数组会导致 L1 和 L2 未命中。

缓存未命中的频率取决于访问步幅和缓存行大小。步长等于或大于缓存行大小时,每次迭代都会发生缓存未命中。步幅小于缓存行大小时,缓存未命中仅每 n 次迭代(平均)发生一次,其中 n 是缓存行大小/步幅的比率。

因此,我们可以通过比较没有未命中的执行时间与每次迭代恰好有一个未命中的执行时间来计算缓存未命中的延迟。这种方法只有在内存访问是纯顺序执行的情况下才有效,也就是说,我们必须确保两个或更多的加载指令和内存访问和纯 CPU 工作都不能重叠。我们使用一个简单的指针追踪机制来实现这一点:我们访问的内存区域被初始化,这样每次加载都返回下一次迭代中后续加载的地址。因此,超标量 CPU 无法从其通过推测执行隐藏内存访问延迟的能力中受益。

为了测量缓存特性,我们多次运行实验,改变步幅和数组大小。我们确保步幅至少在 4 字节和最大预期缓存行大小的两倍之间变化,并且数组大小从最小预期缓存大小的一半变化到至少最大预期缓存大小的十倍。

我必须注释掉#include "math.h"它才能编译它,之后它正确地找到了我的笔记本电脑的缓存值。我也无法查看生成的 postscript 文件。

于 2012-10-11T20:00:58.663 回答
3

您可以CPUID在汇编程序中使用该功能,虽然不可移植,但它会给您想要的。

对于 Intel 微处理器,可以通过调用 cpuid 函数 0x1 后将 bh 乘以 8 来计算高速缓存行大小。

对于 AMD 微处理器,调用 cpuid 函数 0x80000005 后,数据缓存线大小在 cl 中,指令缓存线大小在 dl 中。

我从这里的这篇文章中得到了这个。

于 2012-10-11T11:40:10.293 回答
2

我认为您应该编写程序,它将以随机顺序而不是直接遍历数组,因为现代进程执行硬件预取。例如,制作 int 数组,其中值将是下一个单元格的编号。1 年前我做过类似的程序http://pastebin.com/9mFScs9Z 对不起我的英语,我不是母语人士。

于 2012-10-07T17:30:31.007 回答
1

看看 memtest86 是如何实现的。他们以某种方式测量和分析数据传输率。速率变化点对应于 L1、L2 的大小和可能的 L3 缓存大小。

于 2012-10-01T15:04:22.943 回答
1

如果你被困在泥泞中无法脱身,请看这里

有手册和代码解释了如何做你所要求的。代码质量也很高。查看“子程序库”。

代码和手册基于 X86 处理器。

于 2012-10-02T09:32:55.303 回答
0

我认为对使用一些内存的操作进行计时应该足够了。然后逐步增加操作使用的内存(例如操作数)。当操作性能严重下降时,您已经找到了极限。

我会只读取一堆字节而不打印它们(打印会影响性能,以至于会成为瓶颈)。读取时,时间应该与读取的字节量成正比,直到数据不再适合 L1,然后您将获得性能打击。

您还应该在程序开始时和开始计算时间之前分配一次内存。

于 2012-10-01T14:25:58.633 回答
0

只是一个注释。

缓存行大小在少数 ARM Cortex 系列上是可变的,并且可以在执行期间更改,而无需通知当前程序。

于 2018-05-12T14:27:24.563 回答