From: Joseph Matan <joseph.matan...@gmail.com>

The percentile filter can be very useful when running in a non-ptp-aware 
environment.
For example, if we set a low percentile value (and the filter length is large 
enough),
we can still get a good estimation of the real delay,
even if our setup is running under heavy network traffic.
(when setting the percentile value to 0.50, the median filter is a private 
use-case of the percentile filter)

Signed-off-by: Joseph Matan <joseph.matan...@gmail.com>
---
 clock.c                    |  3 ++-
 config.c                   |  6 ++++--
 configs/default.cfg        |  1 +
 filter.c                   |  8 +++++---
 filter.h                   |  8 +++++---
 makefile                   |  2 +-
 mmedian.c => mpercentile.c | 42 +++++++++++++++++++++-----------------
 mmedian.h => mpercentile.h | 10 ++++-----
 nsm.c                      |  2 +-
 port.c                     |  3 ++-
 ptp4l.8                    |  6 +++++-
 tsproc.c                   |  4 ++--
 tsproc.h                   |  3 ++-
 13 files changed, 58 insertions(+), 40 deletions(-)
 rename mmedian.c => mpercentile.c (64%)
 rename mmedian.h => mpercentile.h (81%)

diff --git a/clock.c b/clock.c
index ec70f91..9c4b6cc 100644
--- a/clock.c
+++ b/clock.c
@@ -1171,7 +1171,8 @@ struct clock *clock_create(enum clock_type type, struct 
config *config,
        }
        c->tsproc = tsproc_create(config_get_int(config, NULL, "tsproc_mode"),
                                  config_get_int(config, NULL, "delay_filter"),
-                                 config_get_int(config, NULL, 
"delay_filter_length"));
+                                 config_get_int(config, NULL, 
"delay_filter_length"),
+                                 config_get_double(config, NULL, 
"delay_filter_percentile"));
        if (!c->tsproc) {
                pr_err("Failed to create time stamp processor");
                return NULL;
diff --git a/config.c b/config.c
index eb8b988..31351f4 100644
--- a/config.c
+++ b/config.c
@@ -158,8 +158,9 @@ static struct config_enum dataset_comp_enu[] = {
 };
 
 static struct config_enum delay_filter_enu[] = {
-       { "moving_average", FILTER_MOVING_AVERAGE },
-       { "moving_median",  FILTER_MOVING_MEDIAN  },
+       { "moving_average",     FILTER_MOVING_AVERAGE       },
+       { "moving_median",      FILTER_MOVING_MEDIAN        },
+       { "moving_percentile",  FILTER_MOVING_PERCENTILE    },
        { NULL, 0 },
 };
 
@@ -238,6 +239,7 @@ struct config_item config_tab[] = {
        PORT_ITEM_INT("delayAsymmetry", 0, INT_MIN, INT_MAX),
        PORT_ITEM_ENU("delay_filter", FILTER_MOVING_MEDIAN, delay_filter_enu),
        PORT_ITEM_INT("delay_filter_length", 10, 1, INT_MAX),
+       PORT_ITEM_DBL("delay_filter_percentile", 0.5, 0.0, 1.0),
        PORT_ITEM_ENU("delay_mechanism", DM_E2E, delay_mech_enu),
        GLOB_ITEM_INT("dscp_event", 0, 0, 63),
        GLOB_ITEM_INT("dscp_general", 0, 0, 63),
diff --git a/configs/default.cfg b/configs/default.cfg
index d615610..29cba1a 100644
--- a/configs/default.cfg
+++ b/configs/default.cfg
@@ -102,6 +102,7 @@ time_stamping               hardware
 tsproc_mode            filter
 delay_filter           moving_median
 delay_filter_length    10
+delay_filter_percentile        0.5
 egressLatency          0
 ingressLatency         0
 boundary_clock_jbod    0
diff --git a/filter.c b/filter.c
index fceb29a..f779280 100644
--- a/filter.c
+++ b/filter.c
@@ -19,15 +19,17 @@
 
 #include "filter_private.h"
 #include "mave.h"
-#include "mmedian.h"
+#include "mpercentile.h"
 
-struct filter *filter_create(enum filter_type type, int length)
+struct filter *filter_create(enum filter_type type, int length, double 
percentile)
 {
        switch (type) {
        case FILTER_MOVING_AVERAGE:
                return mave_create(length);
        case FILTER_MOVING_MEDIAN:
-               return mmedian_create(length);
+               return mpercentile_create(length, 0.5);
+       case FILTER_MOVING_PERCENTILE:
+               return mpercentile_create(length, percentile);
        default:
                return NULL;
        }
diff --git a/filter.h b/filter.h
index 5a196bc..78be629 100644
--- a/filter.h
+++ b/filter.h
@@ -31,15 +31,17 @@ struct filter;
 enum filter_type {
        FILTER_MOVING_AVERAGE,
        FILTER_MOVING_MEDIAN,
+       FILTER_MOVING_PERCENTILE,
 };
 
 /**
  * Create a new instance of a filter.
- * @param type    The type of the filter to create.
- * @param length  The filter's length.
+ * @param type          The type of the filter to create.
+ * @param length        The filter's length.
+ * @param percentile    The percentile of the delay filter samples (valid only 
for FILTER_MOVING_PERCENTILE filter type).
  * @return A pointer to a new filter on success, NULL otherwise.
  */
-struct filter *filter_create(enum filter_type type, int length);
+struct filter *filter_create(enum filter_type type, int length, double 
percentile);
 
 /**
  * Destroy an instance of a filter.
diff --git a/makefile b/makefile
index 33e7ca0..7de5eab 100644
--- a/makefile
+++ b/makefile
@@ -23,7 +23,7 @@ VER     = -DVER=$(version)
 CFLAGS = -Wall $(VER) $(incdefs) $(DEBUG) $(EXTRA_CFLAGS)
 LDLIBS = -lm -lrt -pthread $(EXTRA_LDFLAGS)
 PRG    = ptp4l hwstamp_ctl nsm phc2sys phc_ctl pmc timemaster ts2phc
-FILTERS        = filter.o mave.o mmedian.o
+FILTERS        = filter.o mave.o mpercentile.o
 SERVOS = linreg.o ntpshm.o nullf.o pi.o servo.o
 TRANSP = raw.o transport.o udp.o udp6.o uds.o
 TS2PHC = ts2phc.o lstab.o nmea.o serial.o sock.o ts2phc_generic_master.o \
diff --git a/mmedian.c b/mpercentile.c
similarity index 64%
rename from mmedian.c
rename to mpercentile.c
index 2383467..cb4010b 100644
--- a/mmedian.c
+++ b/mpercentile.c
@@ -1,5 +1,5 @@
 /**
- * @file mmedian.c
+ * @file mpercentile.c
  * @note Copyright (C) 2013 Miroslav Lichvar <mlich...@redhat.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -19,36 +19,41 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include "mmedian.h"
+#include "mpercentile.h"
 #include "filter_private.h"
+#include "print.h"
+#include "math.h"
 
-struct mmedian {
+struct mpercentile {
        struct filter filter;
        int cnt;
        int len;
        int index;
+       double percentile;
+       int percentile_index;
        /* Indices sorted by value. */
        int *order;
        /* Values stored in circular buffer. */
        tmv_t *samples;
 };
 
-static void mmedian_destroy(struct filter *filter)
+static void mpercentile_destroy(struct filter *filter)
 {
-       struct mmedian *m = container_of(filter, struct mmedian, filter);
+       struct mpercentile *m = container_of(filter, struct mpercentile, 
filter);
        free(m->order);
        free(m->samples);
        free(m);
 }
 
-static tmv_t mmedian_sample(struct filter *filter, tmv_t sample)
+static tmv_t mpercentile_sample(struct filter *filter, tmv_t sample)
 {
-       struct mmedian *m = container_of(filter, struct mmedian, filter);
+       struct mpercentile *m = container_of(filter, struct mpercentile, 
filter);
        int i;
 
        m->samples[m->index] = sample;
        if (m->cnt < m->len) {
                m->cnt++;
+               m->percentile_index = (int)round(m->percentile * (m->cnt - 1));
        } else {
                /* Remove index of the replaced value from order. */
                for (i = 0; i < m->cnt; i++)
@@ -69,32 +74,30 @@ static tmv_t mmedian_sample(struct filter *filter, tmv_t 
sample)
 
        m->index = (1 + m->index) % m->len;
 
-       if (m->cnt % 2)
-               return m->samples[m->order[m->cnt / 2]];
-       else
-               return tmv_div(tmv_add(m->samples[m->order[m->cnt / 2 - 1]],
-                                      m->samples[m->order[m->cnt / 2]]), 2);
+       /*TODO: deleteMe*/ pr_info("lenght(%d) percentile(%0.2f) 
percentile_index(%d), filtered_delay(%lld)", 
+        m->cnt, m->percentile, m->percentile_index, 
tmv_to_nanoseconds(m->samples[m->order[m->percentile_index]]));
+       return m->samples[m->order[m->percentile_index]];
 }
 
-static void mmedian_reset(struct filter *filter)
+static void mpercentile_reset(struct filter *filter)
 {
-       struct mmedian *m = container_of(filter, struct mmedian, filter);
+       struct mpercentile *m = container_of(filter, struct mpercentile, 
filter);
        m->cnt = 0;
        m->index = 0;
 }
 
-struct filter *mmedian_create(int length)
+struct filter *mpercentile_create(int length, double percentile)
 {
-       struct mmedian *m;
+       struct mpercentile *m;
 
        if (length < 1)
                return NULL;
        m = calloc(1, sizeof(*m));
        if (!m)
                return NULL;
-       m->filter.destroy = mmedian_destroy;
-       m->filter.sample = mmedian_sample;
-       m->filter.reset = mmedian_reset;
+       m->filter.destroy = mpercentile_destroy;
+       m->filter.sample = mpercentile_sample;
+       m->filter.reset = mpercentile_reset;
        m->order = calloc(1, length * sizeof(*m->order));
        if (!m->order) {
                free(m);
@@ -107,5 +110,6 @@ struct filter *mmedian_create(int length)
                return NULL;
        }
        m->len = length;
+       m->percentile = percentile;
        return &m->filter;
 }
diff --git a/mmedian.h b/mpercentile.h
similarity index 81%
rename from mmedian.h
rename to mpercentile.h
index 8fee0dc..193a333 100644
--- a/mmedian.h
+++ b/mpercentile.h
@@ -1,6 +1,6 @@
 /**
- * @file mmedian.h
- * @brief Implements a moving median.
+ * @file mpercentile.h
+ * @brief Implements a moving percentile.
  * @note Copyright (C) 2013 Miroslav Lichvar <mlich...@redhat.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -17,11 +17,11 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
-#ifndef HAVE_MMEDIAN_H
-#define HAVE_MMEDIAN_H
+#ifndef HAVE_MPERCENTILE_H
+#define HAVE_MPERCENTILE_H
 
 #include "filter.h"
 
-struct filter *mmedian_create(int length);
+struct filter *mpercentile_create(int length, double percentile);
 
 #endif
diff --git a/nsm.c b/nsm.c
index 5aa925b..3ede6a0 100644
--- a/nsm.c
+++ b/nsm.c
@@ -295,7 +295,7 @@ static int nsm_open(struct nsm *nsm, struct config *cfg)
        }
        nsm->port_identity.portNumber = 1;
 
-       nsm->tsproc = tsproc_create(TSPROC_RAW, FILTER_MOVING_AVERAGE, 10);
+       nsm->tsproc = tsproc_create(TSPROC_RAW, FILTER_MOVING_AVERAGE, 10, 0);
        if (!nsm->tsproc) {
                pr_err("failed to create time stamp processor");
                goto no_tsproc;
diff --git a/port.c b/port.c
index c82bdaf..6dae97b 100644
--- a/port.c
+++ b/port.c
@@ -3200,7 +3200,8 @@ struct port *port_open(const char *phc_device,
 
        p->tsproc = tsproc_create(config_get_int(cfg, p->name, "tsproc_mode"),
                                  config_get_int(cfg, p->name, "delay_filter"),
-                                 config_get_int(cfg, p->name, 
"delay_filter_length"));
+                                 config_get_int(cfg, p->name, 
"delay_filter_length"),
+                                 config_get_double(cfg, p->name, 
"delay_filter_percentile")); 
        if (!p->tsproc) {
                pr_err("Failed to create time stamp processor");
                goto err_uc_service;
diff --git a/ptp4l.8 b/ptp4l.8
index a0779ef..3a3fc13 100644
--- a/ptp4l.8
+++ b/ptp4l.8
@@ -340,13 +340,17 @@ 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.
+values are moving_average, moving_median and moving_percentile.
 The default is moving_median.
 .TP
 .B delay_filter_length
 The length of the delay filter in samples.
 The default is 10.
 .TP
+.B delay_filter_percentile
+The percentile of the delay filter samples (relevant only when choosing the 
delay_filter as moving_percentile).
+The default is 0.5 (50%).
+.TP
 .B egressLatency
 Specifies the difference in nanoseconds between the actual transmission
 time at the reference plane and the reported transmit time stamp. This
diff --git a/tsproc.c b/tsproc.c
index a871049..8ace4a6 100644
--- a/tsproc.c
+++ b/tsproc.c
@@ -61,7 +61,7 @@ static int weighting(struct tsproc *tsp)
 }
 
 struct tsproc *tsproc_create(enum tsproc_mode mode,
-                            enum filter_type delay_filter, int filter_length)
+                            enum filter_type delay_filter, int filter_length, 
double percentile)
 {
        struct tsproc *tsp;
 
@@ -81,7 +81,7 @@ struct tsproc *tsproc_create(enum tsproc_mode mode,
                return NULL;
        }
 
-       tsp->delay_filter = filter_create(delay_filter, filter_length);
+       tsp->delay_filter = filter_create(delay_filter, filter_length, 
percentile);
        if (!tsp->delay_filter) {
                free(tsp);
                return NULL;
diff --git a/tsproc.h b/tsproc.h
index fdb35a8..5970705 100644
--- a/tsproc.h
+++ b/tsproc.h
@@ -40,10 +40,11 @@ enum tsproc_mode {
  * @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.
+ * @param percentile     The percentile of the delay filter samples (valid 
only for FILTER_MOVING_PERCENTILE filter type).
  * @return               A pointer to a new tsproc on success, NULL otherwise.
  */
 struct tsproc *tsproc_create(enum tsproc_mode mode,
-                            enum filter_type delay_filter, int filter_length);
+                            enum filter_type delay_filter, int filter_length, 
double percentile);
 
 /**
  * Destroy a time stamp processor.
-- 
2.17.1



_______________________________________________
Linuxptp-devel mailing list
Linuxptp-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linuxptp-devel

Reply via email to