Ste*_*wat 5 linux performance caching perf
我正在尝试将一些性能工程技术应用于Dijkstra算法的实现.为了找到(天真的和未经优化的)程序中的瓶颈,我正在使用该perf命令来记录缓存未命中的数量.相关的代码片段如下,它找到距离最小的未访问节点:
for (int i = 0; i < count; i++) {
if (!visited[i]) {
if (tmp == -1 || dist[i] < dist[tmp]) {
tmp = i;
}
}
}
Run Code Online (Sandbox Code Playgroud)
对于LLC-load-misses度量标准,perf report显示程序集的以下注释:
? for (int i = 0; i < count; i++) { ?
1.19 ? ff: add $0x1,%eax ?
0.03 ?102: cmp 0x20(%rsp),%eax ?
? ? jge 135 ?
? if (!visited[i]) { ?
0.07 ? movslq %eax,%rdx ?
? mov 0x18(%rsp),%rdi ?
0.70 ? cmpb $0x0,(%rdi,%rdx,1) ?
0.53 ? ? jne ff ?
? if (tmp == -1 || dist[i] < dist[tmp]) { ?
0.07 ? cmp $0xffffffff,%r13d ?
? ? je fc ?
0.96 ? mov 0x40(%rsp),%rcx ?
0.08 ? movslq %r13d,%rsi ?
? movsd (%rcx,%rsi,8),%xmm0 ?
0.13 ? ucomis (%rcx,%rdx,8),%xmm0 ?
57.99 ? ? jbe ff ?
? tmp = i; ?
? mov %eax,%r13d ?
? ? jmp ff ?
? } ?
? } ?
? }
Run Code Online (Sandbox Code Playgroud)
我的问题是:为什么jbe指令产生如此多的缓存未命中?如果我没有弄错的话,该指令根本不必从内存中检索任何内容.我认为它可能与指令缓存未命中有关,但即使只测量L1数据缓存未命中L1-dcache-load-misses,也表明该指令中存在大量缓存未命中.
这有点让我感到困惑.谁能解释这个(在我看来)奇怪的结果?先感谢您.
关于你的例子:
高柜台前和高柜台有几条指令:
? movsd (%rcx,%rsi,8),%xmm0
0.13 ? ucomis (%rcx,%rdx,8),%xmm0
57.99 ? ? jbe ff
Run Code Online (Sandbox Code Playgroud)
"movsd"将来自(%rcx,%rsi,8)(某些数组访问)的字加载到xmm0寄存器中,"ucomis"加载另一个字(%rcx,%rdx,8),并将其与xmm0寄存器中刚加载的值进行比较."jbe"是条件跳跃,取决于比较结果.
许多现代英特尔CPU(以及AMD可能也是)可以并且将把一些操作组合(realworldtech.com/nehalem/5"融合到单个uop,CMP + JCC中)"和cmp +条件跳转非常常见的指令要融合的组合(您可以使用Intel IACA模拟工具进行检查,对您的CPU使用ver 2.1).可以在perf/PMU/PEBS中错误地报告融合对,其中大多数事件偏向两个指令之一.
该代码可能意味着表达式"dist [i] <dist [tmp]"生成两个存储器访问,并且这两个值都用于ucomis与jbe条件跳转(部分?)融合的指令中.dist [i]或dist [tmp]或两个表达式都会产生大量未命中.任何这样的未命中将阻止ucomis生成结果并阻塞jbe以给出下一条指令以执行(或退出预测的指令).因此,jbe可能会获得高计数器的所有名声,而不是真正的内存访问指令(对于像"缓存"响应这样的"远"事件,会对最后一次阻塞指令产生一些偏差).
您可以尝试将已访问的[N]和dist [N]数组合并到数组[N]中,struct { int visited; float dist}以便array[i].dist在您访问时强制进行预取,array[i].visited或者您可以尝试更改顶点访问顺序,或重新编号图顶点,或者执行某些软件预取下一个或多个元素(?)
关于perf名称问题和可能的非核心倾斜的通用事件.
perfLinux中的(perf_events)工具在调用时使用预定义的事件集perf list,并且某些列出的硬件事件可能无法实现; 其他映射到当前的CPU功能(并且一些映射不完全正确).有关真实PMU的一些基本信息在您的https://software.intel.com/sites/products/collateral/hpc/vtune/performance_analysis_guide.pdf中(但它有关于相关Nehalem-EP变体的更多详细信息).
对于Nehalem(Intel Core i5 750,L3缓存为8MB,没有多CPU /多插槽/ NUMA支持),perf会将标准("通用缓存事件")LLC-load-misses事件映射为..."OFFCORE_RESPONSE.ANY_DATA.ANY_LLC_MISS"在perf事件映射(唯一的)的最佳文档中 - 内核源代码
http://elixir.free-electrons.com/linux/v4.8/source/arch/x86/events/intel/core.c#L1103
u64 nehalem_hw_cache_event_ids ...
[ C(LL ) ] = {
[ C(OP_READ) ] = {
/* OFFCORE_RESPONSE.ANY_DATA.LOCAL_CACHE */
[ C(RESULT_ACCESS) ] = 0x01b7,
/* OFFCORE_RESPONSE.ANY_DATA.ANY_LLC_MISS */
[ C(RESULT_MISS) ] = 0x01b7,
...
/*
* Nehalem/Westmere MSR_OFFCORE_RESPONSE bits;
* See IA32 SDM Vol 3B 30.6.1.3
*/
#define NHM_DMND_DATA_RD (1 << 0)
#define NHM_DMND_READ (NHM_DMND_DATA_RD)
#define NHM_L3_MISS (NHM_NON_DRAM|NHM_LOCAL_DRAM|NHM_REMOTE_DRAM|NHM_REMOTE_CACHE_FWD)
...
u64 nehalem_hw_cache_extra_regs
..
[ C(LL ) ] = {
[ C(OP_READ) ] = {
[ C(RESULT_ACCESS) ] = NHM_DMND_READ|NHM_L3_ACCESS,
[ C(RESULT_MISS) ] = NHM_DMND_READ|NHM_L3_MISS,
Run Code Online (Sandbox Code Playgroud)
我认为这个事件并不精确:cpu管道会将(无序)加载请求发布到缓存层次结构并执行其他指令.经过一段时间(大约10个周期到达并从L2获得响应并且40个周期达到L3)将在相应的(offcore?)PMU中有未命中标志的响应以增加计数器.在此计数器溢出时,将从此PMU生成分析中断.在几个cpu时钟周期中,它将到达管道中断它,perf_events子系统的处理程序将通过注册当前(中断的)EIP/RIP指令指针并将PMU计数器重置为某个负值来处理此问题(例如,-100000以获得每个中断)计算100000 L3未命中;用于perf record -e LLC-load-misses -c 100000设置精确计数或perf将自动调谐限制以获得一些默认频率).注册的EIP/RIP不是加载命令的IP,也可能不是要使用加载数据的命令的EIP/RIP.
但是如果您的CPU是系统中唯一的插槽并且您访问普通内存(而不是某些映射的PCI-express空间),则L3 miss实际上将实现为本地内存访问,并且有一些计数器...(https: //software.intel.com/en-us/node/596851 - "此处丢失的任何内存请求必须由本地或远程DRAM提供服务").
您的CPU有一些PMU事件列表:
官方英特尔的"英特尔®64和IA-32架构软件开发人员手册"(SDM):https://software.intel.com/en-us/articles/intel-sdm,第3卷,附录A
来自oprofile http://oprofile.sourceforge.net/docs/intel-corei7-events.php
showevtinfo http://www.bnikolic.co.uk/blog/hpc-prof-events.html(注意,此页面上有Sandy Bridge列表,请在您的PC上运行libpfm4 ant以获取您的列表).check_eventslibpfm4中还有一个工具可以帮助您将编码事件作为原始事件perf.ocperf来自Intel的perf开发人员Andi Kleen的工具,他的pmu工具https://github.com/andikleen/pmu-tools的一部分.ocperf只是perf and this package will download event description and any supported event name will be converted into correct raw encoding ofperf`的包装.应该有一些关于ANY_LLC_MISS offcore PMU事件实现的信息和Nhm的PEBS事件列表,但我现在找不到它.
我可以推荐你使用ocperf从https://github.com/andikleen/pmu-tools与CPU的任何PMU事件,而不需要手动进行编码.您的CPU中有一些PEBS事件,并且有延迟分析/ perf mem某种内存访问分析(一些随机性的性能pdf:2012年帖子"性能:添加内存访问抽样支持",RH 2013 - 第26-30页,仍然没有记录在2015年 - sowa pg19,ls /sys/devices/cpu/events).对于较新的CPU,有更新的工具,如ucevent.
我也建议你尝试使用GUI 的程序的cachegrindprofiler /缓存模拟器工具来查看配置文件.基于Valgrind的分析器可以帮助您了解代码的工作原理:它们为每条指令收集精确的指令执行计数,而cachegrind也模拟一些抽象的多级缓存.但是,真正的CPU将每个循环执行多个指令(以便,/ 1个指令= 1级的CPU时钟周期的成本模型给出了一些错误; cachegrind缓存模型具有不相同的逻辑实缓存).并且所有工具都是动态二进制检测工具,与本机运行相比,它会使程序速度降低20-30倍.valgrindkcachegrindcallgrindcachegrindvalgrind