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;
  }

我想将相同的行放在内核代码中(在上下文切换函数中)并检查正在读取的值。

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

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

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

由于文件描述符与打开它们的进程相关联,如何从内核中使用它们?是否有另一种方法可以将 pmu 配置为在不涉及文件描述符的情况下开始计数?

4

1 回答 1

3

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

最简单的方法是从用户空间进行系统调用以对 PMU 进行编程(计算某些事件,可能将其设置为在内核模式而不是用户空间中计数,这样计数器溢出的频率就会降低)。

然后只需rdpmc在您的自定义内核代码中使用两次(以获取启动/停止计数)。计数器将继续运行,我猜内核性能代码将在它回绕时处理中断。(或者当它的 PEBS 缓冲区已满时。)

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


旧答案,解决您的旧问题,该问题基于printf打印非零垃圾的错误格式字符串,即使您也没有计算用户空间中的任何内容。

您的内联汇编看起来是正确的,所以问题是在您的代码运行的上下文中,PMU 计数器被编程为在内核模式下计数到底是什么。

perf在上下文切换时虚拟化 PMU 计数器,perf stat即使在跨 CPU 迁移时也会产生计数单个进程的错觉。除非您perf -a用于获取系统范围的计数,否则 PMU 可能不会被编程为计数任何东西,因此0即使在其他时间它被编程为计数快速变化的事件(如周期或指令),多次读取也会给出。


您确定您已perf设置计算用户 + 内核事件,而不仅仅是用户空间事件吗?

perf stat将显示类似的东西,instructions:u而不是instructions它是否将自身限制在用户空间中。kernel.perf_event_paranoid(如果您没有将 sysctl 降低到 0 或不让用户空间了解有关内核的任何内容的安全默认值,这是非 root用户的默认值。)

硬件支持将计数器编程为仅在 CPL != 0 时计数(即不在环 0/内核模式下)。 较高的值kernel.perf_event_paranoid会限制 perf API 以不允许编程计数器在内核+用户模式下计数,但即使有paranoid = -1可能以这种方式对其进行编程。如果这就是您编写计数器的方式,那么这将解释一切。

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

当没有进程使用 PAPI 函数启用每个进程或系统范围的计数器时,内核不会让计数器一直运行;这会产生中断,使系统变慢而没有任何好处。

于 2019-03-11T17:10:33.797 回答