有时我需要一种适当的方法来从我的用户空间应用程序中测量纳秒级的性能,以便在我的测量中包含系统调用延迟。我读了很多旧的(10yo)文章说它不稳定,他们会把它从用户空间中删除。
- 2020年,英特尔第8代/第9代x86-64 CPU的稳定性如何?我们还能安全地使用 TSC 汇编代码吗?
- 现在在用户空间中使用 TSC 的最佳实践是什么?
链接:
有时我需要一种适当的方法来从我的用户空间应用程序中测量纳秒级的性能,以便在我的测量中包含系统调用延迟。我读了很多旧的(10yo)文章说它不稳定,他们会把它从用户空间中删除。
链接:
它与主板上的时钟晶体一样稳定,但它被锁定到参考频率(取决于 CPU 型号),而不是当前的 CPU 核心时钟频率。这种变化大约在 15 年前(constant_tsc CPU 功能)使其可用于挂钟计时而不是循环计数。
例如,Linux VDSO 用户空间实现使用clock_gettime
和rdtsc
比例因子来计算内核定时器中断更新的不太频繁更新的时间戳的偏移量。(VDSO = 内核拥有的代码和数据页,以只读方式映射到用户空间进程。)
现在在用户空间中使用 TSC 的最佳实践是什么?
如果要计算核心时钟周期,请使用rdpmc
(使用适当编程和设置的硬件性能计数器,以便允许用户空间读取它。)或者用户perf
或其他使用硬件性能计数器的方式。
但除此之外,您可以rdtsc
通过包装库直接或间接使用。
根据您的开销要求,以及您愿意付出多少努力来找出 TSC 频率,以便您可以将 TSC 计数与秒数关联起来,您可能只需要通过std::chrono
或 libc使用它clock_gettime
,而无需实际进入内核,这要归功于VDSO。
如何从 C++ 获取 x86_64 中的 CPU 周期数?- 我的回答有更多关于 TSC 的详细信息,包括它在旧 CPU 上的工作方式,以及乱序执行意味着rdtsc
如果你想在读取之前等待早期代码完成执行,你需要在之前/之后使用 lfence内部 TSC。
测量少于几百条指令的代码块会引入复杂性,即吞吐量和延迟是不同的东西,仅用一个数字来衡量性能是没有意义的。乱序执行意味着周围的代码很重要。
他们将从用户空间中删除它。
x86 基本上从未删除过任何东西,而且绝对不会从用户空间中删除。与现有二进制文件向后兼容是 x86 的主要声名和继续存在的原因。
rdtsc
记录在 Intel 和 AMD 的 x86 手册中,例如Intel 的 vol.2 entry for it。有一个 CPU 功能可以让内核为用户空间禁用 RDTSC(TSD = TimeStamp Disable),但它通常不在 Linux 上使用。(注意#GP(0) 异常:如果寄存器 CR4 中的 TSD 标志已设置且 CPL 大于 0 - 当前特权级别 0 = 内核,更高 = 用户空间。
IDK 如果有计划默认使用 TSD;我认为不是因为它是有用且高效的时间源。即使是这样,在您想要进行分析/微基准测试的开发机器上,您也可以切换该功能。(虽然通常我只是将东西放在一个足够大的重复循环中的静态可执行文件中并在其下运行perf stat
以获得总时间和硬件性能计数器。)