固定计数器并不是一直在计数,只有在软件启用它们时才会计数。通常(内核端的)perf 会在程序开始之前将其重置为零。
与可编程计数器一样,固定计数器也有位控制它们是否在用户、内核或用户+内核(即始终)中进行计数。我猜想 Linux 的 perf 内核代码在它们没有被使用时保持它们的状态为未计数。
如果你想自己使用原始的 RDPMC,你需要通过设置 IA32_PERF_GLOBAL_CTRL 和 IA32_FIXED_CTR_CTRL MSR 中相应的位来编程/启用计数器,或者让 perf 在你的程序下运行,比如“perf stat ./a.out”。
如果你使用“perf stat -e instructions:u ./perf; echo $ ?”,固定计数器将在进入你的代码之前清零,因此你可以从一次使用 rdpmc 得到一致的结果。否则,例如默认值“-e instructions”(而非:u),你无法知道计数器的初始值。你可以通过计算差值,在开始时读取一次计数器,然后在循环后再读取一次以解决这个问题。
退出状态仅有8位长度,因此这个小技巧避免使用 printf 或 write()。它还意味着构造完整的64位 rdpmc 结果是毫无意义的:输入的高32位对低8位的 sub 结果没有影响,因为进位只从低到高。通常情况下,除非你预计计数 > 2^32,否则请使用 EAX 结果。即使在你测量的时间间隔内原始的64位计数器被包裹,你的减法结果仍将是一个正确的小整数(32位寄存器)。
此外,注意将操作数缩进,这样即使助记符超过3个字母,它们也可以保持在一个一致的列中。
segment .text
global _start
_start:
mov ecx, 1<<30
rdpmc
mov edi, eax
mov edx, 10
.loop:
dec edx
jnz .loop
rdpmc
sub eax, edi
mov edi, eax
mov eax, 231
syscall
在
perf stat ./a.out
或
perf stat -e instructions:u ./a.out
下运行,我们总是从
echo $?
得到
23
(
instructions:u
显示为30,比程序实际运行的指令数多1,包括
syscall
)。
23条指令恰好是第一个
rdpmc
之后但包括第二个
rdpmc
之后的严格指令数。
如果我们注释掉第一个
rdpmc
并在
perf stat -e instructions:u
下运行,则退出状态始终为
26
并从
perf
得到
29
。
rdpmc
是要执行的第24条指令。(因为这是Linux静态可执行文件,所以在
_start
之前没有动态链接器运行,所以RAX始终初始化为零。) 我想知道内核中的
sysret
是否被计为"用户"指令。
但是,如果注释掉第一个
rdpmc
并在
perf stat -e instructions
(不是-u)下运行,则起始计数器值不固定,因此会给出任意值作为退出状态。 因此,我们只是将(某些任意起始点+26) mod 256作为退出状态。
但请注意,RDPMC不是序列化指令,可以无序执行。 一般情况下,您可能需要
lfence
,或者(如John McCalpin在您链接的主题中建议的那样)使ECX对您关心的指令的结果具有虚假依赖性。例如,
and ecx,0
/
or ecx,1<<30
可行,因为与异或清零不同,
and ecx, 0
不会破坏依赖关系。
在这个程序中没有发生奇怪的事情,因为前端是唯一的瓶颈,因此所有指令基本上在发布时立即执行。另外,
rdpmc
紧随循环之后,因此循环退出分支的分支预测可能会防止它在循环完成之前被发送到OoO后端。
PS:对于未来的读者,一种启用Linux上用户空间RDPMC而不需要除
perf
所需的任何自定义模块之外的方法在
perf_event_open(2)
中有记录。
echo 2 | sudo tee /sys/devices/cpu/rdpmc # enable RDPMC always, not just when a perf event is open
for(i=0 ; i<1000; i++)
更好的翻译是将循环计数器移动到寄存器中。或者使用cmp eax, 1000
。使用a dq 100
只会让代码变得混乱;内联小的只读常量。(如果您仍想在代码前定义,请使用equ
)。1<<30
的正确翻译是mov ecx, 1<<30
,而不是运行时移位。更有效率的循环结构是dec ebx / jnz .loop
。rdpmc
将 EAX 和 EDX 写入,并隐式地零扩展为 RAX 和 RDX,您不需要先将它们清零。此外,除非计数可能大于 2^32,否则可以忽略 RDX。 - Peter Cordesperf
的意义所在。但是您可以采取增量方式。 - Peter Cordes