1+ #include <math.h>
12#include <stdbool.h>
3+ #include <stdio.h>
24#include <time.h>
35
46#include "utils.h"
@@ -24,6 +26,10 @@ bool boot_complete = false;
2426static double ticks_increment ;
2527static double boot_ticks ;
2628
29+ /* Timer calibration statistics */
30+ static uint64_t timer_call_count = 0 ;
31+ static int timer_n_harts = 1 ;
32+
2733/* Calculate "x * n / d" without unnecessary overflow or loss of precision.
2834 *
2935 * Reference:
@@ -88,6 +94,7 @@ static uint64_t semu_timer_clocksource(semu_timer_t *timer)
8894 static bool first_switch = true;
8995
9096 if (!boot_complete ) {
97+ timer_call_count ++ ;
9198 boot_ticks += ticks_increment ;
9299 return (uint64_t ) boot_ticks ;
93100 }
@@ -98,6 +105,34 @@ static uint64_t semu_timer_clocksource(semu_timer_t *timer)
98105
99106 /* Calculate the offset between the real time and the emulator time */
100107 offset = (int64_t ) (real_ticks - boot_ticks );
108+
109+ #ifdef SEMU_TIMER_STATS
110+ /* Output timer calibration statistics (only when SEMU_TIMER_STATS is
111+ * defined) */
112+ double actual_coefficient = (double ) timer_call_count / timer_n_harts ;
113+ double current_coefficient = 1.744e8 ;
114+ double recommended_coefficient = actual_coefficient ;
115+
116+ fprintf (stderr , "\n[Timer Calibration Statistics]\n" );
117+ fprintf (stderr , " Boot completed after %llu timer calls\n" ,
118+ (unsigned long long ) timer_call_count );
119+ fprintf (stderr , " Number of harts: %d\n" , timer_n_harts );
120+ fprintf (stderr , " Actual coefficient: %.3e (%.2f calls per hart)\n" ,
121+ actual_coefficient , actual_coefficient );
122+ fprintf (stderr , " Current coefficient: %.3e\n" , current_coefficient );
123+ fprintf (stderr , " Difference: %.2f%% %s\n" ,
124+ fabs (actual_coefficient - current_coefficient ) /
125+ current_coefficient * 100.0 ,
126+ actual_coefficient > current_coefficient ? "(more calls)"
127+ : "(fewer calls)" );
128+ fprintf (stderr , "\n[Recommendation]\n" );
129+ fprintf (stderr , " Update utils.c line 121 to:\n" );
130+ fprintf (stderr ,
131+ " ticks_increment = (SEMU_BOOT_TARGET_TIME * CLOCK_FREQ) / "
132+ "(%.3e * n_harts);\n" ,
133+ recommended_coefficient );
134+ fprintf (stderr , "\n" );
135+ #endif
101136 }
102137 return (uint64_t ) ((int64_t ) real_ticks - offset );
103138}
@@ -108,14 +143,28 @@ void semu_timer_init(semu_timer_t *timer, uint64_t freq, int n_harts)
108143 timer -> begin = mult_frac (host_time_ns (), timer -> freq , 1e9 );
109144 boot_ticks = timer -> begin ; /* Initialize the fake ticks for boot process */
110145
146+ /* Store n_harts for calibration statistics */
147+ timer_n_harts = n_harts ;
148+
111149 /* According to statistics, the number of times 'semu_timer_clocksource'
112- * called is approximately 'SMP count * 2.15 * 1e8'. By the time the boot
150+ * called is approximately 'SMP count * 1.744 * 1e8'. By the time the boot
113151 * process is completed, the emulator will have a total of 'boot seconds *
114- * frequency' ticks. Therefore, each time, '(boot seconds * frequency) /
115- * (2.15 * 1e8 * SMP count)' ticks need to be added.
152+ * frequency' ticks. Therefore, each time, (boot seconds * frequency) /
153+ * (1.744 * 1e8 * SMP count) ticks need to be added.
154+ *
155+ * Note: This coefficient was recalibrated after MMU cache optimization
156+ * (8×2 set-associative with 99%+ hit rate). The original coefficient
157+ * (2.15 * 1e8) was based on measurements before the optimization. With
158+ * faster CPU execution, fewer timer calls are needed to complete boot.
159+ *
160+ * Calibration history:
161+ * - Original (pre-MMU cache): 2.15 × 10^8
162+ * - After MMU cache (measured): 1.696 × 10^8 (-21.1%)
163+ * - Verification measurement: 1.744 × 10^8 (error: 2.85%)
164+ * - Final coefficient: 1.744 × 10^8 (based on verification)
116165 */
117166 ticks_increment =
118- (SEMU_BOOT_TARGET_TIME * CLOCK_FREQ ) / (2.15 * 1e8 * n_harts );
167+ (SEMU_BOOT_TARGET_TIME * CLOCK_FREQ ) / (1.744 * 1e8 * n_harts );
119168}
120169
121170uint64_t semu_timer_get (semu_timer_t * timer )
0 commit comments