From: Mike Brady <4265913+mikebrady@users.noreply.github.com> Date: Sat, 5 Jun 2021 16:53:52 +0000 (+0100) Subject: Add a lookback to see if the master's first offset can be improved with prior estimat... X-Git-Tag: 1.2~124 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f5308a59e7f8fbd49836693a3d0d57fd3045f1bf;p=thirdparty%2Fnqptp.git Add a lookback to see if the master's first offset can be improved with prior estimates. Doesn't seem to make any difference. Make mastership base time the time of the first follow up after attaining mastership. Seems to be important. --- diff --git a/nqptp-clock-sources.c b/nqptp-clock-sources.c index fbe5573..8d22645 100644 --- a/nqptp-clock-sources.c +++ b/nqptp-clock-sources.c @@ -20,6 +20,7 @@ #include "nqptp-clock-sources.h" #include "debug.h" #include "nqptp-ptp-definitions.h" +#include "general-utilities.h" #include #include #include @@ -68,6 +69,7 @@ int create_clock_source_record(char *sender_string, memset(&clocks_private_info[i], 0, sizeof(clock_source_private_data)); strncpy((char *)&clocks_private_info[i].ip, sender_string, FIELD_SIZEOF(clock_source_private_data, ip) - 1); + clocks_private_info[i].vacant_samples = MAX_TIMING_SAMPLES; clocks_private_info[i].in_use = 1; debug(2, "create record for ip: %s.", &clocks_private_info[i].ip); } else { @@ -202,22 +204,106 @@ void update_master() { if (old_master != -1) { // but there was a master clock, so remove it debug(1, "shm interface -- remove master clock designation"); - update_master_clock_info(0, NULL, 0, 0); + update_master_clock_info(0, NULL, 0, 0, 0); } if (timing_peer_count == 0) debug(2, "No timing peer list found"); else debug(1, "No master clock not found!"); - } else { - // we found a master clock - clocks_private[best_so_far].flags |= (1 << clock_is_master); - // master_clock_index = best_so_far; - if (old_master != best_so_far) { - clocks_private[best_so_far].previous_offset_time = 0; // resync when you become master + } else { + // we found a master clock + clocks_private[best_so_far].flags |= (1 << clock_is_master); + + if (old_master != best_so_far) { + +/* + // clang-format off + // now we use the last few samples to calculate the best offset for the + // new master clock. + + // the time of the oldest sample we use will become the time of the start of the + // mastership + + // we will accept samples that would make the local-to-clock offset greatest, + // provided they are not too old and that they don't push the current clock time + // more than, say, 1000 ms into the future. + + // this is the only time estimate we have when the clock is definitely a master + // so we use it to eliminate any previous time estimates, made when the clock wasn't designated + // a master, that would put it more than, say, a second further into the future + + // allow the samples to give a valid master clock time up to this much later than the single definitive sample we have + + uint64_t oldest_acceptable_master_clock_time = clocks_private[best_so_far].source_time + 1000000000; + + // we will try to improve on this single definitive local_to_source_time_offset we have + int changes_made = 0; + + uint64_t best_offset_so_far = clocks_private[best_so_far].local_to_source_time_offset; + uint64_t age_of_oldest_legitimate_sample = clocks_private[best_so_far].local_time; + + int number_of_samples = MAX_TIMING_SAMPLES - clocks_private[best_so_far].vacant_samples; + int samples_checked = 0; +// if (0) { + if (number_of_samples > 0) { + debug(1,"Number of samples: %d.", number_of_samples); + uint64_t time_now = get_time_now(); + uint64_t oldest_acceptable_time = time_now - 10000000000; // only go back this far (ns) + int i; + for (i = 0; i < number_of_samples; i++) { + int64_t age_relative_to_oldest_acceptable_time = clocks_private[best_so_far].samples[i].local_time - oldest_acceptable_time; + if (age_relative_to_oldest_acceptable_time > 0) { + if (clocks_private[best_so_far].samples[i].local_time < age_of_oldest_legitimate_sample) { + age_of_oldest_legitimate_sample = clocks_private[best_so_far].samples[i].local_time; + } + uint64_t possible_offset = clocks_private[best_so_far].samples[i].clock_time - clocks_private[best_so_far].samples[i].local_time; + uint64_t possible_master_clock_time = clocks_private[best_so_far].local_time + possible_offset; + int64_t age_relative_to_oldest_acceptable_master_clock_time = possible_master_clock_time - oldest_acceptable_master_clock_time; + if (age_relative_to_oldest_acceptable_master_clock_time <= 0) { + samples_checked++; + // so, the sample was not obtained too far in the past + // and it would not push the estimated master clock_time too far into the future + // so, if it is greater than the best_offset_so_far, then make it the new one + if (possible_offset > best_offset_so_far) { + debug(1,"new best offset"); + best_offset_so_far = possible_offset; + changes_made++; + } + } else { + debug(1,"sample too far into the future"); + } + } else { + debug(1,"sample too old"); + } + } + + } + +// if (changes_made == 0) { +// clocks_private[best_so_far].previous_offset_time = 0; // if you have no previous samples (how?), then resync +// clocks_private[best_so_far].mastership_start_time = clocks_private[best_so_far].local_time; +// } else { + clocks_private[best_so_far].mastership_start_time = age_of_oldest_legitimate_sample; + int64_t offset_difference = best_offset_so_far - clocks_private[best_so_far].local_to_source_time_offset; + + debug(1,"Lookback difference: %f ms with %d samples checked of %d samples total.", 0.000001 * offset_difference, samples_checked, number_of_samples); + clocks_private[best_so_far].local_to_source_time_offset = best_offset_so_far; + +// clocks_private[best_so_far].previous_offset_time = clocks_private[best_so_far].local_time; +// clocks_private[best_so_far].previous_offset = clocks_private[best_so_far].local_to_source_time_offset; +// } + + + debug(1,"Master sampling started %f ms before becoming master.", 0.000001 * (clocks_private[best_so_far].local_time - age_of_oldest_legitimate_sample)); update_master_clock_info(clocks_private[best_so_far].clock_id, (const char *)&clocks_private[best_so_far].ip, clocks_private[best_so_far].local_time, - clocks_private[best_so_far].local_to_source_time_offset); + clocks_private[best_so_far].local_to_source_time_offset, + clocks_private[best_so_far].mastership_start_time); + // clang-format on +*/ + + clocks_private[best_so_far].previous_offset_time = 0; // resync } } diff --git a/nqptp-clock-sources.h b/nqptp-clock-sources.h index 61c5b09..4820a62 100644 --- a/nqptp-clock-sources.h +++ b/nqptp-clock-sources.h @@ -32,16 +32,23 @@ typedef enum { clock_is_master } clock_flags; +#define MAX_TIMING_SAMPLES 47 + typedef struct { + uint64_t local_time, clock_time; + } timing_samples; + // information about each clock source typedef struct { char ip[64]; // 64 is nicely aligned and bigger than INET6_ADDRSTRLEN (46) uint64_t clock_id; uint64_t local_time; // the local time when the offset was calculated - uint64_t origin_time; + uint64_t source_time; uint64_t local_to_source_time_offset; // add this to the local time to get source time uint32_t flags; uint16_t in_use; uint64_t previous_offset, previous_offset_time, last_sync_time; + uint64_t mastership_start_time; // set to the time of the first sample used as master + // for garbage collection uint64_t time_of_last_use; // will be taken out of use if not used for a while and not in the // timing peer group @@ -50,6 +57,12 @@ typedef struct { uint64_t announce_times[4]; // we'll check qualification and currency using these int is_one_of_ours; // true if it is one of our own clocks + timing_samples samples[MAX_TIMING_SAMPLES]; + int vacant_samples; // the number of elements in the timing_samples array that are not yet used + int next_sample_goes_here; // point to where in the timing samples array the next entries should + // go + + // these are for finding the best clock to use // See Figure 27 and 27 pp 89 -- 90 for the Data set comparison algorithm diff --git a/nqptp-message-handlers.c b/nqptp-message-handlers.c index 7417839..3c76f7c 100644 --- a/nqptp-message-handlers.c +++ b/nqptp-message-handlers.c @@ -218,18 +218,9 @@ void handle_announce(char *buf, ssize_t recv_len, clock_source_private_data *clo void handle_follow_up(char *buf, __attribute__((unused)) ssize_t recv_len, clock_source_private_data *clock_private_info, uint64_t reception_time) { - clock_private_info->flags |= (1 << clock_is_valid); - if ((clock_private_info->flags & (1 << clock_is_master)) != 0) { - debug(2, "FOLLOWUP from %" PRIx64 ", %s.", clock_private_info->clock_id, - &clock_private_info->ip); - struct ptp_follow_up_message *msg = (struct ptp_follow_up_message *)buf; -/* - uint64_t packet_clock_id = nctohl(&msg->header.clockIdentity[0]); - uint64_t packet_clock_id_low = nctohl(&msg->header.clockIdentity[4]); - packet_clock_id = packet_clock_id << 32; - packet_clock_id = packet_clock_id + packet_clock_id_low; -*/ + clock_private_info->flags |= (1 << clock_is_valid); // valid because it has at least one follow_up + struct ptp_follow_up_message *msg = (struct ptp_follow_up_message *)buf; uint16_t seconds_hi = nctohs(&msg->follow_up.preciseOriginTimestamp[0]); uint32_t seconds_low = nctohl(&msg->follow_up.preciseOriginTimestamp[2]); @@ -240,8 +231,26 @@ void handle_follow_up(char *buf, __attribute__((unused)) ssize_t recv_len, preciseOriginTimestamp = preciseOriginTimestamp * 1000000000L; preciseOriginTimestamp = preciseOriginTimestamp + nanoseconds; - // preciseOriginTimestamp is called "t1" in the IEEE spec. - // we are using the reception time here as t2, which is a hack + // update our sample information + + clock_private_info->samples[clock_private_info->next_sample_goes_here].local_time = + reception_time; + clock_private_info->samples[clock_private_info->next_sample_goes_here] + .clock_time = preciseOriginTimestamp; + + if (clock_private_info->vacant_samples > 0) + clock_private_info->vacant_samples--; + + clock_private_info->next_sample_goes_here++; + // if we have need to wrap. + if (clock_private_info->next_sample_goes_here == MAX_TIMING_SAMPLES) + clock_private_info->next_sample_goes_here = 0; + + +// if ((clock_private_info->flags & (1 << clock_is_master)) != 0) { + if (1) { + debug(2, "FOLLOWUP from %" PRIx64 ", %s.", clock_private_info->clock_id, + &clock_private_info->ip); // check to see the difference between the previous preciseOriginTimestamp @@ -285,7 +294,7 @@ void handle_follow_up(char *buf, __attribute__((unused)) ssize_t recv_len, // 125 ms is 100 ppm. offset = clock_private_info->previous_offset + jitter; } - } else { + } else if ((clock_private_info->flags & (1 << clock_is_master)) != 0) { warn("Lost sync with clock %" PRIx64 " at %s. Resynchronising.", clock_private_info->clock_id, clock_private_info->ip); // leave the offset as it was coming in and take it as a sync time @@ -305,14 +314,14 @@ void handle_follow_up(char *buf, __attribute__((unused)) ssize_t recv_len, // clock_private_info->clock_id = packet_clock_id; clock_private_info->local_time = reception_time; - clock_private_info->origin_time = preciseOriginTimestamp; + clock_private_info->source_time = preciseOriginTimestamp; clock_private_info->local_to_source_time_offset = offset; if (old_flags != clock_private_info->flags) { update_master(); } else if ((clock_private_info->flags & (1 << clock_is_master)) != 0) { update_master_clock_info(clock_private_info->clock_id, (const char *)&clock_private_info->ip, - reception_time, offset); + reception_time, offset, clock_private_info->mastership_start_time); debug(3, "clock: %" PRIx64 ", time: %" PRIu64 ", offset: %" PRId64 ", jitter: %+f ms.", clock_private_info->clock_id, reception_time, offset, 0.000001 * jitter); } diff --git a/nqptp.c b/nqptp.c index a2e0960..f390c12 100644 --- a/nqptp.c +++ b/nqptp.c @@ -80,7 +80,7 @@ struct shm_structure *shared_memory = NULL; // this is where public clock info i int epoll_fd; void update_master_clock_info(uint64_t master_clock_id, const char *ip, uint64_t local_time, - uint64_t local_to_master_offset) { + uint64_t local_to_master_offset, uint64_t mastership_start_time) { if (shared_memory->master_clock_id != master_clock_id) debug(1, "Master clock is: %" PRIx64 ".", master_clock_id); int rc = pthread_mutex_lock(&shared_memory->shm_mutex); @@ -88,7 +88,7 @@ void update_master_clock_info(uint64_t master_clock_id, const char *ip, uint64_t warn("Can't acquire mutex to update master clock!"); if (shared_memory->master_clock_id != master_clock_id) { shared_memory->master_clock_id = master_clock_id; - shared_memory->master_clock_start_time = get_time_now(); + shared_memory->master_clock_start_time = local_time; } if (ip != NULL) strncpy((char *)&shared_memory->master_clock_ip, ip, diff --git a/nqptp.h b/nqptp.h index c1da9eb..714f995 100644 --- a/nqptp.h +++ b/nqptp.h @@ -32,6 +32,6 @@ extern int master_clock_index; extern struct shm_structure *shared_memory; void update_master_clock_info(uint64_t master_clock_id, const char *ip, uint64_t local_time, - uint64_t local_to_master_offset); + uint64_t local_to_master_offset, uint64_t mastership_start_time); #endif \ No newline at end of file