我想读取某些性能计数器。我知道有像perf这样的工具,可以在用户空间本身为我做到这一点,我希望代码在Linux内核中。
我想编写一种机制来监视英特尔(R) 酷睿(TM) i7-3770 CPU 上的性能计数器。除了使用之外,我还使用 Ubuntu 内核 4.19.2。我从easyperf那里得到了以下方法
这是我阅读说明的代码的一部分。
struct perf_event_attr *attr
memset (&pe, 0, sizeof (struct perf_event_attr));
pe.type = PERF_TYPE_HARDWARE;
pe.size = sizeof (struct perf_event_attr);
pe.config = PERF_COUNT_HW_INSTRUCTIONS;
pe.disabled = 0;
pe.exclude_kernel = 0;
pe.exclude_user = 0;
pe.exclude_hv = 0;
pe.exclude_idle = 0;
fd = syscall(__NR_perf_event_open, hw, pid, cpu, grp, flags);
uint64_t perf_read(int fd) {
uint64_t val;
int rc;
rc = read(fd, &val, sizeof(val));
assert(rc == sizeof(val));
return val;
}
我想在内核代码中(在上下文切换函数中)放置相同的行并检查正在读取的值。
我的最终目标是找出一种方法,在每次进程切换到另一个进程时,从内核(4.19.2)本身读取进程的性能计数器。
为此,我查看了系统调用号码__NR_perf_event_open的代码。可以在这里找到 为了使可用,我将内部的代码复制为一个单独的函数,在同一文件中将其命名为perf_event_open()并导出。
现在的问题是,每当我以与上面相同的方式调用 perf_event_open() 时,返回的描述符都是 -2。检查错误代码,我发现错误是ENOENT。在 perf_event_open() 手册页中,此错误的原因定义为错误的类型字段。
由于文件描述符与打开它们的进程相关联,因此如何从内核中使用它们?有没有另一种方法可以将 pmu 配置为在不涉及文件描述符的情况下开始计数?
您可能不希望在上下文切换函数中重新编程计数器的开销。
最简单的方法是从用户空间进行系统调用以对 PMU 进行编程(对某个事件进行计数,可能将其设置为在内核模式下计数,但不设置为在用户空间中计数,只是为了减少计数器溢出的频率)。
然后,只需在自定义内核代码中使用rdpmc
两次(以获取启动/停止计数)。 计数器将保持运行,我猜内核 perf 代码在环绕时将处理中断。 (或者当其 PEBS 缓冲区已满时。
IDK 如果可以对计数器进行编程,使其只是包装而不会中断,对于像这样的用例,您不关心总计或基于样本的分析,只想使用rdpmc
. 如果是这样,请这样做。
答案,解决您的旧问题,该问题基于一个错误的printf
格式字符串,该字符串正在打印非零垃圾,即使您也没有在用户空间中计算任何内容。
您的内联 asm 看起来是正确的,所以问题是 PMU 计数器究竟被编程为在代码运行的上下文中以内核模式计数。
perf
在上下文切换时虚拟化 PMU 计数器,给人一种perf stat
计数单个进程的错觉,即使它跨 CPU 迁移也是如此。 除非您使用perf -a
来获取系统范围的计数,否则 PMU 可能不会被编程为对任何内容进行计数,因此即使在其他时候,多次读取都会提供0
,即使它被编程为对快速变化的事件(如周期或指令)进行计数。
将perf
设置为计数用户 + 内核事件,而不仅仅是用户空间事件?
perf stat
将显示类似instructions:u
的内容,而不是instructions
如果它限制在用户空间。 (如果您没有将 sysctlkernel.perf_event_paranoid
降低到 0 或安全默认值中的某些内容,则这是非 root 的默认值,这不会让用户空间了解有关内核的任何信息。
硬件支持对计数器进行编程,使其仅在 CPL != 0 时计数(即不在环 0/内核模式下)。kernel.perf_event_paranoid
较高的值将性能 API 限制为不允许编程计数器在内核+用户模式下计数,但即使有paranoid = -1
也可以通过这种方式对它们进行编程。 如果这就是你对计数器进行编程的方式,那么这将解释一切。
我们需要查看对计数器进行编程的代码。 这不会自动发生。
当没有进程使用 PAPI 函数来启用每个进程或系统范围的计数器时,内核不会一直让计数器运行;这将产生中断,从而减慢系统速度而没有任何好处。