KiD0M4N KiD0M4N - 2 months ago 25
C++ Question

Finding out the CPU clock frequency (per core, per processor)

Programs like CPUz are very good at giving in depth information about the system (bus speed, memory timings, etc.)

However, is there a programmatic way of calculating the per core (and per processor, in multi processor systems with multiple cores per CPU) frequency without having to deal with CPU specific info.

I am trying to develop a anti cheating tool (for use with clock limited benchmark competitions) which will be able to record the CPU clock during the benchmark run for all the active cores in the system (across all processors.)

Answer

I'll expand on my comments here. This is too big and in-depth for me to fit in the comments.

What you're trying to do is very difficult - to the point of being impractical for the following reasons:

  • There's no portable way to get the processor frequency. rdtsc does NOT always give the correct frequency due to effects such as SpeedStep and Turbo Boost.
  • All known methods to measure frequency require an accurate measurement of time. However, a determined cheater can tamper with all the clocks and timers in the system.

There's no portable way to get the processor frequency:

The "easy" way to get the CPU frequency is to call rdtsc twice with a fixed time-duration in between. Then dividing out the difference will give you the frequency.

The problem is that rdtsc does not give the true frequency of the processor. Because real-time applications such as games rely on it, rdtsc needs to be consistent through CPU throttling and Turbo Boost. So once your system boots, rdtsc will always run at the same rate (unless you start messing with the bus speeds with SetFSB or something).

For example, on my Core i7 2600K, rdtsc will always show the frequency at 3.4 GHz. But in reality, it idles at 1.6 GHz and clocks up to 4.6 GHz under load via the overclocked Turbo Boost multiplier at 46x.

Now suppose you find a way to measure the true frequency, (or you're happy enough with rdtsc). To get the frequencies of each core on each socket, you do that by playing with thread-affinities.

I'm not sure exactly how CPUz measures the correct frequency. But I think it actually goes all the way into BIOS and does it's own bus-speed x multiplier arithmetic. This requires having a database of all the processor systems. (which explains why CPUz needs to be constantly updated with new processors)

All known methods to measure frequency require an accurate measurement of time:

This is perhaps the bigger problem. You need a timer to be able to measure the frequency. A capable hacker will be able to tamper with all the clocks that you can use in C/C++. This includes all of the following:

  • clock()
  • gettimeofday()
  • QueryPerformanceCounter()
  • etc...

The list goes on and on. In other words, you cannot trust any of the timers as a capable hacker will be able to spoof all of them. For example clock() and gettimeofday() can be fooled by changing the system clock directly within the OS. Fooling QueryPerformanceCounter() is harder. At the request of the XtremeSystems Forums admins, I will not reveal how to do this. They have taught me some of the most powerful overclocking cheats just so that I could develop and implement countermeasures into my y-cruncher Multi-threaded Pi Benchmark. But for the most part, I'm not entirely successful in implementing these countermeasures...


So to answer your question in the comments, yes I have implemented a decent anti-cheating system to prevent timer hacks. Although I don't try to get an accurate frequency measurement, the timer-protection is enough to make the benchmarks reasonably hard to cheat.

I obviously can't go into details, but part of it involves using multiple clocks and re-syncing them multiple times during a benchmark. If any of them get to far out-of-sync, then raise the cheat flag.

Overall, what I have is not perfect. I can hack it myself in about 5 min. (well, I know how it works). Furthermore, it occasionally gives false-positives... which is also bad.