从内核读取性能寄存器

问题描述 投票:1回答:1

我想阅读某些性能指标。我知道有像perf这样的工具可以在用户空间本身为我做,我希望代码在Linux内核中。

我想编写一种机制来监控Intel(R)Core(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;
  }

我想在内核代码(在context switch函数中)中添加相同的行并检查正在读取的值。

我的最终目标是找出一种方法来读取进程的性能计数器,每次从内核(4.19.2)本身切换到另一个进程。

为此,我查看了系统调用号__NR_perf_event_open的代码。它可以找到here为了使可用我将代码内部复制为一个单独的函数,在同一个文件中将其命名为perf_event_open()并导出。

现在问题是每当我以与上面相同的方式调用perf_event_open()时,返回的描述符是-2。检查error codes,我发现错误是ENOENT。在perf_event_open() man page中,此错误的原因被定义为错误的类型字段。

由于文件描述符与打开它们的进程相关联,如何从内核中使用它们?有没有另一种方法来配置pmu开始计数而不涉及文件描述符?

linux-kernel x86 performancecounter perf intel-pmu
1个回答
3
投票

您可能不希望在上下文切换功能中重新编程计数器的开销。

最简单的方法是从用户空间进行系统调用以对PMU进行编程(计算某些事件,可能将其设置为内核模式但不是用户空间,因此计数器溢出的次数较少)。

然后在自定义内核代码中使用rdpmc两次(以获取开始/停止计数)。计数器将保持运行,我想内核性能代码将在它包装时处理中断。 (或者当它的PEBS缓冲区已满时。)

IDK是否可以对计数器进行编程以便它只是在不中断的情况下进行编程,对于这样的用例,您不关心总计或基于样本的分析,只想使用rdpmc。如果是这样,那就这样做。


旧的答案,解决你的旧问题,这是基于一个有缺陷的printf格式字符串打印非零垃圾,即使你没有在用户空间计算任何东西。

你的内联asm看起来是正确的,所以问题是PMU计数器在代码运行的上下文中被编程为在内核模式下计数的确切内容。

perf在上下文切换时虚拟化PMU计数器,给出了perf stat计算单个进程的错觉,即使它在CPU中迁移也是如此。除非你使用perf -a来获得系统范围的计数,否则PMU可能不会被编程为计算任何东西,所以即使在其他时候它被编程为计算诸如周期或指令之类的快速变化事件,所以多次读取都会给0


你确定你有perf设置来计算用户+内核事件,而不仅仅是用户空间事件?

perf stat将显示像instructions:u而不是instructions,如果它限制用户空间。 (如果你没有将sysctl kernel.perf_event_paranoid降低到0或安全默认值,那么这是非root用户的默认设置,不允许用户空间学习内核的任何内容。)

有一个HW支持编程计数器只在CPL!= 0时计数(即不在环0 /内核模式下)。 kernel.perf_event_paranoid的较高值限制了perf API不允许编程计数器在内核+用户模式中计数,但即使使用paranoid = -1,也可以通过这种方式对它们进行编程。如果你是如何编程一个计数器,那么这将解释一切。

我们需要看到编写计数器的代码。这不会自动发生。

当没有进程使用PAPI函数来启用每进程或系统范围的计数器时,内核不会让计数器一直运行;这会产生中断,使系统速度降低而无益。

© www.soinside.com 2019 - 2024. All rights reserved.