5

perf_event_open我正在系统调用之上进行自定义实现。

该实现旨在支持任何核心上特定线程的PERF_TYPE_HARDWARE各种事件PERF_TYPE_SOFTWAREPERF_TYPE_HW_CACHE事件。

Intel® 64 and IA-32 Architectures Software Developer's Manual vol 3B中,我看到以下测试 CPU(Kaby Lake):

在此处输入图像描述

到目前为止,据我所知,可以同时监视(理论上)无限PERF_TYPE_SOFTWARE事件,但同时监视(没有多路复用)PERF_TYPE_HARDWAREPERF_TYPE_HW_CACHE事件是有限的,因为每个事件都是通过 CPU 的 PMU 的有限(如上面的手册中所见)计数器数量来衡量的。

因此,对于启用了超线程的四核 Kaby Lake CPU,我假设最多可以同时监视 4 个PERF_TYPE_HARDWARE/PERF_TYPE_HW_CACHE事件(如果只使用 4 个线程,则最多可以监视 8 个)。

对上述假设进行实验后,我发现虽然我可以成功监控多达 4 个事件(对于 8 个线程),但对于最多只能同时监控 2 个事件PERF_TYPE_HARDWARE的事件,情况并非如此!PERF_TYPE_HW_CACHE

我也尝试只使用 4 个线程,但同时监视的“PERF_TYPE_HARDWARE”事件的上限仍然是 4。禁用超线程时也会发生同样的情况!

有人可能会问:为什么需要避免多路复用。首先,实现需要尽可能准确,避免多路复用的潜在盲点,其次,当超过“上限”时,所有事件值都为 0...

PERF_TYPE_HW_CACHE我要定位的事件是:

CACHE_LLC_READ(PERF_HW_CACHE_TYPE_ID.PERF_COUNT_HW_CACHE_LL.value  | PERF_HW_CACHE_OP_ID.PERF_COUNT_HW_CACHE_OP_READ.value << 8 | PERF_HW_CACHE_OP_RESULT_ID.PERF_COUNT_HW_CACHE_RESULT_ACCESS.value << 16),
CACHE_LLC_WRITE(PERF_HW_CACHE_TYPE_ID.PERF_COUNT_HW_CACHE_LL.value  | PERF_HW_CACHE_OP_ID.PERF_COUNT_HW_CACHE_OP_WRITE.value << 8 | PERF_HW_CACHE_OP_RESULT_ID.PERF_COUNT_HW_CACHE_RESULT_ACCESS.value << 16),
CACHE_LLC_READ_MISS(PERF_HW_CACHE_TYPE_ID.PERF_COUNT_HW_CACHE_LL.value  | PERF_HW_CACHE_OP_ID.PERF_COUNT_HW_CACHE_OP_READ.value << 8 | PERF_HW_CACHE_OP_RESULT_ID.PERF_COUNT_HW_CACHE_RESULT_MISS.value << 16),
CACHE_LLC_WRITE_MISS(PERF_HW_CACHE_TYPE_ID.PERF_COUNT_HW_CACHE_LL.value  | PERF_HW_CACHE_OP_ID.PERF_COUNT_HW_CACHE_OP_WRITE.value << 8 | PERF_HW_CACHE_OP_RESULT_ID.PERF_COUNT_HW_CACHE_RESULT_MISS.value << 16),

所有都使用提供的公式实现:

(perf_hw_cache_id) | (perf_hw_cache_op_id << 8) |
(perf_hw_cache_op_result_id << 16)

并作为一个群体被操纵(第一个是组长等)。

所以,我的问题如下:

  1. PMU 的哪些计数器用于事件PERF_TYPE_HARDWARE,哪些用于PERF_TYPE_HW_CACHE事件,我在哪里可以找到这些信息?
  2. PERF_TYPE_HARDWARE预定义事件(例如PERF_COUNT_HW_CACHE_MISSES)和事件之间有什么区别PERF_TYPE_HW_CACHE
  3. 关于如何在不复用所有列出的PERF_TYPE_HW_CACHE事件的情况下进行监控的任何建议?
  4. 关于如何在不复用多达 8 个PERF_TYPE_HARDWARE或/和PERF_TYPE_HW_CACHE事件的情况下进行监控的任何建议?

提前致谢!

4

1 回答 1

