如何从 Java 进程中找到 L1 缓存行的大小?

Posted

技术标签:

【中文标题】如何从 Java 进程中找到 L1 缓存行的大小?【英文标题】:How do I find the size of the L1 cache lines from within a Java process? 【发布时间】:2013-06-27 23:35:18 【问题描述】:

我对微调缓存感知数据结构(例如,参见 Michael Spiegel's dissertation 或 Herlihy 等人的 hopscotch hashing 中的无锁跳过树)以及防止 false sharing 感兴趣。在并发数组处理期间。我已经知道如何通过“sun.arch.data.model”属性找到 JVM 指针大小,但我一直无法找到确定 L1 缓存中缓存行大小的方法。

请注意,此信息并不重要,因为我可以继续对 L1 行大小使用保守估计(微调缓存敏感数据结构时为 64 字节,或防止错误共享时为 256 字节);不过如果L1缓存属性很容易获取,那我不妨利用一下。

【问题讨论】:

我认为这个(非常有趣,我什至会说令人兴奋)任务的实施成本太高。我会在这里做一件懒惰的事情:硬编码 CPU 模型的缓存大小,并确定它 - 因为它可能碰巧更容易。但是,如果 JVM 在隐藏实际 CPU 模型的某种 VM 中运行,则可能会出错,而您的解决方案将针对该场景使用正确的大小... 行号为行号;在什么意义上它曾经是 64 256? @OliCharlesworth 如果我不知道精确的线条大小,那么我会根据我想要完成的任务使用不同的估计值,例如如果我正在微调一个缓存感知数据结构,那么我将使用 64 字节的较低估计值,因为这样如果实际行大小大于 64 字节,并且如果我是防止错误共享,然后我将使用 256 字节的更高估计值,因为如果实际行大小小于 256 字节,这仍然会表现良好。 【参考方案1】:

您可以做一个简单的循环,以给定的步幅从内存中读取单个字节。如果步幅为 1(字节),则每次迭代都必须支付一次取行罚款。如果你加倍跳过,你可以期待一半的性能,因为你现在每相同数量的迭代获取一行两次。

一旦您的步幅达到缓存线大小,您应该会看到性能降级停止,因为您将达到每次迭代获取一行的级别,并且再次将步幅加倍不会改变它,您会跳过行。这样做的一个问题是,您可能会在 CPU 中触发硬件流预取器,并在某个较低的缓存级别提前让线路等待您,所以我希望看到斜率减小,但不会完全变直。以两倍于缓存行大小的步幅,这可能会消失,因为您可以通过比它们更快来摆脱某些流预取器(仍然可能有步幅预取器“帮助”您进一步,但影响应该会小得多)。

另外请记住,您的代码应该在比最后一级缓存更大的数据集(例如数组)上运行,几 MB 就足够了。

【讨论】:

以上是关于如何从 Java 进程中找到 L1 缓存行的大小?的主要内容,如果未能解决你的问题,请参考以下文章

Java IO流之字符缓冲流

查找Java字节数组的缓存行的开头

如何在现代 x86/amd64 芯片上关闭 L1、L2、L3 CPU 缓存?

进程缓存和缓存服务,如何抉择?

clflush 是不是刷新 L1i?

java多线程和硬件内存之间关系