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
parent
c452e862dd
commit
06fcfe123c
5
clock.c
5
clock.c
|
@ -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))
|
||||
|
|
24
config.c
24
config.c
|
@ -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;
|
||||
|
|
1
config.h
1
config.h
|
@ -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;
|
||||
|
|
|
@ -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
2
ds.h
|
@ -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;
|
||||
|
|
1
gPTP.cfg
1
gPTP.cfg
|
@ -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
3
port.c
|
@ -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");
|
||||
|
|
8
ptp4l.8
8
ptp4l.8
|
@ -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.
|
||||
|
|
1
ptp4l.c
1
ptp4l.c
|
@ -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,
|
||||
|
|
51
tsproc.c
51
tsproc.c
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
17
tsproc.h
17
tsproc.h
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue