如何用C语言编写一个程序来衡量缓存速度?

8

编写一个程序并尝试比较(如果可能的话)从主存和缓存中访问数据所需的时间。

如果你能做到这一点,那么如何测量每个级别缓存的速度呢?


3
这可行吗?缓存不受你的控制,你没办法知道数据是何时从哪里加载的。(好吧,也许你能追踪缓存未命中,但我猜测追踪开销会影响结果。) - millimoose
1
也许你应该相信,你可以非常快地从缓存中检索元素... - Grady Player
我的最佳猜测是在堆上分配多个内存块的巨大数组(>缓存大小),然后为您的测试读入每个“页面”。这将将页面(<缓存大小)拉到缓存中,然后执行操作。然后在随机选择的页面上执行一次,这可能不会在缓存中。看看需要多长时间。 - im so confused
另外,请记住,获取系统时间也可能会更改缓存的内容。因此,这也让您假设没有任何原因会导致您认为已缓存的页面被删除。 - millimoose
2
谷歌搜索缓存基准测试将会产生无数的结果,其中包括一些备受尊敬的缓存基准测试程序。 - High Performance Mark
显示剩余6条评论
3个回答

5
您需要想出一种启发式方法,以强制实现100%(或非常接近)的缓存未命中(希望您有一个缓存失效操作代码?),并且实现100%缓存命中。很好,这对第一层缓存可以起作用。现在,如何在二级和三级缓存中做到这一点?
说真的,可能没有一种方法可以百分之百地可靠地完成这个任务,除非使用特殊硬件和连接到CPU和内存的跟踪器。但是这是我会做的:
在内存中的一个位置写入足够多的数据,确保它始终命中L1缓存,并记录时间(这会影响您的缓存,所以要小心)。您应该在无需分支的情况下进行此组写入,以尽可能消除分支预测不一致性。这是最佳时间。现在,不时地向远离已知位置右侧的随机位置RAM中写入一个缓存行大小的数据,并记录新时间。希望这需要更长时间。不断重复此操作,记录各种时间,希望您能看到一些时间会聚成几组。每个组“可能”显示L2、L3和内存访问时间的时间。问题在于其他许多东西都会妨碍此过程。操作系统可能会切换上下文并破坏您的缓存。中断可能会来了,打乱您的计时。有许多东西可能会使值失真。但是,希望您在数据中获得足够的信号以查看它是否有效。
这在较简单的嵌入式系统上可能更容易完成,因为操作系统(如果有)不会妨碍您的工作。

但是如何测量一次读取数据的时间呢?它非常短,可能只有几纳秒! - Sayakiss
通过足够的尝试,你应该能够将计数器提高到毫秒级别。不过,我并没有说这很容易 :) - Michael Dorgan
但是在第一次执行后,它可能会被加载到缓存中(假设之前没有被加载过)。 - Sayakiss

3
这通常需要对缓存的“几何”和其他方面有一定了解。此外,拥有一些系统控制能力也很有帮助,超出简单用户访问它和比标准C时钟机制提供更精细时间等实现相关事物。
以下是一个初始方法:
编写一个例程,需要指向内存的指针、长度和重复次数,并按顺序读取所有的内存,重复这个过程。
编写一个例程,需要指向内存的指针、长度和重复次数,并按顺序将所有的内存写入,重复这个过程。
上述例程可能需要将它们的指针转换为易失性指针,以防止编译器优化掉没有效果的访问。
分配大量内存。
调用上述每个例程,在每次调用之前和之后获取当前时间,并使用各种长度调用,以查看不同长度的时间。
这样做,你通常会看到小长度的快速速度(每秒读/写字节数),而更长长度的速度较慢。当超过不同级别缓存的大小时,速度下降会发生。因此,使用上述技术收集的数据中很可能会反映L1和L2缓存的大小。
以下是该方法不足的一些原因:
它不能控制用于读取或写入缓存的指令。C编译器可能会生成load-word和store-word指令,但许多现代处理器具有可以一次加载和存储16个字节的指令,并且使用这些指令读取和写入可能比使用四个字节的word指令更快。
当您按顺序访问时,缓存的行为将与随机访问时不同。大多数缓存都会尝试跟踪数据何时被使用,以便最近使用的数据保留在缓存中,而其他数据则被弃用。实际程序的访问部分通常与上述连续操作不同。
特别是,对内存的连续写入可能能够填充整个缓存行,因此不需要从内存读取任何内容,而只写入一个单词到特定位置的实际使用模式可能需要从内存读取缓存行并合并更改的字节。
来自系统中其他进程的竞争将干扰缓存内容和测量。

2

1
啊,如果仿真的质量足够好,那么仿真可能是一个更好的选择。好主意。 - Michael Dorgan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接