#endif
f64 cpu_freq;
+#ifdef __x86_64__
+ u32 __clib_unused eax = 0, ebx = 0, ecx = 0, edx = 0;
+ clib_get_cpuid (0x00, &eax, &ebx, &ecx, &edx);
+ if (eax >= 0x15)
+ {
+ u32 max_leaf = eax;
+ /*
+ CPUID Leaf 0x15 - Time Stamp Counter and Nominal Core Crystal Clock Info
+ eax - denominator of the TSC/”core crystal clock” ratio
+ ebx - numerator of the TSC/”core crystal clock” ratio
+ ecx - nominal frequency of the core crystal clock in Hz
+ edx - reseved
+ */
+
+ clib_get_cpuid (0x15, &eax, &ebx, &ecx, &edx);
+ if (ebx && ecx)
+ return ecx * ebx / eax;
+
+ if (max_leaf >= 0x16)
+ {
+ /*
+ CPUID Leaf 0x16 - Processor Frequency Information Leaf
+ eax - Bits 15 - 00: Processor Base Frequency (in MHz).
+ */
+
+ clib_get_cpuid (0x16, &eax, &ebx, &ecx, &edx);
+ if (eax)
+ return 1e6 * (eax & 0xffff);
+ }
+ }
+#endif
+
if (clib_cpu_supports_invariant_tsc ())
return estimate_clock_frequency (1e-3);
f64 dtr_max;
u64 dtc = c->last_cpu_time - c->last_verify_cpu_time;
f64 new_clocks_per_second, delta;
+ f64 save_total_cpu_time_in_seconds;
c->last_verify_cpu_time = c->last_cpu_time;
c->last_verify_reference_time = now_reference;
flt_round_nearest ((f64) dtc / (dtr * c->round_to_units))
* c->round_to_units;
+ /* Compute abs(rate change) */
delta = new_clocks_per_second - c->clocks_per_second;
if (delta < 0.0)
delta = -delta;
+ /* If rate change > 1%, reject it and try again */
if (PREDICT_FALSE ((delta / c->clocks_per_second) > .01))
{
clib_warning ("Rejecting large frequency change of %.2f%%",
return;
}
- c->clocks_per_second =
- flt_round_nearest ((f64) dtc / (dtr * c->round_to_units))
- * c->round_to_units;
+ /* Save total cpu time in seconds */
+ save_total_cpu_time_in_seconds = c->total_cpu_time * c->seconds_per_clock;
+
+ /* Recalculate clock rate */
+ c->clocks_per_second = new_clocks_per_second;
c->seconds_per_clock = 1 / c->clocks_per_second;
+ /*
+ * Restore total cpu time in seconds. Otherwise, if c->clocks_per_second
+ * has decreased, time may appear to flow backwards.
+ */
+ c->total_cpu_time = save_total_cpu_time_in_seconds * c->clocks_per_second;
+
/* Double time between verifies; max at 64 secs ~ 1 minute. */
if (c->log2_clocks_per_frequency_verify < c->log2_clocks_per_second + 6)
c->log2_clocks_per_frequency_verify += 1;