@@ -40,69 +40,51 @@ static monotime getMonotonicUs_x86(void) {
4040static void monotonicInit_x86linux (void ) {
4141 const int bufflen = 256 ;
4242 char buf [bufflen ];
43- regex_t cpuGhzRegex , constTscRegex ;
43+ regex_t constTscRegex ;
4444 const size_t nmatch = 2 ;
4545 regmatch_t pmatch [nmatch ];
4646 int constantTsc = 0 ;
4747 int rc ;
4848
49- /* Determine the number of TSC ticks in a micro-second. This is
50- * a constant value matching the standard speed of the processor.
51- * On modern processors, this speed remains constant even though
52- * the actual clock speed varies dynamically for each core. */
53- rc = regcomp (& cpuGhzRegex , "^model name\\s+:.*@ ([0-9.]+)GHz" , REG_EXTENDED );
54- assert (rc == 0 );
49+ /* Calibrate TSC ticks per microsecond against CLOCK_MONOTONIC.
50+ * This determines the actual TSC frequency regardless of what
51+ * the processor model name reports. */
52+ for (int i = 0 ; i < TSC_CALIBRATION_ITERATIONS ; ++ i ) {
53+ /* Calibrate TSC against CLOCK_MONOTONIC */
54+ struct timespec start , end ;
55+ uint64_t tsc_start , tsc_end ;
56+
57+ clock_gettime (CLOCK_MONOTONIC , & start );
58+ tsc_start = __rdtsc ();
59+ usleep (10000 ); /* Sleep for 10ms */
60+ tsc_end = __rdtsc ();
61+ clock_gettime (CLOCK_MONOTONIC , & end );
62+
63+ uint64_t elapsed_us = (end .tv_sec - start .tv_sec ) * 1000000ULL + (end .tv_nsec - start .tv_nsec ) / 1000 ;
64+ uint64_t tsc_elapsed = tsc_end - tsc_start ;
65+ long sample_ticksPerMicrosecond = tsc_elapsed / elapsed_us ;
66+
67+ /* Use the maximum out of TSC_CALIBRATION_ITERATIONS iterations for accuracy */
68+ if (sample_ticksPerMicrosecond > mono_ticksPerMicrosecond ) {
69+ mono_ticksPerMicrosecond = sample_ticksPerMicrosecond ;
70+ }
71+ }
5572
56- /* Also check that the constant_tsc flag is present. (It should be
57- * unless this is a really old CPU. */
73+ /* Check that the constant_tsc flag is present. (It should be
74+ * unless this is a really old CPU.) */
5875 rc = regcomp (& constTscRegex , "^flags\\s+:.* constant_tsc" , REG_EXTENDED );
5976 assert (rc == 0 );
6077
6178 FILE * cpuinfo = fopen ("/proc/cpuinfo" , "r" );
6279 if (cpuinfo != NULL ) {
63- while (fgets (buf , bufflen , cpuinfo ) != NULL ) {
64- if (regexec (& cpuGhzRegex , buf , nmatch , pmatch , 0 ) == 0 ) {
65- buf [pmatch [1 ].rm_eo ] = '\0' ;
66- double ghz = atof (& buf [pmatch [1 ].rm_so ]);
67- mono_ticksPerMicrosecond = (long )(ghz * 1000 );
68- break ;
69- }
70- }
71- /* Some CPUs may not contain clock speed in the model name */
72- if (mono_ticksPerMicrosecond == 0 ) {
73- for (int i = 0 ; i < TSC_CALIBRATION_ITERATIONS ; ++ i ) {
74- /* Calibrate TSC against CLOCK_MONOTONIC */
75- struct timespec start , end ;
76- uint64_t tsc_start , tsc_end ;
77-
78- clock_gettime (CLOCK_MONOTONIC , & start );
79- tsc_start = __rdtsc ();
80- usleep (10000 ); /* Sleep for 10ms */
81- tsc_end = __rdtsc ();
82- clock_gettime (CLOCK_MONOTONIC , & end );
83-
84- uint64_t elapsed_us = (end .tv_sec - start .tv_sec ) * 1000000ULL + (end .tv_nsec - start .tv_nsec ) / 1000 ;
85- uint64_t tsc_elapsed = tsc_end - tsc_start ;
86- long sample_ticksPerMicrosecond = tsc_elapsed / elapsed_us ;
87-
88- /* Use the maximum out of TSC_CALIBRATION_ITERATIONS iterations for accuracy */
89- if (sample_ticksPerMicrosecond > mono_ticksPerMicrosecond ) {
90- mono_ticksPerMicrosecond = sample_ticksPerMicrosecond ;
91- }
92- }
93- }
94- /* Rewind file to search for constant_tsc flag */
95- rewind (cpuinfo );
9680 while (fgets (buf , bufflen , cpuinfo ) != NULL ) {
9781 if (regexec (& constTscRegex , buf , nmatch , pmatch , 0 ) == 0 ) {
9882 constantTsc = 1 ;
9983 break ;
10084 }
10185 }
102-
10386 fclose (cpuinfo );
10487 }
105- regfree (& cpuGhzRegex );
10688 regfree (& constTscRegex );
10789
10890 if (mono_ticksPerMicrosecond == 0 ) {
0 commit comments