【问题标题】:How to find the size of the L1 cache line size with IO timing measurements?如何通过 IO 时序测量找到 L1 缓存线大小的大小?
【发布时间】:2012-09-22 09:49:37
【问题描述】:

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

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

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

我在想也许我只需要改变第 2 行,(i * 4) 部分?所以一旦我超过缓存行大小,我可能需要更换它,这需要一些时间?但就这么简单吗?所需的块可能已经在内存中的某个地方?或者,如果我有足够大的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(数组大小)

【问题讨论】:

  • 添加了 C 标签 - @JiewMeng,也许你会确认你确实是用 C 写的。我已经删除了 homework 标签(根据meta.stackexchange.com/questions/147100/…
  • @DanPuzey,是的,它的 C 或 C++ ...
  • 谷歌“缓存基准测试”,做一些研究。
  • 您可以使用汇编,然后使用 CPUID 指令(它是处理器指令,而不是 API)来获取此信息。我知道你可能不是在寻找这样的解决方案,但无论如何我认为值得分享......
  • This question 可能会给你一些想法。它不测量缓存大小,但确实显示每个缓存级别的性能显着下降。

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


【解决方案1】:

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

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

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

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

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

【讨论】:

  • 可能硬件预取会计算出'n'的步骤,并会在你之前加载。
  • 我认为这个想法应该可行,但是尝试以随机方式采取 n 步以避免预取,例如 n + (r * c),其中 c 是 2 的幂值大于可能的缓存线大小和 r 是一个随机值。您需要确保 n + (r * c) 在您的数组中,可能使用模数。
  • 我想做一些假设也是公平的,比如缓存行大小必须是 2 的幂,至少 32 字节,最大 512 字节。
  • 您的 data 数组只有 32KB,所以整个东西都适合 L1 缓存。请注意我上面说的第一件事:“分配一个 BIG char 数组。确保它太大而无法放入 L1 或 L2 缓存。”。
  • @JiewMeng,我现在不发布我的代码,因为您将通过弄清楚如何自己修复代码来了解更多信息。你搞清楚后,我可以把我的代码发给你比较。
【解决方案2】:

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

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

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

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

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

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

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

【讨论】:

  • 对于我的机器 (Haswell) 校准器预测线大小不正确,@AlexD 的方法也不起作用。问题在于预取器,它设法猜测恒定步幅模式并欺骗实验。我想这可以通过禁用预取器来衡量
【解决方案3】:

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

对于 Intel 微处理器,可以在调用 cpuid 函数 0x1 后将 bh 乘以 8 来计算 Cache Line Size。

对于AMD微处理器,调用cpuid函数0x80000005后,数据Cache Line Size在cl,指令Cache Line Size在dl。

我从这个article here 中得到这个。

【讨论】:

    【解决方案4】:

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

    【讨论】:

      【解决方案5】:

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

      【讨论】:

      • 较大阵列的内存带宽下降可以告诉您L1d / L2 / L3的总大小,但这个问题是询问每行的大小,即缓存块大小。
      【解决方案6】:

      如果你陷入泥潭出不来,请看here

      有手册和代码解释了如何按照您的要求进行操作。代码质量也很高。查看“子程序库”。

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

      【讨论】:

        【解决方案7】:

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

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

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

        【讨论】:

        • 他的任务不是求L1缓存的大小,而是求L1中一个cache line的大小。
        【解决方案8】:

        只是一个注释。

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

        【讨论】:

          猜你喜欢
          • 2015-02-07
          • 2013-06-27
          • 2013-01-20
          • 2021-11-27
          • 2015-10-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-02-20
          相关资源
          最近更新 更多