Skip to content

Commit 4927cdb

Browse files
committed
[PAL/LinuxSGX] fast-clock desc type cleanups
Signed-off-by: Jonathan Shamir <[email protected]>
1 parent aa8f0aa commit 4927cdb

File tree

2 files changed

+79
-92
lines changed

2 files changed

+79
-92
lines changed

pal/src/host/linux-sgx/utils/fast_clock.c

Lines changed: 57 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,10 @@
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.
@@ -104,9 +104,23 @@
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

189193
static 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
}

pal/src/host/linux-sgx/utils/fast_clock.h

Lines changed: 22 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2,62 +2,45 @@
22

33
#include <stdint.h>
44
#include <stdbool.h>
5+
#include "api.h"
56

67

7-
enum fast_clock_state_e
8-
{
9-
FC_STATE_RDTSC,
10-
FC_STATE_RDTSC_RECALIBRATE,
11-
FC_STATE_CALIBRATING,
12-
FC_STATE_INIT,
13-
14-
FC_STATE_RDTSC_DISABLED,
15-
};
16-
typedef uint16_t fast_clock_state_t;
17-
188
#define _FC_NUM_TIMEPOINT_BITS (1)
19-
#define _FC_NUM_TIMEPOINTS (1<<_FC_NUM_TIMEPOINT_BITS)
20-
21-
enum fast_clock_flags_e
22-
{
23-
FC_FLAGS_INIT = 0,
24-
25-
FC_FLAGS_TIMEPOINT_MASK = _FC_NUM_TIMEPOINTS - 1,
26-
FC_FLAGS_NUM_TIMEPOINTS = _FC_NUM_TIMEPOINTS,
27-
28-
FC_FLAGS_STATE_CHANGING = 0x8000,
29-
};
30-
typedef uint16_t fast_clock_flags_t;
9+
#define FC_NUM_TIMEPOINTS (1<<_FC_NUM_TIMEPOINT_BITS)
3110

3211
typedef union
3312
{
34-
#pragma pack(push, 1)
3513
struct
3614
{
37-
fast_clock_state_t state;
38-
fast_clock_flags_t flags;
15+
uint16_t state : 4;
16+
uint16_t timepoint_index : _FC_NUM_TIMEPOINT_BITS;
17+
uint16_t _pad0 : (16 - _FC_NUM_TIMEPOINT_BITS - 5);
18+
uint16_t state_changing : 1;
3919
};
40-
#pragma pack(pop)
4120

42-
uint32_t desc;
43-
} fast_clock_desc_t;
21+
uint16_t desc;
22+
} fast_clock_desc;
23+
24+
static_assert(_FC_NUM_TIMEPOINT_BITS >= 1, "timepoint_index must have at minimum 1-bit");
25+
static_assert(_FC_NUM_TIMEPOINT_BITS + 5 <= 16, "timepoint_index uses too many bits");
26+
static_assert(sizeof(fast_clock_desc) == sizeof(uint16_t), "fast_clock_desc size mismatch");
4427

45-
typedef struct fast_clock_timepoint_s
28+
typedef struct
4629
{
4730
uint64_t clock_freq;
4831
uint64_t tsc0;
4932
uint64_t t0_usec;
5033
uint64_t expiration_usec;
51-
} fast_clock_timepoint_t;
34+
} fast_clock_timepoint;
5235

53-
typedef struct fast_clock_s
36+
typedef struct
5437
{
55-
fast_clock_desc_t atomic_descriptor;
56-
fast_clock_timepoint_t time_points[FC_FLAGS_NUM_TIMEPOINTS];
57-
} fast_clock_t;
38+
fast_clock_desc atomic_descriptor;
39+
fast_clock_timepoint time_points[FC_NUM_TIMEPOINTS];
40+
} fast_clock;
5841

59-
extern fast_clock_t g_fast_clock;
42+
extern fast_clock g_fast_clock;
6043

61-
int fast_clock_get_time(fast_clock_t* fast_clock, uint64_t* time_micros, bool force_new_timepoint);
62-
bool fast_clock_is_enabled(const fast_clock_t* fast_clock);
63-
void fast_clock_disable(fast_clock_t* fast_clock);
44+
int fast_clock_get_time(fast_clock* fast_clock, uint64_t* time_micros, bool force_new_timepoint);
45+
bool fast_clock_is_enabled(const fast_clock* fast_clock);
46+
void fast_clock_disable(fast_clock* fast_clock);

0 commit comments

Comments
 (0)