【发布时间】:2018-05-16 16:59:23
【问题描述】:
英特尔 PMU 能否用于测量每核读/写内存带宽使用情况?这里的“内存”指的是 DRAM(即,不命中任何缓存级别)。
【问题讨论】:
标签: performance x86 intel-pmu memory-bandwidth
英特尔 PMU 能否用于测量每核读/写内存带宽使用情况?这里的“内存”指的是 DRAM(即,不命中任何缓存级别)。
【问题讨论】:
标签: performance x86 intel-pmu memory-bandwidth
是的(ish),间接的。您可以使用计数器之间的关系(包括时间戳)来推断其他数字。例如,如果您对 1 秒的间隔进行采样,并且有 N 个最后一级 (3) 缓存未命中,那么您可以非常确定每秒占用了 N*CacheLineSize 个字节。
将其准确地与程序活动关联起来会有点棘手,因为这些未命中可能反映了 cpu 预取、中断活动等。
还有一个“除非这个配置位处于这个状态,否则这个 cpu 不算数(MMX、SSE、AVX、..)”的泥潭;因此自己滚动很麻烦....
【讨论】:
是的,这是可能的,尽管它不一定像编程通常的 PMU 计数器那样简单。
一种方法是使用通过 PCI 空间访问的可编程内存控制器计数器。一个好的起点是在pcm-memorypcm-memory.cpp 中检查英特尔自己的实现。这个应用程序向您展示了每个插槽或每个内存控制器的吞吐量,这适用于某些用途。特别是,带宽在所有内核之间共享,因此在安静的机器上,您可以假设大部分带宽与被测进程相关联,或者如果您想在套接字级别进行监控,这正是您想要的。
另一种选择是对“offcore repsonse”计数器进行仔细编程。据我所知,这些与 L2(最后一个核心私有缓存)和系统其余部分之间的流量有关。您可以按核心响应的结果进行过滤,因此您可以使用各种“L3 未命中”事件的组合并乘以高速缓存行大小来获得读写带宽。这些事件的粒度非常细,因此您可以通过首先导致访问的原因进一步细分:指令获取、数据需求请求、预取等。
非核心响应计数器在 perf 和 likwid 等工具的支持方面通常落后,但至少最近的版本似乎有合理的支持,即使对于像 SKL 这样的客户端部件也是如此。
【讨论】:
核心外响应性能监控工具可用于计算来自特定核心的 IDI 上所有源自核心的请求。请求类型字段可用于统计特定类型的请求,例如需求数据读取。但是,要测量每个内核的内存带宽,必须以某种方式将请求数转换为每秒字节数。大多数请求都是高速缓存行大小,即 64 字节。其他请求的大小可能未知,并且可能会向内存带宽添加小于或大于高速缓存行大小的字节数。其中包括高速缓存行拆分锁定请求、WC 请求、UC 请求和 I/O 请求(但这些不会增加内存带宽),以及需要完成所有挂起写入的围栏请求(MFENCE、@987654332 @,以及序列化指令)。
如果您只对可缓存带宽感兴趣,那么您可以计算可缓存请求的数量并将其乘以 64 字节。这可能非常准确,假设可缓存的高速缓存行拆分锁定请求很少见。不幸的是,当前任何微架构上的核心外响应工具都无法计算从 L3(或 L4,如果可用)到内存的回写。原因是这些写回不是源自核心,通常是由于 L3 中的冲突未命中而发生的。因此,可以计算在 L3 中丢失并导致回写的请求,但核心外响应工具无法让您确定对 L3(或 L4)的任何请求是否导致回写。这就是为什么不可能“按核心”计算回写到内存的原因。
此外,核心外响应事件需要一个可编程的性能计数器,该计数器是 0、1、2 或 3 之一(但在禁用 hyptherhreading 时不是 4-7)。
英特尔至强 Broadwell 支持许多资源控制器技术 (RDT) 功能。特别是它支持Memory Bandwidth Monitoring (MBM),这是准确测量每个内核的内存带宽的唯一方法。
MBM 与非核心响应相比具有三个优势:
offcore response 的优点是它支持请求类型、供应商类型和 snoop 信息字段。
Linux 支持以kernel version 4.6 开头的 MBM。在 4.6 到 4.13 中,perf 支持 MBM 事件,使用以下事件名称:
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的实现有significantly changed。
在运行内核版本 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 处理器上都变成了buggy。根据SKZ4和SKX4:
英特尔® 资源控制器技术 (RDT) 内存带宽监控 (MBM) 不计算到本地的可缓存回写流量 记忆。这导致 RDT MBM 功能在计数总数下 消耗的带宽。
这就是为什么在 Skylake-X 和 Skylake-SP(它们是唯一支持 MBM 的 Skylake 处理器)上运行时在 Linux 上默认为 disabled 的原因。您可以通过将以下 parameter rdt=mbmtotal,mbmlocal 添加到内核命令行来启用 MBM。某些寄存器中没有启用或禁用 MBM 或任何其他 RDT 功能的标志。相反,这是在内核中的某些数据结构中跟踪的。
在 Intel Core 2 微架构上,可以使用 BUS_TRANS_MEM 事件测量每个内核的内存带宽,如 here 所述。
【讨论】:
在某些架构上,使用 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 的读写操作中从主内存传输到缓存的字节数。将该数字除以使用的时间,就可以得到所使用的平均内存带宽的近似值。
【讨论】:
intel_gpu_top -l 用于其 IMC MiB/s 读/写列的内容。
我不确定 Intel PMU,但我认为您可以使用 Intel VTune Amplifier (https://software.intel.com/en-us/intel-vtune-amplifier-xe)。这个有很多性能监控工具(内存、cpu缓存、cpu)。也许这对你有用。
【讨论】: