如何在进程中配置和采样英特尔性能计数器
How to Configure and Sample Intel Performance Counters In-Process
简而言之,我试图在用户区基准测试过程中实现以下目标(伪代码,假设 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;
}
FWIW,我正在考虑使用的性能计数器是 CPU_CLK_UNHALTED.THREAD_ALL
,用于读取独立于时钟频率变化的核心周期数(在 我一直计划使用 TSC为此注册,但是,唉,这根本不是这个注册所衡量的)。
我的初衷是使用内联汇编程序首先使用 WRMSR
配置计数器,然后使用 sample_pctr()
中的 RDPMC
读取计数器。
我遇到了第一个障碍,因为编写 MSR 需要内核权限。看起来你实际上可以 读取 来自用户 space 的计数器(如果配置正确),但是 配置 计数器的行为(有MSR)需要内核承担。
有谁知道一种轻量级的方法来要求内核从 user-space 配置性能计数器,以便我可以在我的基准测试工具中使用 RDPMC
?
我看过 into/thought 的内容:
- Linux 的 Perf 工具。似乎已准备好在流程的整个生命周期内进行抽样,而不是在流程内作为特定点(每次迭代之前和之后)进行抽样。
- 直接使用 perf 系统调用(即
perf_event_open
)。看起来计数器值只会定期更新(使用采样率)或在计数器超过阈值后更新。在我询问的那一刻,我恰好需要计数器值。这就是 RDPMC
看起来如此吸引人的原因。我认为频繁采样本身会使性能计数器读数发生偏差。
- PAPI基于perf,所以可能继承了上面的问题。
- 编写内核模块 -- 太费力,太容易出错。
理想情况下,我想要一个适用于 OpenBSD 和 Linux 的解决方案,但不知何故,我认为这是一项艰巨的任务。也许现在只是 Linux。
非常感谢任何帮助。谢谢。
编辑:我刚找到 Linux msr device node,这可能就足够了。我会留下问题,以防出现更好的答案。
似乎最好的方法——至少对于 Linux——是使用 the msr device node.
您只需打开一个设备节点,查找所需 MSR 的地址,然后读取或写入 8 个字节。
OpenBSD 更难,因为(在撰写本文时)没有用户-space 到 MSR 的代理。因此,您需要编写内核模块或手动实现 sysctl。
简而言之,我试图在用户区基准测试过程中实现以下目标(伪代码,假设 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;
}
FWIW,我正在考虑使用的性能计数器是 CPU_CLK_UNHALTED.THREAD_ALL
,用于读取独立于时钟频率变化的核心周期数(在
我的初衷是使用内联汇编程序首先使用 WRMSR
配置计数器,然后使用 sample_pctr()
中的 RDPMC
读取计数器。
我遇到了第一个障碍,因为编写 MSR 需要内核权限。看起来你实际上可以 读取 来自用户 space 的计数器(如果配置正确),但是 配置 计数器的行为(有MSR)需要内核承担。
有谁知道一种轻量级的方法来要求内核从 user-space 配置性能计数器,以便我可以在我的基准测试工具中使用 RDPMC
?
我看过 into/thought 的内容:
- Linux 的 Perf 工具。似乎已准备好在流程的整个生命周期内进行抽样,而不是在流程内作为特定点(每次迭代之前和之后)进行抽样。
- 直接使用 perf 系统调用(即
perf_event_open
)。看起来计数器值只会定期更新(使用采样率)或在计数器超过阈值后更新。在我询问的那一刻,我恰好需要计数器值。这就是RDPMC
看起来如此吸引人的原因。我认为频繁采样本身会使性能计数器读数发生偏差。 - PAPI基于perf,所以可能继承了上面的问题。
- 编写内核模块 -- 太费力,太容易出错。
理想情况下,我想要一个适用于 OpenBSD 和 Linux 的解决方案,但不知何故,我认为这是一项艰巨的任务。也许现在只是 Linux。
非常感谢任何帮助。谢谢。
编辑:我刚找到 Linux msr device node,这可能就足够了。我会留下问题,以防出现更好的答案。
似乎最好的方法——至少对于 Linux——是使用 the msr device node.
您只需打开一个设备节点,查找所需 MSR 的地址,然后读取或写入 8 个字节。
OpenBSD 更难,因为(在撰写本文时)没有用户-space 到 MSR 的代理。因此,您需要编写内核模块或手动实现 sysctl。