tsproc: add raw and weighting modes.

Add new time stamp processing modes to return raw delay and offset based
on the raw delay instead of the long-term filtered delay, and to return
also a weight of the sample. The weight is set to the ratio between the
two delays. This gives smaller weight to samples where the sync and/or
delay messages were delayed significantly in the network and possibly
include a large error.

Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
master
Miroslav Lichvar 2015-03-26 16:32:14 +01:00 committed by Richard Cochran
parent c452e862dd
commit 06fcfe123c
11 changed files with 104 additions and 10 deletions

View File

@ -852,7 +852,8 @@ struct clock *clock_create(int phc_index, struct interfaces_head *ifaces,
}
c->servo_state = SERVO_UNLOCKED;
c->servo_type = servo;
c->tsproc = tsproc_create(dds->delay_filter, dds->delay_filter_length);
c->tsproc = tsproc_create(dds->tsproc_mode, dds->delay_filter,
dds->delay_filter_length);
if (!c->tsproc) {
pr_err("Failed to create time stamp processor");
return NULL;
@ -1357,7 +1358,7 @@ enum servo_state clock_synchronize(struct clock *c, tmv_t ingress, tmv_t origin)
tsproc_down_ts(c->tsproc, origin, ingress);
if (tsproc_update_offset(c->tsproc, &c->master_offset))
if (tsproc_update_offset(c->tsproc, &c->master_offset, NULL))
return state;
if (clock_utc_correct(c, ingress))

View File

@ -203,6 +203,18 @@ static enum parser_result parse_port_setting(const char *option,
else
return BAD_VALUE;
} else if (!strcmp(option, "tsproc_mode")) {
if (!strcasecmp("filter", value))
iface->tsproc_mode = TSPROC_FILTER;
else if (!strcasecmp("raw", value))
iface->tsproc_mode = TSPROC_RAW;
else if (!strcasecmp("filter_weight", value))
iface->tsproc_mode = TSPROC_FILTER_WEIGHT;
else if (!strcasecmp("raw_weight", value))
iface->tsproc_mode = TSPROC_RAW_WEIGHT;
else
return BAD_VALUE;
} else if (!strcmp(option, "delay_filter")) {
if (!strcasecmp("moving_average", value))
iface->delay_filter = FILTER_MOVING_AVERAGE;
@ -566,6 +578,18 @@ static enum parser_result parse_global_setting(const char *option,
return r;
cfg->dds.time_source = val;
} else if (!strcmp(option, "tsproc_mode")) {
if (!strcasecmp("filter", value))
cfg->dds.tsproc_mode = TSPROC_FILTER;
else if (!strcasecmp("raw", value))
cfg->dds.tsproc_mode = TSPROC_RAW;
else if (!strcasecmp("filter_weight", value))
cfg->dds.tsproc_mode = TSPROC_FILTER_WEIGHT;
else if (!strcasecmp("raw_weight", value))
cfg->dds.tsproc_mode = TSPROC_RAW_WEIGHT;
else
return BAD_VALUE;
} else if (!strcmp(option, "delay_filter")) {
if (!strcasecmp("moving_average", value))
cfg->dds.delay_filter = FILTER_MOVING_AVERAGE;

View File

@ -39,6 +39,7 @@ struct interface {
enum transport_type transport;
struct port_defaults pod;
struct sk_ts_info ts_info;
enum tsproc_mode tsproc_mode;
enum filter_type delay_filter;
int delay_filter_length;
int boundary_clock_jbod;

View File

@ -68,6 +68,7 @@ uds_address /var/run/ptp4l
network_transport UDPv4
delay_mechanism E2E
time_stamping hardware
tsproc_mode filter
delay_filter moving_median
delay_filter_length 10
egressLatency 0

2
ds.h
View File

@ -23,6 +23,7 @@
#include "ddt.h"
#include "fault.h"
#include "filter.h"
#include "tsproc.h"
/* clock data sets */
@ -59,6 +60,7 @@ struct default_ds {
int sanity_freq_limit;
int time_source;
struct clock_description clock_desc;
enum tsproc_mode tsproc_mode;
enum filter_type delay_filter;
int delay_filter_length;
int boundary_clock_jbod;

View File

@ -67,6 +67,7 @@ uds_address /var/run/ptp4l
network_transport L2
delay_mechanism P2P
time_stamping hardware
tsproc_mode filter
delay_filter moving_median
delay_filter_length 10
egressLatency 0

3
port.c
View File

@ -2534,7 +2534,8 @@ struct port *port_open(int phc_index,
p->delayMechanism = interface->dm;
p->versionNumber = PTP_VERSION;
p->tsproc = tsproc_create(interface->delay_filter,
p->tsproc = tsproc_create(interface->tsproc_mode,
interface->delay_filter,
interface->delay_filter_length);
if (!p->tsproc) {
pr_err("Failed to create time stamp processor");

View File

@ -197,6 +197,14 @@ greater than this value the port is marked as not 802.1AS capable.
Lower limit for peer delay in nanoseconds. If the estimated peer delay is
smaller than this value the port is marked as not 802.1AS capable.
.TP
.B tsproc_mode
Select the time stamp processing mode used to calculate offset and delay.
Possible values are filter, raw, filter_weight, raw_weight. Raw modes perform
well when the rate of sync messages (logSyncInterval) is similar to the rate of
delay messages (logMinDelayReqInterval or logMinPdelayReqInterval). Weighting
is useful with larger network jitters (e.g. software time stamping).
The default is filter.
.TP
.B delay_filter
Select the algorithm used to filter the measured delay and peer delay. Possible
values are moving_average and moving_median.

View File

@ -73,6 +73,7 @@ static struct config cfg_settings = {
.userDescription = { .max_symbols = 128 },
.manufacturerIdentity = { 0, 0, 0 },
},
.tsproc_mode = TSPROC_FILTER,
.delay_filter = FILTER_MOVING_MEDIAN,
.delay_filter_length = 10,
.boundary_clock_jbod = 0,

View File

@ -25,6 +25,10 @@
#include "print.h"
struct tsproc {
/* Processing options */
int raw_mode;
int weighting;
/* Current ratio between remote and local clock frequency */
double clock_rate_ratio;
@ -43,7 +47,8 @@ struct tsproc {
struct filter *delay_filter;
};
struct tsproc *tsproc_create(enum filter_type delay_filter, int filter_length)
struct tsproc *tsproc_create(enum tsproc_mode mode,
enum filter_type delay_filter, int filter_length)
{
struct tsproc *tsp;
@ -51,6 +56,28 @@ struct tsproc *tsproc_create(enum filter_type delay_filter, int filter_length)
if (!tsp)
return NULL;
switch (mode) {
case TSPROC_FILTER:
tsp->raw_mode = 0;
tsp->weighting = 0;
break;
case TSPROC_RAW:
tsp->raw_mode = 1;
tsp->weighting = 0;
break;
case TSPROC_FILTER_WEIGHT:
tsp->raw_mode = 0;
tsp->weighting = 1;
break;
case TSPROC_RAW_WEIGHT:
tsp->raw_mode = 1;
tsp->weighting = 1;
break;
default:
free(tsp);
return NULL;
}
tsp->delay_filter = filter_create(delay_filter, filter_length);
if (!tsp->delay_filter) {
free(tsp);
@ -128,24 +155,38 @@ int tsproc_update_delay(struct tsproc *tsp, tmv_t *delay)
tsp->filtered_delay, raw_delay);
if (delay)
*delay = tsp->filtered_delay;
*delay = tsp->raw_mode ? raw_delay : tsp->filtered_delay;
return 0;
}
int tsproc_update_offset(struct tsproc *tsp, tmv_t *offset)
int tsproc_update_offset(struct tsproc *tsp, tmv_t *offset, double *weight)
{
tmv_t delay;
tmv_t delay, raw_delay = 0;
if (tmv_is_zero(tsp->t1) || tmv_is_zero(tsp->t2) ||
tmv_is_zero(tsp->t3) || tmv_is_zero(tsp->t4))
return -1;
delay = tsp->filtered_delay;
if (tsp->raw_mode || tsp->weighting)
raw_delay = get_raw_delay(tsp);
delay = tsp->raw_mode ? raw_delay : tsp->filtered_delay;
/* offset = t2 - t1 - delay */
*offset = tmv_sub(tmv_sub(tsp->t2, tsp->t1), delay);
if (!weight)
return 0;
if (tsp->weighting && tsp->filtered_delay > 0 && raw_delay > 0) {
*weight = (double)tsp->filtered_delay / raw_delay;
if (*weight > 1.0)
*weight = 1.0;
} else {
*weight = 1.0;
}
return 0;
}

View File

@ -25,13 +25,25 @@
/** Opaque type */
struct tsproc;
/**
* Defines the available modes.
*/
enum tsproc_mode {
TSPROC_FILTER,
TSPROC_RAW,
TSPROC_FILTER_WEIGHT,
TSPROC_RAW_WEIGHT,
};
/**
* Create a new instance of the time stamp processor.
* @param mode Time stamp processing mode.
* @param delay_filter Type of the filter that will be applied to delay.
* @param filter_length Length of the filter.
* @return A pointer to a new tsproc on success, NULL otherwise.
*/
struct tsproc *tsproc_create(enum filter_type delay_filter, int filter_length);
struct tsproc *tsproc_create(enum tsproc_mode mode,
enum filter_type delay_filter, int filter_length);
/**
* Destroy a time stamp processor.
@ -82,9 +94,10 @@ int tsproc_update_delay(struct tsproc *tsp, tmv_t *delay);
* Update offset in a time stamp processor using new measurements.
* @param tsp Pointer obtained via @ref tsproc_create().
* @param offset A pointer to store the new offset.
* @param weight A pointer to store the weight of the sample, may be NULL.
* @return 0 on success, -1 when missing a measurement.
*/
int tsproc_update_offset(struct tsproc *tsp, tmv_t *offset);
int tsproc_update_offset(struct tsproc *tsp, tmv_t *offset, double *weight);
/**
* Reset a time stamp processor.