如何通过IO时序测量找到L1缓存行大小的大小?

时间:2012-10-01 14:19:09

标签: c++ c performance caching cpu-architecture

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

在对作业的另一部分进行不完整的尝试时,找到等级&缓存的大小,我有:

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

我想也许我只需要改变第2行,(i * 4)部分?所以一旦我超过缓存行大小,我可能需要更换它,这需要一些时间?但它是如此直截了当?所需的块可能已经存在于内存中?或者perpahs我仍然可以依靠这样一个事实,即如果我有一个足够大的steps,它仍然可以非常准确地运作?

更新

Heres an attempt on 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(数组大小)

8 个答案:

答案 0 :(得分:27)

分配一个BIG char阵列(确保它太大,不适合L1 L2缓存)。用随机数据填写。

开始以n字节为步长遍历数组。使用检索到的字节执行某些操作,例如对它们进行求和。

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

n ==您的缓存行大小时,每次访问都需要在L1缓存中读取新行。所以基准测试结果在这一点上会变得非常缓慢。

如果数组足够大,那么当你到达终点时,数组开头的数据将再次超出缓存,这就是你想要的。因此,在您递增n并重新开始后,结果将不会受到缓存中已有数据的影响。

答案 1 :(得分:5)

查看Calibrator,所有作品均受版权保护,但source code可免费使用。从其document想法来计算缓存行大小听起来比那里已经说过的更有教养。

  
    

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

         

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

         

缓存未命中的频率取决于访问跨度和缓存行大小。大踏步前进     等于或大于高速缓存行大小,每次迭代都会发生高速缓存未命中。大踏步前进     如果小于高速缓存行大小,则仅在每n次迭代(平均)中发生高速缓存未命中,其中n为     比率缓存     线     大小/步幅。

         

因此,我们可以通过比较执行时间来计算缓存未命中的延迟     每次迭代只错过一次错过执行时间。 此方法仅适用于     内存访问是纯粹顺序执行的,即我们必须确保两个或两个以上的加载     指令,内存访问和纯CPU工作可以重叠。我们使用简单的指针追逐     实现此目的的机制:我们访问的内存区域被初始化,以便每个负载返回     下一次迭代中后续加载的地址。因此,超标量CPU无法从中受益     他们通过推测性执行隐藏内存访问延迟的能力。

         

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

  

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

答案 2 :(得分:3)

您可以在汇编程序中使用CPUID函数,虽然不可移植,但它会为您提供所需的内容。

  

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

     

对于AMD微处理器,数据高速缓存行大小在cl中,并且在调用cpuid函数0x80000005之后指令高速缓存行大小为dl。

我从article here获取了这个。

答案 3 :(得分:2)

我认为你应该编写程序,它将以随机顺序直接遍历数组,因为现代流程会进行硬件预取。 例如,make int of int,其值将是下一个单元格的数量。 我做了类似的程序1年前http://pastebin.com/9mFScs9Z 对不起我的英语,我不是母语。

答案 4 :(得分:1)

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

答案 5 :(得分:1)

如果你陷入困境并且无法离开,请查看here

有手册和代码可以解释如何做你要问的事情。代码质量也很高。看看“子程序库”。

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

答案 6 :(得分:0)

我认为应该对使用一定量内存的操作进行计时。然后逐步增加操作使用的内存(例如操作数)。 当操作性能急剧下降时,您已找到限制。

我只需要阅读一堆字节而不打印它们(打印会使性能如此糟糕,以至于会成为瓶颈)。在读取时,时间应该与读取的字节数直接成比例,直到数据不再适合L1,然后你将获得性能损失。

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

答案 7 :(得分:0)

只是一张纸条。

高速缓存行大小在少数ARM Cortex系列中是可变的,并且可以在执行期间更改,而不会向当前程序发送任何通知。