现代 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
指令的开销。
这不是重复问题。有人声称此问题与
我想知道如何在没有外部程序的情况下测量中断时间。换句话说,我想自己在代码中进行时间测量,最好使用硬件寄存器。 为了这个问题,我们假设没有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
指令的开销。