硬件处理器计数器错误地重置

时间:2012-07-09 16:04:50

标签: c assembly x86 msr

我写了一个程序,它读取英特尔芯片上的APERF / MPERF计数器(http://www.intel.com/content/dam/doc/manual/64-ia-32-architectures-software-developer-vol-3b-part-2-manual.pdf上的第2页)。

这些计数器可通过readmsr / writemsr指令读/写,我目前只是通过Windows 7中的设备驱动程序定期读取它们。计数器为64位,大约每个处理器时钟递增,因此你会期望它们在很长一段时间内溢出,但当我读取计数器时,它们的值会跳转,好像它们被另一个程序重置一样。

有没有办法追踪哪些程序会重置计数器?可能还有什么东西导致读取不正确的值?我正在使用的相关组件和相应的C函数如下所示。 rdmsr的64位结果保存到eax:edx中,所以为了确保我没有丢失r_x寄存器中的任何数字,我多次运行命令来检查它们。

C:

long long test1, test2, test3, test4;
test1 = TST1();
test2 = TST2();
test3 = TST3();
test4 = TST4();
status = RtlStringCbPrintfA(buffer, sizeof(buffer), "Value: %llu %llu %llu %llu\n", test1, test2, test3, test4);

大会:

;;;;;;;;;;;;;;;;;;;
PUBLIC TST1 
TST1 proc
    mov ecx, 231 ; 0xE7
    rdmsr
    ret ; returns rax
TST1 endp

;;;;;;;;;;;;;;;;;;;
PUBLIC TST2 
TST2 proc
    mov ecx, 231 ; 0xE7
    rdmsr
    mov rax, rbx
    ret ; returns rax
TST2 endp

;;;;;;;;;;;;;;;;;;;
PUBLIC TST3 
TST3 proc
    mov ecx, 231 ; 0xE7
    rdmsr
    mov rax, rcx
    ret ; returns rax
TST3 endp

;;;;;;;;;;;;;;;;;;;
PUBLIC TST4 
TST4  proc
    mov ecx, 231 ; 0xE7
    rdmsr
    mov rax, rdx
    ret ; returns rax
TST4 endp

打印输出的结果如下所示,但唯一改变的寄存器是rax寄存器,它不会单调增加(可以跳转):

Value: 312664 37 231 0
Value: 252576 37 231 0
Value: 1051857 37 231 0

2 个答案:

答案 0 :(得分:2)

我无法弄清楚是什么重置了我的计数器,但我能够确定频率。英特尔文档指出,当一个计数器溢出时,另一个计数器也会溢出。因此,即使计数器不断重置,aperf和mperf的比率仍然代表处理器的频率。

答案 1 :(得分:0)

似乎Windows 7和Windows 8在AMD处理器上读取和重置可写APERF / MPERF计数器。因此,您希望在寄存器0xc00000E7 / E8访问只读APERF / MPERF计数器。

但是有一个新问题。在某些最新的AMD处理器(系列0x16处理器)上,并不总是支持这些寄存器。要确定是否支持这些寄存器,必须读取CPUID Fn8000_0007_EDX中的EffFreqRO位。如前所述,所有这些仅适用于AMD处理器。