Skip to content

Commit e4e39b6

Browse files
vvfedorenkofacebook-github-bot
authored andcommitted
add approximation coefficient
Summary: The difference between system clock speed and PHC speed may be so huge that the linear approximation will fail to provide monotonically increasing time. For example, we run PHC time reader every ~10ms, the observed situation on dns09.28.lla1 was: ``` oldSysTimeNS=1749167822494826022 newSysTimeNS=1749167822504951677 diff=10125655ns oldPhcTimeNS=1749167859494830869 newPhcTimeNS=1749167859504956519 diff=10125650ns ``` That means that the system time on the hosts went faster then PHC time during one of 10ms interval. Now if we will take a system time of 1749167822504951676 ( 1 ns before new system time) and try to linearly extrapolate PHC time using the diff between previous system time and the time point we chose, we will get PHC time equal to 1749167859504956523. But this value is 4 ns bigger than the next PHC value we read. That means the PHC time is not monotonic anymore. But if will apply correction coefficient of -493 PPB (ns/s), the corrected value will not be bigger then new read. Re-arrange structure to fill in gaps and reduce the growth by only 4 bytes. Reviewed By: t3lurid3 Differential Revision: D76096414 fbshipit-source-id: 608d79183c1c105fff99df45c8f24d8bc69fef44
1 parent 25fecc7 commit e4e39b6

4 files changed

Lines changed: 85 additions & 19 deletions

File tree

