【发布时间】:2019-08-01 16:25:18
【问题描述】:
我想读取某些性能计数器。我知道有像 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中,这个错误的原因被定义为错误的type字段。
由于文件描述符与打开它们的进程相关联,如何从内核中使用它们?是否有另一种方法可以将 pmu 配置为在不涉及文件描述符的情况下开始计数?
【问题讨论】:
-
你不需要内联汇编; gcc 有一个
__builtin_rdpmc(int)。但是你的内联汇编看起来是正确的,所以这不会改变任何东西。 (注意gcc.gnu.org/bugzilla/show_bug.cgi?id=87550:在 gcc6.5 / 7.4 / 8.3 之前,内置忽略了volatile。) -
您必须显示您在用户模式和内核模式下使用的整个代码。我怀疑您在用户模式下使用的代码启用了指令退休固定功能计数器,但您在内核模式下使用的代码没有。
-
您可能会发现在 NanoBench 中查看它是如何完成的会很有帮助。
-
您仍然只显示使用
rdpmc的代码。您没有显示任何对 PMU 进行编程的代码。您在对我的回答的评论中链接了software.intel.com/en-us/forums/…,但您甚至还没有在您的问题中提到做任何事情来使计数器计数。只是你从那里得到了rdmpc代码本身。 -
您必须首先使用
rdpmc启用或编程要读取的计数器。甚至您的用户模式代码也不起作用;它只会打印零。您认为它有效的原因是因为您使用%ld格式来打印double值,它基本上将零重新解释为一个大整数。正确的代码是来自英特尔论坛上 Kumar C 在“Thu, 11/17/2016 - 17:41”上发表的评论中的代码。
标签: linux-kernel x86 performancecounter perf intel-pmu