如何在进程中配置和采样英特尔性能计数器

4

简而言之,我试图在用户空间基准测试进程中实现以下目标(伪代码,假设为x86_64和UNIX系统):

results[] = ...
for (iteration = 0; iteration < num_iterations; iteration++) {
    pctr_start = sample_pctr();
    the_benchmark();
    pctr_stop = sample_pctr();
    results[iteration] = pctr_stop - pctr_start;
}

值得一提的是,我要使用的性能计数器是CPU_CLK_UNHALTED.THREAD_ALL,用于读取独立于时钟频率变化的核心周期数(在以前的一个问题中,我原本打算使用TSC寄存器来实现这一点,但遗憾的是,该寄存器根本不测量这个)。

我的初始意图是使用内联汇编器首先使用WRMSR配置计数器,然后在sample_pctr()中使用RDPMC读取计数器。

但我在第一个障碍上失败了,因为写入MSRs需要内核权限。似乎你确实可以从用户空间读取计数器(如果正确配置),但配置计数器(使用MSR)的操作需要由内核执行。

有人知道一种轻量级的方法来从用户空间请求内核配置性能计数器,以便我可以在我的基准测试套件中使用RDPMC吗?

我考虑过以下事项:

  • 针对Linux的Perf工具。似乎适用于在进程的整个生命周期中进行采样,而不是在特定时间点(在每次迭代之前和之后)内部进行。
  • 直接使用Perf系统调用(即perf_event_open)。看起来计数器值只会定期更新(使用采样率)或在计数器超过阈值后更新。我需要在我要求的那一刻精确地获得计数器值。这就是为什么RDPMC看起来很有吸引力的原因。我认为频繁采样本身会扭曲性能计数器读数。
  • PAPI基于Perf构建,因此可能会继承上述问题。
  • 编写一个内核模块——太费力了,也容易出错。

理想情况下,我希望找到适用于OpenBSD和Linux的解决方案,但我认为这是一个高难度的问题。也许现在只需要适用于Linux。

非常感谢任何帮助。谢谢。

编辑:我刚刚发现了Linux msr设备节点,这可能就足够了。如果有更好的答案出现,我会保留这个问题。


您可以从用户空间编程计数器,但是由于在上下文切换时PMC不会被保存/恢复,因此您可能希望将线程固定到核心。请参见http://agner.org/optimize/,其中已经编写了一个Linux内核模块,可为您提供PMC访问权限,以及http://stackoverflow.com/questions/38848914/pmu-for-multi-threaded-environment/38984414#38984414,以获取有关使用它们的讨论。 - Peter Cordes
谢谢!您能否评论一下perf采样模型会带来多少开销?那些perf例程本身是否包含在我所采取的任何读数中? - Edd Barrett
没什么头绪;我只是将想要进行微基准测试的循环放入独立的程序中,并使用 perf stat 使用 perf - Peter Cordes
1个回答

0

对于 Linux 系统而言,最好的方式似乎是使用 msr 设备节点

你只需要打开设备节点,寻找所需 MSR 的地址,然后读取或写入 8 字节即可。

在 OpenBSD 上则比较困难,因为(截至撰写本文时)没有用户空间代理来访问 MSRs。因此,你需要编写一个内核模块或手动实现 sysctl。


不要使用lseek/write,而是使用pwrite在指定的偏移量处进行写入,如http://stackoverflow.com/questions/38848914/pmu-for-multi-threaded-environment/38984414#38984414所述。 - Peter Cordes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接