fbclock/cpp_test/test.cpp

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,9 +151,9 @@ int writer_thread_v2(int sfd_rw, int tries) {
151151
.ingress_time_ns = 1,
152152
.error_bound_ns = 2,
153153
.holdover_multiplier_ns = 3,
154+
.clockId = CLOCK_MONOTONIC_RAW,
154155
.phc_time_ns = 1748164346441310791,
155156
.sysclock_time_ns = 1748164309441310791,
156-
.clockId = CLOCK_MONOTONIC_RAW,
157157
};
158158
for (int i = 0; i < tries; i++) {
159159
err = fbclock_clockdata_store_data_v2(sfd_rw, &data);
@@ -290,6 +290,63 @@ TEST(fbclockTest, test_fbclock_calculate_time) {
290290
EXPECT_EQ(truetime.latest_ns, 1647290691804195223);
291291
}
292292

293+
TEST(fbclockTest, test_fbclock_calculate_time_v2) {
294+
int err;
295+
fbclock_truetime truetime;
296+
fbclock_clockdata_v2 state = {
297+
.ingress_time_ns = 1647269091803102957,
298+
.clockId = CLOCK_MONOTONIC_RAW,
299+
// phc time is before ingress time, error
300+
.phc_time_ns = 1647269082943150996,
301+
};
302+
double error_bound = 172.0;
303+
double h_value = 50.5;
304+
305+
struct timespec tp = {};
306+
clock_gettime(CLOCK_MONOTONIC_RAW, &tp);
307+
308+
int64_t sysclock_time_ns = tp.tv_sec * 1000000000 + tp.tv_nsec;
309+
state.sysclock_time_ns = sysclock_time_ns;
310+
311+
err = fbclock_calculate_time_v2(
312+
error_bound,
313+
h_value,
314+
&state,
315+
sysclock_time_ns + 1000, // + 1us
316+
&truetime,
317+
FBCLOCK_TAI);
318+
ASSERT_EQ(err, FBCLOCK_E_PHC_IN_THE_PAST);
319+
320+
// phc time is after ingress time, all good
321+
state = {
322+
.ingress_time_ns = 1647269082943150996,
323+
.clockId = CLOCK_MONOTONIC_RAW,
324+
.phc_time_ns = 1647269091803102957,
325+
.sysclock_time_ns = sysclock_time_ns,
326+
.coef_ppb = 12,
327+
};
328+
err = fbclock_calculate_time_v2(
329+
error_bound,
330+
h_value,
331+
&state,
332+
sysclock_time_ns + 1000,
333+
&truetime,
334+
FBCLOCK_TAI);
335+
ASSERT_EQ(err, 0);
336+
337+
EXPECT_EQ(truetime.earliest_ns, 1647269091803103381);
338+
EXPECT_EQ(truetime.latest_ns, 1647269091803104619);
339+
340+
// WOU is very big
341+
error_bound = 1000.0;
342+
sysclock_time_ns += 6 * 3600 * 1000000000ULL; // + 6 hours
343+
err = fbclock_calculate_time_v2(
344+
error_bound, h_value, &state, sysclock_time_ns, &truetime, FBCLOCK_TAI);
345+
ASSERT_EQ(err, 0);
346+
EXPECT_EQ(truetime.earliest_ns, 1647290691803360857);
347+
EXPECT_EQ(truetime.latest_ns, 1647290691803363751);
348+
}
349+
293350
TEST(fbclockTest, test_fbclock_apply_smear_after_2017_leap_second) {
294351
uint64_t offset_pre_ns = 36e9;
295352
uint64_t offset_post_ns = 37e9;

fbclock/fbclock.c

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -310,26 +310,25 @@ int fbclock_calculate_time_v2(
310310
uint64_t error_bound_ns,
311311
double h_value_ns,
312312
fbclock_clockdata_v2* state,
313-
int64_t phc_time_ns,
314-
int64_t sysclock_time_ns,
315313
int64_t sysclock_time_now_ns,
316314
fbclock_truetime* truetime,
317315
int time_standard) {
316+
int64_t phc_time_ns = state->phc_time_ns;
318317
if (state->ingress_time_ns > phc_time_ns) {
319318
return FBCLOCK_E_PHC_IN_THE_PAST;
320319
}
321320
// check how far back since last SYNC message from GM (in seconds)
322321
double seconds =
323322
(double)(phc_time_ns - state->ingress_time_ns) / NANOSECONDS_IN_SECONDS;
324323

324+
int64_t diff_ns = sysclock_time_now_ns - state->sysclock_time_ns;
325+
phc_time_ns += diff_ns + diff_ns * state->coef_ppb / NANOSECONDS_IN_SECONDS;
326+
325327
// UTC offset applied if time standard used is UTC (and not TAI)
326328
if (time_standard == FBCLOCK_UTC) {
327329
phc_time_ns = fbclock_apply_utc_offset_v2(state, phc_time_ns);
328330
}
329331

330-
int64_t diff_ns = sysclock_time_now_ns - sysclock_time_ns;
331-
phc_time_ns += diff_ns;
332-
333332
// calculate the Window of Uncertainty (WOU) (in nanoseconds)
334333
uint64_t wou_ns =
335334
fbclock_window_of_uncertainty(seconds, error_bound_ns, h_value_ns);
@@ -403,7 +402,7 @@ int fbclock_gettime_tz_v2(
403402
double h_value = (double)state.holdover_multiplier_ns / FBCLOCK_POW2_16;
404403

405404
struct timespec ts;
406-
if (clock_gettime(CLOCK_MONOTONIC_RAW, &ts) == -1) {
405+
if (clock_gettime(state.clockId, &ts) == -1) {
407406
return FBCLOCK_E_PTP_READ_OFFSET;
408407
}
409408
int64_t sysclock_time_now_ns =
@@ -413,8 +412,6 @@ int fbclock_gettime_tz_v2(
413412
error_bound,
414413
h_value,
415414
&state,
416-
state.phc_time_ns,
417-
state.sysclock_time_ns,
418415
sysclock_time_now_ns,
419416
truetime,
420417
time_standard);

fbclock/fbclock.h

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,15 +80,17 @@ typedef struct fbclock_clockdata_v2 {
8080
// end time (TAI) to stop smearing clock
8181
uint64_t clock_smearing_end_s;
8282
// UTC offset before latest published leap second (tzdata)
83-
int32_t utc_offset_pre_s;
83+
int16_t utc_offset_pre_s;
8484
// UTC offset after latest published leap second (tzdata)
85-
int32_t utc_offset_post_s;
85+
int16_t utc_offset_post_s;
86+
// we may have sys clock read with MONOTONIC_RAW or REALTIME clock source
87+
uint32_t clockId;
8688
// periodically updated PHC time
8789
int64_t phc_time_ns;
8890
// system clock time received during periodical update of PHC time
8991
int64_t sysclock_time_ns;
90-
// we may have sys clock read with MONOTONIC_RAW or REALTIME clock source
91-
uint32_t clockId;
92+
// extrapolation coefficient in PPB
93+
int64_t coef_ppb;
9294

9395
} fbclock_clockdata_v2;
9496

@@ -148,6 +150,13 @@ int fbclock_calculate_time(
148150
int64_t phctime_ns,
149151
fbclock_truetime* truetime,
150152
int timezone);
153+
int fbclock_calculate_time_v2(
154+
uint64_t error_bound_ns,
155+
double h_value_ns,
156+
fbclock_clockdata_v2* state,
157+
int64_t sysclock_time_now_ns,
158+
fbclock_truetime* truetime,
159+
int timezone);
151160
uint64_t fbclock_apply_utc_offset(fbclock_clockdata* state, int64_t phctime_ns);
152161
uint64_t fbclock_apply_utc_offset_v2(
153162
fbclock_clockdata_v2* state,

fbclock/shmem.go

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,12 @@ type DataV2 struct {
9494
HoldoverMultiplierNS float64 // float stored as multiplier of 2**16
9595
SmearingStartS uint64 // Smearing starts before the Leap Second Event Time (midnight on June-30 or Dec-31)
9696
SmearingEndS uint64 // Smearing ends after the Leap Second Event Time (midnight on June-30 or Dec-31)
97-
UTCOffsetPreS int32 // UTC Offset before Leap Second Event
98-
UTCOffsetPostS int32 // UTC Offset after Leap Second Event
97+
UTCOffsetPreS int16 // UTC Offset before Leap Second Event
98+
UTCOffsetPostS int16 // UTC Offset after Leap Second Event
99+
ClockID uint32 // Clock ID of SysclockTimeNS (MONOTONIC_RAW or REALTIME)
99100
PHCTimeNS int64 // Periodically updated PHC time used to calculate real PHC time
100101
SysclockTimeNS int64 // Periodically updated system clock time (MONOTONIC_RAW or REALTIME) received with PHC time
101-
ClockID uint32 // Clock ID of SysclockTimeNS (MONOTONIC_RAW or REALTIME)
102+
CoefPPB int64 // Coefficient of the approximation of the PHC time
102103
}
103104

104105
// OpenFBClockShmCustom returns opened POSIX shared mem used by fbclock,
@@ -227,11 +228,12 @@ func StoreFBClockDataV2(fd uintptr, d DataV2) error {
227228
holdover_multiplier_ns: C.uint32_t(FloatAsUint32(d.HoldoverMultiplierNS)),
228229
clock_smearing_start_s: C.uint64_t(d.SmearingStartS),
229230
clock_smearing_end_s: C.uint64_t(d.SmearingEndS),
230-
utc_offset_pre_s: C.int32_t(d.UTCOffsetPreS),
231-
utc_offset_post_s: C.int32_t(d.UTCOffsetPostS),
231+
utc_offset_pre_s: C.int16_t(d.UTCOffsetPreS),
232+
utc_offset_post_s: C.int16_t(d.UTCOffsetPostS),
233+
clockId: C.uint32_t(d.ClockID),
232234
phc_time_ns: C.int64_t(d.PHCTimeNS),
233235
sysclock_time_ns: C.int64_t(d.SysclockTimeNS),
234-
clockId: C.uint32_t(d.ClockID),
236+
coef_ppb: C.int64_t(d.CoefPPB),
235237
}
236238
// fbclock_clockdata_store_data comes from fbclock.c
237239
res := C.fbclock_clockdata_store_data_v2(C.uint(fd), cData)
@@ -257,5 +259,6 @@ func ReadFBClockDataV2(shmp unsafe.Pointer) (*DataV2, error) {
257259
PHCTimeNS: int64(cData.phc_time_ns),
258260
SysclockTimeNS: int64(cData.sysclock_time_ns),
259261
ClockID: uint32(cData.clockId),
262+
CoefPPB: int64(cData.coef_ppb),
260263
}, nil
261264
}

0 commit comments

Comments
 (0)