现代 x86 CPU 中是否有一个计数器只计算在中断处理程序中花费的时间(或周期)?

Is there a counter in modern x86 CPUs which only counts the time (or cycles) spent in interrupt handlers?

这不是重复问题。有人声称此问题与 重复。但是,我没有提到“Linux”或“Kernel”(无论是在标签中还是在文本中)。因此,声称这是处理 Linux 和 perf 的问题的重复是错误的。

我想知道如何在没有外部程序的情况下测量中断时间。换句话说,我想自己在代码中进行时间测量,最好使用硬件寄存器。 为了这个问题,我们假设没有O/S。

话虽如此:

在类似奔腾-M 的处理器上运行的汇编程序中,我想测量执行某个程序所需的时间。这通常很容易,有很多文章说明并展示了如何做到这一点,我也有自己的可靠方法。

但是,在这种情况下,有一个问题:程序随时可能被中断(硬件中断)。由于我想测量程序本身的纯执行时间,事情变得越来越复杂:

我一直认为在“现代”英特尔 PC CPU 上有一个计数器,它只在 CPU 执行中断处理程序时才计数。但事实似乎并非如此。至少,我在Intel 64 and IA-32 Architectures Software Developer's manual的“Performance Monitoring”一章中没有找到。

我已经制定了一个解决方案,目前可以满足我的需求,但在未来的情况下并不像我希望的那样精确,也不是很优雅。

因此,我想知道我是否错过了一个硬件计数器,它可以通过仅在执行中断处理程序时进行计数来帮助我(或者,仅在执行 not[ 的代码时进行计数) =52=] 在中断处理程序中)。

禁用中断来测量纯过程执行时间不是一个选项,因为中断处理程序中发生的事情可能会影响过程的执行。

过程和中断处理程序 运行 在同一个内核上。

整个代码(过程和中断处理程序)在环 0 中 运行。

不,没有对此的硬件支持,仅用于编程计数器在环 0(内核模式)与环 3(用户 space)中计数。这就是 Linux perf 用来实现 perf stat --all-user--all-kernel,或 cycles:u:k 修饰符的方法。 (我不确定环 1 和环 2 与哪一个混为一谈)。

x86 ISA 不会将处于“中断处理程序”中的状态区分为特殊状态。这只是一个软件概念,例如主流内核中的中断处理程序可能会跳转到一个名为 schedule() 的函数来决定是 return 到被中断的任务还是其他任务。最终可能会有一个 iret (interrupt-return),但除了从当前堆栈中弹出 CS:RIP、RSP 和 RFLAGS 之外,这并不“特殊”,这可能很难用其他指令来模拟.

但是如果内核 context-switches 到一个任务之前进行了阻塞系统调用,它可能 return 通过 sysret 到 user-space,只有 运行在 context-switching 之后很晚才 iret 回到被中断的任务。你不需要做任何特殊的事情来告诉 x86 CPU 你已经完成了一个中断处理程序(可能不像其他一些 ISA),所以 CPU 甚至没有什么可以监视的。

APIC(外部中断的中断控制器)可能需要被戳一下,让它知道我们已经准备好处理更多此类中断,但 CPU 核心本身可能不会保持跟踪这个。

所以有一些不同的启发式方法可以想象假设的 x86 硬件用来判断中断处理程序何时完成,但我认为实际的 x86 硬件 PMU 不会执行其中任何一个。


对于 user-space 中 运行 的分析代码的正常情况(并且不进行系统调用)perf stat --all-user (或手动编程它将使用的 PMU 设置)将完全按照您的要求进行操作,在 CPU 处于内核模式时不计算任何内容。唯一的内核时间是在中断处理程序中。

但对于您的情况,您要分析的代码 运行ning 在 ring 0 中,HW 无法帮助您。

除非您在中断处理程序中做了非常多的 time-consuming 事情(与其他工作量相比),否则只计算它们可能就足够了。至少对于像“周期”这样的事件。如果中断处理程序导致大量 TLB 未命中或高速缓存未命中或其他情况,这可能会影响您对其他事件的计数。

你的中断处理程序可以 运行 rdpmc 在 start/end 并且可能将每个事件的计数加总到一些全局(或 core-local)变量中,所以你会有一些东西可以从你的主要计数中减去。但这会给每个中断处理程序增加多个 rdpmc 指令的开销。