3
  1. PERF_TYPE_HARDWARE和事件映射到性能监控中涉及的PERF_TYPE_HW_CACHE两组寄存器。调用第一组 MSR,IA32_PERFEVTSELx其中 x 可以在 0 到 N-1 之间变化,N 是可用的通用计数器的总数。这PERFEVTSEL是“性能事件选择”的缩写,它们指定了执行事件计数的各种条件。第二组 MSR 称为IA32_PMCx,其中 x 的变化与 相似PERFEVTSEL。这些 PMC 寄存器存储性能监控事件的计数。每个PERFEVTSEL寄存器都与相应的寄存器配对PMC

映射发生如下 -

在内核的体系结构特定部分初始化时,用于测量硬件特定事件的 pmu 在此处注册为 type PERF_TYPE_RAW。所有PERF_TYPE_HARDWAREPERF_TYPE_HW_CACHE事件都映射到PERF_TYPE_RAW事件以识别 pmu,如可以在此处看到的那样。

if (type == PERF_TYPE_HARDWARE || type == PERF_TYPE_HW_CACHE)
        type = PERF_TYPE_RAW;

相同的架构特定初始化负责设置上述每组性能监控事件寄存器的第一/基址寄存器的地址,这里

    .eventsel       = MSR_ARCH_PERFMON_EVENTSEL0,
    .perfctr        = MSR_ARCH_PERFMON_PERFCTR0,

特定于 PMU 识别的event_init功能,负责设置和“保留”两组性能监控寄存器,以及检查事件约束等,here。预订发生在这里

for (i = 0; i < x86_pmu.num_counters; i++) {
        if (!reserve_perfctr_nmi(x86_pmu_event_addr(i)))
            goto perfctr_fail;
    }

    for (i = 0; i < x86_pmu.num_counters; i++) {
        if (!reserve_evntsel_nmi(x86_pmu_config_addr(i)))
            goto eventsel_fail;
    }

该值=指令num_counters标识的通用计数器的数量。CPUID

除此之外,还有几个额外的寄存器可以监控内核外事件(例如,LLC 缓存特定事件)。

在更高版本的架构性能监控中,一些硬件事件是在固定用途寄存器的帮助下测量的,如此处所示。这些是固定用途的寄存器-

#define MSR_ARCH_PERFMON_FIXED_CTR0 0x309
#define MSR_ARCH_PERFMON_FIXED_CTR1 0x30a
#define MSR_ARCH_PERFMON_FIXED_CTR2 0x30b
  1. PERF_TYPE_HARDWARE预定义事件都是架构性能监控事件这些事件是体系结构的,因为每个体系结构性能事件的行为预计在支持该事件的所有处理器上都是一致的。所有事件都是非架构的,这意味着它们是特定于模型的,并且可能因处理器系列而异。PERF_TYPE_HW_CACHE

  2. 对于我拥有的 Intel Kaby Lake 机器,总共PERF_TYPE_HW_CACHE预定义了 20 个事件。所涉及的事件约束,确保可用的 3 个固定功能计数器映射到 3 个PERF_TYPE_HARDWARE架构事件。每个固定功能计数器只能测量一个事件,因此我们可以丢弃它们进行分析。另一个限制是只能同时测量两个针对 LLC 缓存的事件,因为只有两个OFFCORE RESPONSE寄存器。此外,nmi-watchdog可以将事件固定到通用计数器系列中的另一个计数器。如果nmi-watchdog禁用,我们将剩下 4 个通用计数器。

鉴于所涉及的约束以及可用计数器的数量有限,如果同时测量所有 20 个硬件缓存事件,则无法避免多路复用。测量所有事件的一些解决方法,而不引起多路复用及其错误,是 -

3.1。将所有PERF_TYPE_HW_CACHE事件分成 4 个一组,以便可以在 4 个通用计数器中的每一个上同时安排所有 4 个事件。确保组中的 LLC 缓存事件不超过 2 个。运行相同的配置文件并分别获取每个组的计数。

3.2. 如果PERF_TYPE_HW_CACHE要同时监视所有事件,则可以通过减小 的值来减少多路复用的一些错误perf_event_mux_interval_ms。它可以通过一个名为 的 sysfs 条目进行配置/sys/devices/cpu/perf_event_mux_interval_ms如此处所示,该值不能降低超过一个点。

  1. 监视多达 8 个硬件或硬件缓存事件需要禁用超线程。请注意,有关可用的通用计数器数量的信息是使用CPUID指令检索的,并且此类计数器的数量是在内核启动的体系结构初始化部分通过该early_initcall函数设置的。这可以在这里看到。一旦初始化完成,内核就知道只有 4 个计数器可用,以后对超线程能力的任何更改都不会产生任何影响。
于 2020-05-31T20:07:21.383 回答