8

编写一个程序并尝试比较(如果可以的话,测量)从主存和缓存访问数据的时间。

如果可以做到,那么如何衡量每一级缓存的速度呢?

4

3 回答 3

5

您需要提出一种启发式方法,强制 100%(或非常接近)缓存未命中(希望您有缓存失效操作码?)和 100% 缓存命中。万岁,适用于 1 级缓存。现在,如何为 2 级和 3 级做同样的事情?

严肃地说,如果没有连接到 CPU 和内存的特殊硬件和跟踪,可能无法 100% 可靠地做到这一点,但我会这样做:

将“一堆”内容写入内存中的 1 个位置 - 足以确保它始终如一地访问 L1 缓存并记录时间(这会影响您的缓存,因此请注意)。您应该在没有分支的情况下执行这组写入,以尝试消除分支预测不一致。那是最好的时机。现在,每隔一段时间,将缓存行的数据写入 RAM 中您已知位置右侧的随机遥远位置并记录新时间。希望这需要更长的时间。继续记录不同的时间,希望你会看到几个倾向于组合的时间。这些组中的每一个“可以”显示 L2、L3 和内存访问时序的时序。问题是有太多其他的东西阻碍了。操作系统可以上下文切换你并搞砸你的缓存。中断可能会出现并通过你的时间休息。将会有很多东西可以使价值观偏离。但是,希望您在数据中获得足够的信号来查看它是否有效。

在操作系统(如果有的话)不会妨碍您的更简单的嵌入式类型系统上,这可能会更容易做到。

于 2013-04-26T17:51:55.337 回答
3

这通常需要对缓存的“几何”和它的其他方面有一些了解。除了简单的用户访问和与实现相关的事情(例如比标准 Cclock机制提供的更精细的时序)之外,对系统进行一些控制也很有帮助。

这是一个初步的方法:

  • 编写一个例程,接收指向内存的指针、长度和重复次数,并以连续顺序重复读取所有内存。
  • 编写一个例程,该例程采用指向内存的指针、长度和重复次数,并以连续的顺序重复写入所有内存。
  • 上述例程可能必须将它们的指针转换为volatile以防止编译器优化掉否则无效的访问。
  • 分配大量内存。
  • 调用上面的每一个例程,每次调用前后获取当前时间,用各种长度调用可以看到不同长度的时间。

当您这样做时,您通常会看到小长度的速度(每秒读取/写入的字节数)和较长长度的较慢速度。当超过不同级别的缓存大小时,速度会降低。因此,您很可能会在使用上述技术收集的数据中看到 L1 和 L2 缓存的大小。

以下是方法不充分的一些原因:

  • 它不控制用于读取或写入缓存的指令。C 编译器可以很好地生成加载字和存储字指令,但是许多现代处理器的指令可以一次加载和存储 16 个字节,使用这些指令读取和写入可能比使用四字节字指令更快。
  • 当您按顺序访问时,缓存的行为与随机访问时不同。大多数缓存都会尝试跟踪何时使用数据,以便将最近使用的数据保留在缓存中,而将其他数据丢弃。实际程序的访问部分通常不同于上述的连续操作。
  • 特别是,对内存的连续写入可能会填满整个高速缓存行,因此不需要从内存中读取任何内容,而仅将一个字写入特定位置的实际使用模式可能必须通过读取来实现内存中的缓存行并合并到更改的字节中。
  • 来自系统上其他进程的竞争会干扰缓存中的内容和测量。
于 2013-04-26T18:01:14.057 回答
2

看看cachegrind-valgrind

Cachegrind 模拟您的程序如何与机器的缓存层次结构和(可选)分支预测器进行交互。它模拟具有独立的一级指令和数据缓存(I1 和 D1)的机器,由统一的二级缓存 (L2) 支持。这与许多现代机器的配置完全匹配。

看看这些很好的问题,它们在某种程度上是相关的:

  1. 如何以编程方式禁用硬件预取?
  2. 您一般如何从用户模式代码中检测缓存行关联性?
  3. 基准测试时如何使缓存无效?
于 2013-04-26T17:53:30.907 回答