什么被认为是缓存中的高未命中率/低命中率?
Posted
技术标签:
【中文标题】什么被认为是缓存中的高未命中率/低命中率?【英文标题】:What is considered a high miss rate/low hit rate in caches? 【发布时间】:2018-04-25 14:47:14 【问题描述】:我一直在尝试分析我在机器上编写的一些代码作为小型内存测试,并通过使用 perf 我注意到:
Performance counter stats for './MemBenchmark':
15,980 LLC-loads
8,714 LLC-load-misses # 54.53% of all LL-cache hits
10.002878281 seconds time elapsed
基准测试的整个想法是“强调”内存,所以在我的书中,我认为我可以使未命中率越高。
编辑:Perf 中是否有允许将文件分析到不同部分的功能?例如如果 main() 包含三个 for 循环,是否可以单独分析每个循环以查看 LLC 加载未命中的数量?
【问题讨论】:
这可能取决于您的硬件 @BasileStarynkevitch 你会说哪些因素取决于我的硬件?在我的测试机器上,它有 i3-380M 和 6GB RAM 这取决于您的程序在内存访问方面的性能。如果您的程序在发生 L1 缓存未命中时受到 100 倍的性能影响,您可能希望命中率非常接近 100%,并且会竭尽全力让缓存充满正确的数据。如果性能命中率低得多,您也可以接受低得多的命中率。 【参考方案1】:请记住,LLC-loads 仅计算 L1d 和 L2 中丢失的负载。作为总负载 (L1-dcache-loads
) 的一小部分,这可能是整个缓存层次结构的非常良好的命中率(这要归功于良好的局部性和/或成功的预取。)
(Your CPU has a 3-level cache,所以最后一级是共享的 L3;L1 和 L2 是每个核心的私有缓存。在只有 2 级缓存的 CPU 上,LLC 是 L2。)
只有 9k 次访问必须一直到 DRAM 10 秒是非常非常好的。
LLC 总负载如此之低的低 LLC 命中率告诉您,您的工作负载对于其大部分访问具有良好的局部性,但未命中的访问通常必须一直到达 DRAM,并且只有一半他们完全受益于 L3 缓存。
相关:Cache friendly offline random read,并查看@BeeOnRope 在Understanding perf detail when comparing two different implementations of a BFS algorithm 上的回答,他说LLC 未命中的绝对数量是性能的重要因素。
局部性较差的算法会产生很多的 L2 未命中,并且通常会产生很多 L3 命中(很可能具有高 L3 命中率),但也会产生很多总的 L3 未命中,因此管道在等待内存的时间很多。
您建议用什么指标来衡量我的程序在强调内存方面的表现?
您想知道您的程序导致的总内存流量(包括预取)吗?即它可能对其他竞争内存带宽的程序产生什么样的影响? offcore_requests.all_requests
可以告诉您有多少请求(包括 L2 预取、页面遍历以及加载和存储,但不包括 L3 预取)通过 L2 到达共享 L3 缓存,无论它们是否在共享 L3 中命中。 (Use the ocperf.py
wrapper for perf
。我的 Skylake 有那个活动;如果你的 Nehalem 愿意,IDK。)
就检测您的代码是否存在内存瓶颈而言,以每秒LLC-load-misses
作为绝对衡量标准是合理的。 Skylake 至少有一个 cycle_activity.stalls_l3_miss
来计算没有执行 uops 并且有一个突出的 L3 未命中的周期。如果这超过总周期的百分之几,您需要考虑避免这些停顿。
(我自己没有尝试使用这些事件来学习任何东西,它们可能不是最有用的建议。在分析时很难知道要问自己的正确问题;有很多事件可以查看,但使用他们学习一些可以帮助您弄清楚如何更改代码的东西很难。对代码如何使用内存有一个很好的心理了解很有帮助,因此您知道要寻找什么。对于这样一个一般性的问题,很难多说。)
您是否可以建议一种方法来分解基准文件以查看哪些循环造成的压力最大?
您可以使用perf record -e whatever
/ perf report -Mintel
对您想要的任何事件进行基于统计样本的分析,以查看热点在哪里。
但是对于缓存未命中,有时责备在于一些循环遍历数组并驱逐大量有价值数据的代码,而不是涉及仍然很热的有价值数据的代码。
如果硬件预取完成它的工作,一个大数组上的循环可能不会看到很多缓存未命中。
linux perf: how to interpret and find hotspots。如果您不确切知道程序中什么是慢速和快速,则使用堆栈采样可能非常有用。对每个事件的调用堆栈进行采样将显示调用树中的哪个函数调用应为其被调用者所做的所有工作负责。一开始就避免该调用比稍微加快它调用的函数要好得多。
(避免工作,而不仅仅是用更好的蛮力做同样的工作。仔细应用现代 CPU 可以承受 AVX2 的最大蛮力是有用的你已经确定你一开始就无法避免这样做。)
【讨论】:
彼得,非常感谢您的详细回答。然而,我必须问你最后一个问题。从那以后,我已经在另一台机器上使用来自 LLC 的相同指标运行了它,只是现在我得到的所有 LL 缓存命中率不到 15%。你会认为这比我之前的测试差很多吗?我想我很困惑,就地点而言,较低是更好还是更差 @Jason:是的,这要低得多,但是对于程序性能而言并不重要的指标,因为绝对比率仍然很低。我假设第二台机器的 LLC 较小,但 L1/L2 尺寸相同。您的程序的大部分访问都具有很好的局部性(根本不会进入 LLC),而其他一些访问的局部性很差,因此当它们确实进入 LLC 时,它们通常会错过。 您建议用什么指标来衡量我的程序在强调内存方面的表现?有没有一种方法可以建议您分解基准文件以查看哪些循环造成的压力最大?谢谢! @Jason:编辑了我的答案并回复了您的评论。 一定去阅读linux perf: how to interpret and find hotspots以上是关于什么被认为是缓存中的高未命中率/低命中率?的主要内容,如果未能解决你的问题,请参考以下文章