Hola! I looked at the latest XNU source code, in particular tsc.c and tried to locate a new Skylake specific ARTFrequency property (for OS X) and this is what I have found:

case CPUFAMILY_INTEL_SKYLAKE: { /* * SkyLake and later has an Always Running Timer (ART) providing * the reference frequency. CPUID leaf 0x15 determines the * rationship between this and the TSC frequency expressed as * - multiplier (numerator, N), and * - divisor (denominator, M). * So that TSC = ART * N / M. */ cpuid_tsc_leaf_t *tsc_leafp = &cpuid_info()->cpuid_tsc_leaf; uint64_t N = (uint64_t) tsc_leafp->numerator; uint64_t M = (uint64_t) tsc_leafp->denominator; uint64_t refFreq; refFreq = EFI_get_frequency("ARTFrequency"); if (refFreq == 0) refFreq = BASE_ART_CLOCK_SOURCE; assert(N != 0); assert(M != 1); tscFreq = refFreq * N / M; busFreq = tscFreq; /* bus is APIC frequency */ kprintf(" ART: Frequency = %6d.%06dMHz, N/M = %lld/%llu\n", (uint32_t)(refFreq / Mega), (uint32_t)(refFreq % Mega), N, M); break; }

The numerator and denominator values are read in with help of this code snippet from cpuid.c – CPUID leaf 0x15 exposes the relationship between ART and TSC.

if (info_p->cpuid_max_basic >= 0x15) { /* * TCS/CCC frequency leaf: */ cpuid_fn(0x15, reg); info_p->cpuid_tsc_leaf.denominator = reg[eax]; info_p->cpuid_tsc_leaf.numerator = reg[ebx]; DBG(" TSC/CCC Information Leaf:\n"); DBG(" numerator : 0x%x\n", reg[ebx]); DBG(" denominator : 0x%x\n", reg[eax]); }

The problem I am having with it is that one Intel engineer wrote that the numerator is always 2 and can be found in register eax. Really? Well. I checked it and did indeed find a value of 2 in register eax. Register ebx holds a value of 284 (for the Intel i7-6700) and if I use it like this:

((24000000 * 284) / 2) = 3408000000

or this:

24000000 * (284 / 2) = 3408000000

Then all is fine. A next step is to get the bus frequency by dividing the result by 34 (the CPU ratio) which gives me a value of (roughly) 100 MHz. Exactly what I am looking for. And almost the same value that is used for the FSBFrequency property in OS X. But wait. Why did the Intel engineer say that the numerator (N) is always 2, when in fact it is 284? Turns out that M is 2. Great. Now I look like an jerk, because he was talking about getting M:

tscFreq = 3408000000 // Assuming that we are using an Intel i7-6700

refFreq = BASE_ART_CLOCK_SOURCE // 24000000

N = 2 // value of register eax

M = ((tscFreq * N) / 24000000)

I on the other hand was trying to verify my findings for the TSC/bus frequencies, and he said not to comment on other peoples code. Great.

**Edit**: I redacted my blog article after it became clear that I was wrong. I did’t want to start off on the wrong foot, but I should have checked the Intel Software Developer Manual before posting my blog article. A stupid error on my side, because what Apple does – by following the Intel Software Developer Manual (Vol. 2A 3-187) – is spot on. The Intel engineer was also right, but our conversation got mixed up and I ended up being dead wrong, for which I apologise. Feeling pretty stupid now. What a joy LOL

I don’t get it. They divide N by M, so N is numerator and M is denominator. What is wrong with their math here?

(Moreover, the calculation they do in Linux is actually the same:

http://permalink.gmane.org/gmane.linux.kernel.commits.head/520647

tsc_hz = (unsigned long long) crystal_hz * ebx_tsc / eax_crystal; )

Come on. Seriously? There are so many different versions floating around. Getting confused. Need to have another look.