6666 *
6767 * To achieve the above, we use the following data structures.
6868 *
69- * 1. fast_clock_timepoint_t - this contains all the internal state needed by FastClock to
69+ * 1. fast_clock_timepoint - this contains all the internal state needed by FastClock to
7070 * calculate the time as discussed above. FastClock internally has *two* timepoints, which
7171 * are used in round-robin (alternating).
72- * 2. fast_clock_desc_t - this is read and written to atomically, which is how the lockless
72+ * 2. fast_clock_desc - this is read and written to atomically, which is how the lockless
7373 * thread safety is implemented. The descriptor contains:
7474 * - The current "state" of the FastClock state machine.
7575 * - The round-robin index of the timepoint that is currently in use.
104104#define RDTSC_CALIBRATION_TIME ((uint64_t)1 * TIME_US_IN_S)
105105#define RDTSC_RECALIBRATION_INTERVAL ((uint64_t)120 * TIME_US_IN_S)
106106
107- fast_clock_t g_fast_clock = {
108- .atomic_descriptor = { .state = FC_STATE_INIT , .flags = FC_FLAGS_INIT },
109- .time_points = { [0 ... _FC_NUM_TIMEPOINTS - 1 ] = {
107+ typedef enum
108+ {
109+ FC_STATE_RDTSC ,
110+ FC_STATE_RDTSC_RECALIBRATE ,
111+ FC_STATE_CALIBRATING ,
112+ FC_STATE_INIT ,
113+
114+ FC_STATE_RDTSC_DISABLED ,
115+ } fast_clock_state ;
116+
117+ fast_clock g_fast_clock = {
118+ .atomic_descriptor = {
119+ .state = FC_STATE_INIT ,
120+ .timepoint_index = 0 ,
121+ .state_changing = 0 ,
122+ },
123+ .time_points = { [0 ... FC_NUM_TIMEPOINTS - 1 ] = {
110124 .clock_freq = 0 ,
111125 .tsc0 = 0 ,
112126 .t0_usec = 0 ,
@@ -115,75 +129,65 @@ fast_clock_t g_fast_clock = {
115129};
116130
117131
118- static inline uint16_t timepoint_index (fast_clock_desc_t curr )
119- {
120- return (curr .flags & FC_FLAGS_TIMEPOINT_MASK );
121- }
122-
123- static inline fast_clock_desc_t advance_state (fast_clock_desc_t curr , fast_clock_state_t new_state , bool advance_timepoint )
132+ static inline fast_clock_desc advance_state (fast_clock_desc curr , fast_clock_state new_state , bool advance_timepoint )
124133{
125- fast_clock_desc_t new_descriptor ;
126- new_descriptor .state = new_state ;
127- uint16_t new_tp_index = timepoint_index (curr );
128- if (advance_timepoint ) {
129- new_tp_index = (new_tp_index + 1 ) % FC_FLAGS_NUM_TIMEPOINTS ;
130- }
131- new_descriptor .flags = new_tp_index ;
134+ fast_clock_desc new_descriptor = {
135+ .state = new_state ,
136+ .timepoint_index = advance_timepoint ? curr .timepoint_index + 1 : curr .timepoint_index ,
137+ .state_changing = 0 ,
138+ };
132139 return new_descriptor ;
133140}
134141
135- static inline bool is_expired (const fast_clock_timepoint_t * timepoint , uint64_t now_usec )
142+ static inline bool is_expired (const fast_clock_timepoint * timepoint , uint64_t now_usec )
136143{
137144 return (timepoint -> expiration_usec < now_usec );
138145}
139146
140- static inline void calc_time (const fast_clock_timepoint_t * timepoint , uint64_t * time_usec )
147+ static inline void calc_time (const fast_clock_timepoint * timepoint , uint64_t * time_usec )
141148{
142149 uint64_t tsc = get_tsc ();
143150 uint64_t dtsc = tsc - timepoint -> tsc0 ;
144151 uint64_t dt_usec = (dtsc * TIME_US_IN_S ) / timepoint -> clock_freq ;
145152 * time_usec = timepoint -> t0_usec + dt_usec ;
146153}
147154
148- static inline void reset_clock_frequency (fast_clock_timepoint_t * timepoint , uint64_t tsc , uint64_t time_usec )
155+ static inline void reset_clock_frequency (fast_clock_timepoint * timepoint , uint64_t tsc , uint64_t time_usec )
149156{
150157 // calculate clock frequency in Hz
151158 uint64_t dt_usec = time_usec - timepoint -> t0_usec ;
152159 uint64_t dtsc = tsc - timepoint -> tsc0 ;
153160 timepoint -> clock_freq = (dtsc * TIME_US_IN_S ) / dt_usec ;
154161}
155162
156- static inline long reset_timepoint (fast_clock_timepoint_t * timepoint )
163+ static inline long reset_timepoint (fast_clock_timepoint * timepoint )
157164{
158165 int ret = ocall_gettime (& timepoint -> t0_usec , & timepoint -> tsc0 );
159166 return ret ;
160167}
161168
162- static inline void reset_expiration (fast_clock_timepoint_t * timepoint , uint64_t next_expiration )
169+ static inline void reset_expiration (fast_clock_timepoint * timepoint , uint64_t next_expiration )
163170{
164171 timepoint -> expiration_usec = timepoint -> t0_usec + next_expiration ;
165172}
166173
167- static inline bool set_change_state_guard (fast_clock_t * fast_clock , fast_clock_desc_t descriptor )
174+ static inline bool set_change_state_guard (fast_clock * fast_clock , fast_clock_desc descriptor )
168175{
169- if (( descriptor .flags & FC_FLAGS_STATE_CHANGING ) != 0 ) {
176+ if (descriptor .state_changing != 0 ) {
170177 return false;
171178 }
172179
173- fast_clock_desc_t state_change_guard_desc = {
174- .state = descriptor .state ,
175- .flags = descriptor .flags | FC_FLAGS_STATE_CHANGING ,
176- };
177-
180+ fast_clock_desc state_change_guard_desc = descriptor ;
181+ state_change_guard_desc .state_changing = 1 ;
178182 return __atomic_compare_exchange_n (
179183 & fast_clock -> atomic_descriptor .desc , & descriptor .desc , state_change_guard_desc .desc ,
180184 /*weak=*/ false, __ATOMIC_RELAXED , __ATOMIC_RELAXED
181185 );
182186}
183187
184- static inline fast_clock_timepoint_t * get_timepoint (fast_clock_t * fast_clock , fast_clock_desc_t descriptor )
188+ static inline fast_clock_timepoint * get_timepoint (fast_clock * fast_clock , fast_clock_desc descriptor )
185189{
186- return & fast_clock -> time_points [timepoint_index ( descriptor ) ];
190+ return & fast_clock -> time_points [descriptor . timepoint_index ];
187191}
188192
189193static bool is_rdtsc_available (void ) {
@@ -215,20 +219,20 @@ static int handle_state_rdtsc_disabled(uint64_t* time_usec)
215219 return ocall_gettime (time_usec , NULL );
216220}
217221
218- static int handle_state_init (fast_clock_t * fast_clock , fast_clock_desc_t descriptor , uint64_t * time_usec )
222+ static int handle_state_init (fast_clock * fast_clock , fast_clock_desc descriptor , uint64_t * time_usec )
219223{
220224 if (!set_change_state_guard (fast_clock , descriptor )) {
221225 return handle_state_rdtsc_disabled (time_usec );
222226 }
223227
224228 if (!is_rdtsc_available ()) {
225- fast_clock_desc_t next_desc = advance_state (descriptor , FC_STATE_RDTSC_DISABLED , false);
229+ fast_clock_desc next_desc = advance_state (descriptor , FC_STATE_RDTSC_DISABLED , false);
226230 __atomic_store_n (& fast_clock -> atomic_descriptor .desc , next_desc .desc , __ATOMIC_RELAXED );
227231 return handle_state_rdtsc_disabled (time_usec );
228232 }
229233
230- fast_clock_desc_t next_desc = advance_state (descriptor , FC_STATE_CALIBRATING , false);
231- fast_clock_timepoint_t * timepoint = get_timepoint (fast_clock , next_desc );
234+ fast_clock_desc next_desc = advance_state (descriptor , FC_STATE_CALIBRATING , false);
235+ fast_clock_timepoint * timepoint = get_timepoint (fast_clock , next_desc );
232236 int ret = reset_timepoint (timepoint );
233237
234238 // gettimeofday failed - restore descriptor
@@ -246,7 +250,7 @@ static int handle_state_init(fast_clock_t* fast_clock, fast_clock_desc_t descrip
246250 return ret ;
247251}
248252
249- static int handle_state_calibrating (fast_clock_t * fast_clock , fast_clock_desc_t descriptor , uint64_t * time_usec )
253+ static int handle_state_calibrating (fast_clock * fast_clock , fast_clock_desc descriptor , uint64_t * time_usec )
250254{
251255 // all callers in this state will perform an OCALL - no need to set the change_state_guard before OCALLing
252256 uint64_t tmp_tsc = 0 ;
@@ -255,23 +259,23 @@ static int handle_state_calibrating(fast_clock_t* fast_clock, fast_clock_desc_t
255259 return ret ;
256260 }
257261
258- fast_clock_timepoint_t * timepoint = get_timepoint (fast_clock , descriptor );
262+ fast_clock_timepoint * timepoint = get_timepoint (fast_clock , descriptor );
259263 if (!is_expired (timepoint , * time_usec ) || !set_change_state_guard (fast_clock , descriptor )) {
260264 return ret ;
261265 }
262266
263267 // calculate the clock_freq and advance state
264268 reset_clock_frequency (timepoint , tmp_tsc , * time_usec );
265269 reset_expiration (timepoint , RDTSC_RECALIBRATION_INTERVAL );
266- fast_clock_desc_t new_desc = advance_state (descriptor , FC_STATE_RDTSC , false);
270+ fast_clock_desc new_desc = advance_state (descriptor , FC_STATE_RDTSC , false);
267271 __atomic_store_n (& fast_clock -> atomic_descriptor .desc , new_desc .desc , __ATOMIC_RELEASE );
268272
269273 return ret ;
270274}
271275
272- static inline int handle_state_rdtsc (fast_clock_t * fast_clock , fast_clock_desc_t descriptor , uint64_t * time_usec , bool force_new_timepoint )
276+ static inline int handle_state_rdtsc (fast_clock * fast_clock , fast_clock_desc descriptor , uint64_t * time_usec , bool force_new_timepoint )
273277{
274- fast_clock_timepoint_t * timepoint = get_timepoint (fast_clock , descriptor );
278+ fast_clock_timepoint * timepoint = get_timepoint (fast_clock , descriptor );
275279
276280 // fast path - calculate time with rdtsc
277281 calc_time (timepoint , time_usec );
@@ -281,8 +285,8 @@ static inline int handle_state_rdtsc(fast_clock_t* fast_clock, fast_clock_desc_t
281285 }
282286
283287 // acquire the state_change_guard and prepare the next state (get new ground truth timepoint)
284- fast_clock_desc_t next_desc = advance_state (descriptor , FC_STATE_RDTSC_RECALIBRATE , true);
285- fast_clock_timepoint_t * next_timepoint = get_timepoint (fast_clock , next_desc );
288+ fast_clock_desc next_desc = advance_state (descriptor , FC_STATE_RDTSC_RECALIBRATE , true);
289+ fast_clock_timepoint * next_timepoint = get_timepoint (fast_clock , next_desc );
286290
287291 int ret = reset_timepoint (next_timepoint );
288292 if (ret != 0 ) {
@@ -299,9 +303,9 @@ static inline int handle_state_rdtsc(fast_clock_t* fast_clock, fast_clock_desc_t
299303 return ret ;
300304}
301305
302- static inline int handle_state_rdtsc_recalibrate (fast_clock_t * fast_clock , fast_clock_desc_t descriptor , uint64_t * time_usec )
306+ static inline int handle_state_rdtsc_recalibrate (fast_clock * fast_clock , fast_clock_desc descriptor , uint64_t * time_usec )
303307{
304- fast_clock_timepoint_t * timepoint = get_timepoint (fast_clock , descriptor );
308+ fast_clock_timepoint * timepoint = get_timepoint (fast_clock , descriptor );
305309
306310 // fast path - calculate time with rdtsc
307311 calc_time (timepoint , time_usec );
@@ -318,15 +322,15 @@ static inline int handle_state_rdtsc_recalibrate(fast_clock_t* fast_clock, fast_
318322
319323 reset_clock_frequency (timepoint , tsc , * time_usec );
320324 reset_expiration (timepoint , RDTSC_RECALIBRATION_INTERVAL );
321- fast_clock_desc_t next_desc = advance_state (descriptor , FC_STATE_RDTSC , false);
325+ fast_clock_desc next_desc = advance_state (descriptor , FC_STATE_RDTSC , false);
322326 __atomic_store_n (& fast_clock -> atomic_descriptor .desc , next_desc .desc , __ATOMIC_RELEASE );
323327
324328 return ret ;
325329}
326330
327- int fast_clock_get_time (fast_clock_t * fast_clock , uint64_t * time_usec , bool force_new_timepoint )
331+ int fast_clock_get_time (fast_clock * fast_clock , uint64_t * time_usec , bool force_new_timepoint )
328332{
329- fast_clock_desc_t descriptor = {
333+ fast_clock_desc descriptor = {
330334 .desc = __atomic_load_n (& fast_clock -> atomic_descriptor .desc , __ATOMIC_ACQUIRE ),
331335 };
332336 switch (descriptor .state )
@@ -345,23 +349,23 @@ int fast_clock_get_time(fast_clock_t* fast_clock, uint64_t* time_usec, bool forc
345349 }
346350}
347351
348- bool fast_clock_is_enabled (const fast_clock_t * fast_clock )
352+ bool fast_clock_is_enabled (const fast_clock * fast_clock )
349353{
350- fast_clock_desc_t descriptor = {
354+ fast_clock_desc descriptor = {
351355 .desc = __atomic_load_n (& fast_clock -> atomic_descriptor .desc , __ATOMIC_RELAXED ),
352356 };
353357 return (descriptor .state != FC_STATE_RDTSC_DISABLED );
354358}
355359
356- void fast_clock_disable (fast_clock_t * fast_clock )
360+ void fast_clock_disable (fast_clock * fast_clock )
357361{
358362 /* We need to busy-loop until the state change guard is acquired here - since fast-clock
359363 * might be in the midst of transitioning states. We can't simply store the DISABLED state. */
360- fast_clock_desc_t descriptor ;
364+ fast_clock_desc descriptor ;
361365 do {
362366 descriptor .desc = __atomic_load_n (& fast_clock -> atomic_descriptor .desc , __ATOMIC_ACQUIRE );
363367 } while (!set_change_state_guard (fast_clock , descriptor ));
364368
365- fast_clock_desc_t disabled_desc = advance_state (descriptor , FC_STATE_RDTSC_DISABLED , false);
369+ fast_clock_desc disabled_desc = advance_state (descriptor , FC_STATE_RDTSC_DISABLED , false);
366370 __atomic_store_n (& fast_clock -> atomic_descriptor .desc , disabled_desc .desc , __ATOMIC_RELEASE );
367371}
0 commit comments