如何清理L1、L2和L3缓存?

7

我正在进行一些缓存性能测试,需要确保缓存中没有任何“有用”的数据才能计时。

假设 L3 缓存大小为 10MB,是否创建一个大小为 10M/4 = 2,500,000 的浮点数向量,遍历整个向量,对数字进行求和即可清空先前存在于缓存中的所有数据?


如果您想清除缓存,只需通过一些与测试数据无关的数据即可。 - Mysticial
1
@Mysticial 嘿,Mystical,我的vector<float>的想法得到你的认可了吗?250万足够吗?我不确定因为缓存集合关联性的原因。 - user997112
是的,只需使用memset()函数清空任何大块连续内存即可。一些处理器具有哈希L3缓存。因此,由于冲突,恰好与缓存大小相同的连续内存块可能不足够。但我认为,通过拉取几百MB应该就足够了。 - Mysticial
2
问题和答案都是关于L3缓存的,但标题问的是L1/L2/L3。你应该知道L1和有时L2缓存是每个核心的,通过清除L3缓存,如果你的程序切换核心,仍然可能会遇到麻烦。 - Daniel Frey
3个回答

4

是的,这应该足以清除有用数据的L3缓存。

我做过类似类型的测量,并通过使用英特尔的缓存计数器进行交叉验证,以验证在我的测试期间我遇到了预期数量的L3缓存未命中。

如果你想要绝对确定,你也应该使用计数器。特别地,在大多数英特尔架构中,你可以使用“事件选择2EH,Umask 41H”来测量最后一级缓存未命中。

有关这些计数器的详细信息,请参见Intel手册


嗨@merlin2011,你可以分享一下你在某个网站上进行的测试并给我链接吗?我想尝试进行相同的测试来证明L3缓存被清空了,但我无法做到。 - Draxent

3

这取决于你为了获得保证愿意采取多么疯狂的方式。

x86_64 L3缓存是物理索引的,虽然在虚拟空间中以10MiB为单位的线性块几乎肯定会在轻载机器上物理连续,但无法保证。

例如,Sandy和Ivy Bridge将L3缓存划分为2MiB片段,并具有16路组相联(128kiB步幅),因此您可以通过进行MAP_HUGETLB mmap()调用来保证物理覆盖范围,假设使用标准的2-4MiB巨大页面。

此外,由于每个片段(至少在新的Sandy/Ivy Bridge上)都附加到不同的核心,并且给定物理地址位于哪个片段是由一些低/中序地址位的哈希确定的,所以您可能需要创建一个略大于L3大小的数组,以抵消微不足道的重叠。

此时,线性地多次擦除数组应该就可以解决问题。


0

另一个选择是使用一些ISA提供的专用缓存失效指令。例如,x86有wbinvd用于此目的(或clflush用于单行)。

http://x86.renejeschke.de/html/file_module_x86_id_325.html

一个问题是它需要 ring-0 权限。另一个问题是它不能保证刷新在任何序列化点之前完成,因此不能足够保证系统的不易失性,但只要您可以防止随后的 WB 占用您的内存带宽,这可能足够进行基准测试。
如果您能克服这些问题,在某些情况下,它可能比遍历一些大型数据结构来确保缓存被刷新更好。一些 CPU 可能会决定避免缓存未来不会再使用的取回操作(有关这些选项有几篇论文,并且至少有一些声称它已经实现在真实的 CPU 中)。

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