Skip to content

Commit f3b2dee

Browse files
otherscaseranshid
andauthored
Add monotonic clock calibration handling if clock speed is not found (#2776)
Currently, monotonic clock initialization relies on the model name field from /proc/cpuinfo to retrieve the clock speed. However, this is not always present. In case it is not present, measure the clock tick and use it instead. Before fix: ``` monotonic: x86 linux, unable to determine clock rate ``` After fix: ``` 21695:M 25 Oct 2025 20:16:23.168 * monotonic clock: X86 TSC @ 2649 ticks/us ``` Fixes #2774 --------- Signed-off-by: Ken Nam <[email protected]> Signed-off-by: Ran Shidlansik <[email protected]> Co-authored-by: Ran Shidlansik <[email protected]>
1 parent 909d082 commit f3b2dee

File tree

1 file changed

+27
-0
lines changed

1 file changed

+27
-0
lines changed

src/monotonic.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ static char monotonic_info_string[32];
2727
#include <regex.h>
2828
#include <x86intrin.h>
2929

30+
#define TSC_CALIBRATION_ITERATIONS 3
31+
3032
static long mono_ticksPerMicrosecond = 0;
3133

3234
static monotime getMonotonicUs_x86(void) {
@@ -64,6 +66,31 @@ static void monotonicInit_x86linux(void) {
6466
break;
6567
}
6668
}
69+
/* Some CPUs may not contain clock speed in the model name */
70+
if (mono_ticksPerMicrosecond == 0) {
71+
for (int i = 0; i < TSC_CALIBRATION_ITERATIONS; ++i) {
72+
/* Calibrate TSC against CLOCK_MONOTONIC */
73+
struct timespec start, end;
74+
uint64_t tsc_start, tsc_end;
75+
76+
clock_gettime(CLOCK_MONOTONIC, &start);
77+
tsc_start = __rdtsc();
78+
usleep(10000); /* Sleep for 10ms */
79+
tsc_end = __rdtsc();
80+
clock_gettime(CLOCK_MONOTONIC, &end);
81+
82+
uint64_t elapsed_us = (end.tv_sec - start.tv_sec) * 1000000ULL + (end.tv_nsec - start.tv_nsec) / 1000;
83+
uint64_t tsc_elapsed = tsc_end - tsc_start;
84+
long sample_ticksPerMicrosecond = tsc_elapsed / elapsed_us;
85+
86+
/* Use the maximum out of TSC_CALIBRATION_ITERATIONS iterations for accuracy */
87+
if (sample_ticksPerMicrosecond > mono_ticksPerMicrosecond) {
88+
mono_ticksPerMicrosecond = sample_ticksPerMicrosecond;
89+
}
90+
}
91+
}
92+
/* Rewind file to search for constant_tsc flag */
93+
rewind(cpuinfo);
6794
while (fgets(buf, bufflen, cpuinfo) != NULL) {
6895
if (regexec(&constTscRegex, buf, nmatch, pmatch, 0) == 0) {
6996
constantTsc = 1;

0 commit comments

Comments
 (0)