英特尔 PMU 能否用于测量每核读/写内存带宽使用情况?这里的“内存”是指 DRAM(即,不命中任何缓存级别)。
5 回答
是的(ish),间接的。您可以使用计数器之间的关系(包括时间戳)来推断其他数字。例如,如果您对 1 秒的间隔进行采样,并且有 N 个最后一级 (3) 缓存未命中,则您可以非常确信每秒占用了 N*CacheLineSize 个字节。
将其准确地与程序活动相关联会变得有点棘手,因为这些未命中可能反映了 cpu 预取、中断活动等。
还有一个“除非此配置位处于此状态,否则此 cpu 不算数(MMX,SSE,AVX,..)”的泥潭;因此自己滚动很麻烦....
核心外响应性能监控工具可用于计算IDI 上来自特定核心的所有核心发起请求。请求类型字段可用于统计特定类型的请求,例如需求数据读取。然而,为了测量每核内存带宽,请求的数量必须以某种方式转换为每秒字节数。大多数请求具有高速缓存行大小,即 64 字节。其他请求的大小可能未知,并且可能会向内存带宽添加小于或大于高速缓存行大小的字节数。其中包括高速缓存行分割锁定请求、WC 请求、UC 请求和 I/O 请求(但这些不会增加内存带宽),以及需要完成所有挂起写入的围栏请求MFENCE
(SFENCE
和序列化指令)。
如果您只对可缓存带宽感兴趣,那么您可以计算可缓存请求的数量并将其乘以 64 字节。这可能非常准确,假设可缓存的高速缓存行拆分锁定请求很少见。不幸的是,从 L3(或 L4,如果可用)到内存的回写不能被当前任何微架构上的核心响应设施计算。原因是这些写回不是源自核心,通常是由于 L3 中的冲突未命中而发生的。因此,可以计算在 L3 中丢失并导致回写的请求,但核心外响应工具无法让您确定对 L3(或 L4)的任何请求是否导致回写。这就是为什么不可能“按核心”计算回写到内存的原因。
此外,核心外响应事件需要一个可编程的性能计数器,该计数器是 0、1、2 或 3 之一(但在禁用 hyptherhtreading 时不是 4-7)。
英特尔至强 Broadwell 支持许多资源控制器技术 (RDT) 功能。特别是,它支持内存带宽监控(MBM),这是准确测量每个内核的内存带宽的唯一方法。
MBM 与非核心响应相比具有三个优势:
- 它使您能够测量一个或多个使用资源 ID 标识的任务的带宽,而不仅仅是每个内核。
- 它不需要通用可编程性能计数器之一。
- 它可以准确测量本地或总带宽,包括回写到内存。
非核心响应的优点是它支持请求类型、供应商类型和窥探信息字段。
Linux 从内核版本 4.6开始支持 MBM 。在 4.6 到 4.13 上,MBM 事件支持perf
使用以下事件名称:
intel_cqm_llc/local_bytes - bytes sent through local socket memory controller
intel_cqm_llc/total_bytes - total L3 external bytes sent
也可以通过编程方式访问这些事件。
从4.14开始,Linux 中 RDT 的实现发生了显着变化。
在运行内核版本 4.16 的 BDW-E5(双套接字)系统上,我可以使用以下命令序列查看 MBM 的字节数:
// Mount the resctrl filesystem.
mount -t resctrl resctrl -o mba_MBps /sys/fs/resctrl
// Print the number of local bytes on the first socket.
cat /sys/fs/resctrl/mon_data/mon_L3_00/mbm_local_bytes
// Print the number of total bytes on the first socket.
cat /sys/fs/resctrl/mon_data/mon_L3_00/mbm_total_bytes
// Print the number of local bytes on the second socket.
cat /sys/fs/resctrl/mon_data/mon_L3_01/mbm_local_bytes
// Print the number of total bytes on the second socket.
cat /sys/fs/resctrl/mon_data/mon_L3_01/mbm_total_bytes
我的理解是自系统重置后计算字节数。
请注意,默认情况下,被监视的资源是整个套接字。
不幸的是,包括 MBM 在内的大多数 RDT 功能在支持它的 Skylake 处理器上都存在缺陷。根据SKZ4和SKX4:
英特尔® 资源控制器技术 (RDT) 内存带宽监控 (MBM) 不计算本地内存的可缓存回写流量。这会导致 RDT MBM 功能计算消耗的总带宽不足。
这就是为什么在 Linux 上运行 Skylake-X 和 Skylake-SP(它们是唯一支持 MBM 的 Skylake 处理器)时默认禁用它的原因。您可以通过将以下参数 rdt=mbmtotal,mbmlocal
添加到内核命令行来启用 MBM。某些寄存器中没有启用或禁用 MBM 或任何其他 RDT 功能的标志。相反,这是在内核中的某些数据结构中跟踪的。
在 Intel Core 2 微架构上,可以使用此处BUS_TRANS_MEM
讨论的事件来测量每个内核的内存带宽。
是的,这是可能的,尽管它不一定像编程通常的 PMU 计数器那样简单。
一种方法是使用通过 PCI 空间访问的可编程存储器控制器计数器。一个好的起点是pcm-memory
在pcm-memory.cpp中检查英特尔自己的实现。这个应用程序向您展示了每个插槽或每个内存控制器的吞吐量,这适用于某些用途。特别是,带宽在所有内核之间共享,因此在安静的机器上,您可以假设大部分带宽与被测进程相关联,或者如果您想在套接字级别进行监控,这正是您想要的。
另一种选择是使用“offcore repsonse”计数器的仔细编程。据我所知,这些与 L2(最后一个核心私有缓存)和系统其余部分之间的流量有关。您可以按核心响应的结果进行过滤,因此您可以使用各种“L3 未命中”事件的组合并乘以高速缓存行大小来获得读取和写入带宽。这些事件的粒度非常细,因此您可以通过首先导致访问的原因进一步分解它:指令获取、数据需求请求、预取等。
非核心响应计数器通常落后于工具等工具的支持perf
,likwid
但至少最近的版本似乎有合理的支持,即使对于像 SKL 这样的客户端部件也是如此。
在某些架构上,perf
您可以访问内存控制器的非核心 PMU 计数器。
$ perf list
[...]
uncore_imc_0/cas_count_read/ [Kernel PMU event]
uncore_imc_0/cas_count_write/ [Kernel PMU event]
uncore_imc_0/clockticks/ [Kernel PMU event]
[...]
然后:
$ perf -e "uncore_imc_0/cas_count_read/,uncore_imc_0/cas_count_write/" <program> <arguments>
将报告从内存控制器#0 的读取和写入操作中从主内存传输到缓存的字节数。将该数字除以使用的时间,就可以得到所使用的平均内存带宽的近似值。
我不确定英特尔 PMU,但我认为您可以使用英特尔 VTune 放大器(https://software.intel.com/en-us/intel-vtune-amplifier-xe)。这个有很多性能监控工具(内存、cpu缓存、cpu)。也许这对你有用。