With all the performance counters and MSRs available in Intel CPUs, it still seems impossible to accurately measure CPU frequency in user-mode code:
#include
#include
#include
#pragma comment(lib, "winmm.lib")
typedef unsigned __int64 u64;
__declspec(naked) u64 readtsc(void)
{
__asm {
rdtsc
ret
}
}
double GetCPUFrequency(void)
{
static u64 r0 = 0, f0 = 0;
u64 r1, r2;
DWORD t0, t1;
int i;
timeBeginPeriod(1);
for (i = 0; i < 3; i++) {
t0 = timeGetTime();
t1 = t0;
while (t1 - t0 < 20) {
t1 = timeGetTime();
r1 = readtsc();
}
t0 = t1;
while (t1 - t0 < 40) {
t1 = timeGetTime();
r2 = readtsc();
}
r0 += r2 - r1;
f0 += (t1 - t0);
}
timeEndPeriod(1);
return (r0 / f0) / 1000.0;
}
int main(int argc, char* argv[])
{
for (;;) {
printf("Frequency : %.2f MHzr", GetCPUFrequency());
Sleep(1000);
}
return 0;
}
The above code returns 3400 MHz for a Core i7 2600K overclocked to 4000 MHz. Tools such as CPU-Z and AIDA64 are capable of measuring frequency accurately but they use device drivers to execute ring 0 code which has access to MSRs.
My question is why Intel CPU engineers did not provide user-mode instructions (kind of like RDTSC/RDTSCP) for APERF and MPERF MSRs, but instead left those accessible only from ring 0? What were they thinking?
Finally, is there any way to work around this?




