我使用 perf 作为基本事件计数器。我正在开发一个遭受数据缓存存储未命中的程序。比例高达%80。
我知道缓存原则上是如何工作的。它会在各种未命中情况下从内存加载,并在需要时从缓存中删除数据。我不明白的是:存储未命中和加载未命中之间有什么区别。它与加载和存储有何不同。怎样才能储存错过?
加载未命中(如您所知)是指处理器需要从主存中获取数据,但缓存中不存在数据。因此,每当处理器想要从主内存中获取一些数据时,它就需要缓存,如果数据已经加载,您将获得加载命中,否则您将获得加载未命中。
存储未命中与处理器何时要将新计算的数据写回主存有关。当要将数据写回主存时,必须确保缓存和主存的内容一致记忆是相互同步的。您可以在此处找到两种不同的政策,这可能会发生:Writing Policies。
所以无论你选择什么策略,你首先需要检查数据是否已经在缓存中,以便你可以先将其存储到缓存中(因为它更快),并且你要查找的数据块是否已从缓存中逐出缓存,您会得到与该缓存相关的存储未命中。
您可以查看这里的小程序,以更好地了解不同场景下会发生什么。
我并不完全熟悉 perf 如何定义这些事件,但考虑到通用定义,我相信加载/存储未命中只是分解总体未命中率计数的一种方法,以便您可以判断哪些访问更频繁地未命中。请注意,加载通常是推测性地执行(至少在现代 x86 cpu 中),而存储是在提交点之后沿着管道很晚才执行的,因此即使一段代码同时加载和存储到同一区域也可能有不同的未命中费率。
在基于 MESI 的缓存协议中,加载会命中缓存,或者错过并从内存或下一个缓存级别获取该行,如果它不属于其他任何人,则为独占状态,如果属于其他任何人,则处于共享状态。它会在此过程中将数据写入缓存。 商店将以相同的方式获取一行,但使用 RFO(读取所有权)请求,该请求授予它独占所有权和修改该行的权利。该行仍会被缓存,但一旦新数据写入本地(通常在 L1 缓存中),它就会被修改。不过,命中/未命中过程看起来是一样的。
Saman 在他的回答中提到的是读取和写入之间的故障。加载和存储(以及其他形式的访问,如代码读取)都形成“读取”部分,而写回(或使用特殊命令或内存类型(如不可缓存)的有意直写)形成“写入部分”。