This patch adds pm.c which includes handling of pm data. Each 15
minute, the data is stored in 15 minute and 24 hour recordlists.
24 hour recordlist stores the last complete 24 hour cycle and the
ongoing.
15 minute recordlist stores the last 96 complete 15 minute cycles.

Signed-off-by: Anders Selhammer <anders.selham...@est.tech>
---
 makefile |   2 +-
 pm.c     | 414 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 pm.h     | 100 +++++++++++++--
 3 files changed, 506 insertions(+), 10 deletions(-)
 create mode 100644 pm.c

diff --git a/makefile b/makefile
index 796235b..001bf01 100644
--- a/makefile
+++ b/makefile
@@ -25,7 +25,7 @@ LDLIBS        = -lm -lrt $(EXTRA_LDFLAGS)
 PRG    = ptp4l hwstamp_ctl nsm phc2sys phc_ctl pmc timemaster
 OBJ     = bmc.o clock.o clockadj.o clockcheck.o config.o fault.o \
  filter.o fsm.o hash.o linreg.o mave.o mmedian.o msg.o ntpshm.o nullf.o phc.o \
- pi.o port.o print.o ptp4l.o raw.o rtnl.o servo.o sk.o stats.o tlv.o \
+ pi.o pm.o port.o print.o ptp4l.o raw.o rtnl.o servo.o sk.o stats.o tlv.o \
  transport.o tsproc.o udp.o udp6.o uds.o util.o version.o
 
 OBJECTS        = $(OBJ) hwstamp_ctl.o nsm.o phc2sys.o phc_ctl.o pmc.o 
pmc_common.o \
diff --git a/pm.c b/pm.c
new file mode 100644
index 0000000..8521c88
--- /dev/null
+++ b/pm.c
@@ -0,0 +1,414 @@
+/**
+ * @file pm.c
+ * @note Copyright (C) 2018 Anders Selhammer <anders.selham...@est.tech>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include <stdlib.h>
+#include <time.h>
+
+#include "pm.h"
+#include "print.h"
+
+
+#define CYCLE_24HOUR 96
+#define MIN_24HOUR_INDEX 97
+#define MAX_24HOUR_INDEX 98
+
+int pm_create_clock_stats(struct pm_clock_stats *cr)
+{
+       cr->measurementValid = 1;
+       cr->periodComplete = 0;
+       cr->masterSlaveDelay = stats_create();
+       cr->slaveMasterDelay = stats_create();
+       cr->meanPathDelay    = stats_create();
+       cr->offsetFromMaster = stats_create();
+       if (!cr->masterSlaveDelay || !cr->meanPathDelay ||
+           !cr->slaveMasterDelay || !cr->offsetFromMaster) {
+               return -1;
+       }
+       return 0;
+}
+
+int pm_create_port_stats(struct pm_port_stats *cr)
+{
+       cr->meanLinkDelay = stats_create();
+       if (!cr->meanLinkDelay) {
+               return -1;
+       }
+       return 0;
+}
+
+void pm_reset_clock_stats(struct pm_clock_stats *cr)
+{
+       cr->measurementValid = 1;
+       cr->periodComplete = 0;
+       stats_reset(cr->masterSlaveDelay);
+       stats_reset(cr->slaveMasterDelay);
+       stats_reset(cr->meanPathDelay);
+       stats_reset(cr->offsetFromMaster);
+}
+
+void pm_reset_port_stats(struct pm_port_stats *cr)
+{
+       stats_reset(cr->meanLinkDelay);
+}
+
+void pm_destroy_clock_stats(struct pm_clock_stats *cr)
+{
+       stats_destroy(cr->masterSlaveDelay);
+       stats_destroy(cr->slaveMasterDelay);
+       stats_destroy(cr->meanPathDelay);
+       stats_destroy(cr->offsetFromMaster);
+}
+
+void pm_destroy_port_stats(struct pm_port_stats *cr)
+{
+       stats_destroy(cr->meanLinkDelay);
+}
+void pm_free_clock_recordlist(struct pm_clock_recordlist *rl)
+{
+       struct pm_clock_stats *tmp_s;
+
+       while ((tmp_s = TAILQ_FIRST(&rl->record15_stats)) != NULL) {
+               TAILQ_REMOVE(&rl->record15_stats, tmp_s, list);
+               pm_destroy_clock_stats(tmp_s);
+               free(tmp_s);
+       }
+       while ((tmp_s = TAILQ_FIRST(&rl->record24_stats)) != NULL) {
+               TAILQ_REMOVE(&rl->record24_stats, tmp_s, list);
+               pm_destroy_clock_stats(tmp_s);
+               free(tmp_s);
+       }
+}
+void pm_free_port_recordlist(struct pm_port_recordlist *rl)
+{
+       struct pm_port_stats *tmp_s;
+       struct pm_port_counters *tmp_c;
+
+       while ((tmp_s = TAILQ_FIRST(&rl->record15_stats)) != NULL) {
+               TAILQ_REMOVE(&rl->record15_stats, tmp_s, list);
+               pm_destroy_port_stats(tmp_s);
+               free(tmp_s);
+       }
+       while ((tmp_s = TAILQ_FIRST(&rl->record24_stats)) != NULL) {
+               TAILQ_REMOVE(&rl->record24_stats, tmp_s, list);
+               pm_destroy_port_stats(tmp_s);
+               free(tmp_s);
+       }
+       while ((tmp_c = TAILQ_FIRST(&rl->record15_cnt)) != NULL) {
+               TAILQ_REMOVE(&rl->record15_cnt, tmp_c, list);
+               free(tmp_c);
+       }
+       while ((tmp_c = TAILQ_FIRST(&rl->record24_cnt)) != NULL) {
+               TAILQ_REMOVE(&rl->record24_cnt, tmp_c, list);
+               free(tmp_c);
+       }
+}
+
+static struct pm_clock_stats * calloc_new_clock_stats_record()
+{
+       struct pm_clock_stats *cr = calloc(1, sizeof(*cr));
+
+       if (!cr) {
+               pr_err("low memory, failed to create new clock stats record");
+               return NULL;
+       }
+
+       return cr;
+}
+
+static struct pm_port_stats * calloc_new_port_stats_record()
+{
+       struct pm_port_stats *cr = calloc(1, sizeof(*cr));
+
+       if (!cr) {
+               pr_err("low memory, failed to create new port stats record");
+               return NULL;
+       }
+
+       return cr;
+}
+
+static struct pm_port_counters * calloc_new_port_counter_record()
+{
+       struct pm_port_counters *cr = calloc(1, sizeof(*cr));
+
+       if (!cr) {
+               pr_err("low memory, failed to create new counter record");
+               return NULL;
+       }
+
+       return cr;
+}
+
+static struct pm_clock_stats * add_new_24_clock_stats_record(struct 
pm_clock_recordlist *rl)
+{
+       struct pm_clock_stats *cr = calloc_new_clock_stats_record();
+       if (!cr) {
+               return NULL;
+       }
+       if (pm_create_clock_stats(cr)) {
+               pm_destroy_clock_stats(cr);
+               return NULL;
+       }
+
+       cr->head.index = MIN_24HOUR_INDEX;
+       TAILQ_INSERT_HEAD(&rl->record24_stats, cr, list);
+
+       return cr;
+}
+
+static struct pm_port_stats * add_new_24_port_stats_record(struct 
pm_port_recordlist *rl)
+{
+       struct pm_port_stats *cr = calloc_new_port_stats_record();
+       if (!cr) {
+               return NULL;
+       }
+       if (pm_create_port_stats(cr)) {
+               pm_destroy_port_stats(cr);
+               return NULL;
+       }
+
+       cr->head.index = MIN_24HOUR_INDEX;
+       TAILQ_INSERT_HEAD(&rl->record24_stats, cr, list);
+
+       return cr;
+}
+
+static struct pm_port_counters * add_new_24_port_counter_record(struct 
pm_port_recordlist *rl)
+{
+       struct pm_port_counters *cr = calloc_new_port_counter_record();
+
+       if (!cr) {
+               return NULL;
+       }
+
+       cr->head.index = MIN_24HOUR_INDEX;
+       TAILQ_INSERT_HEAD(&rl->record24_cnt, cr, list);
+
+       return cr;
+}
+
+static struct pm_clock_stats * get_current_24_clock_stats_record(struct 
pm_clock_recordlist *rl)
+{
+       struct pm_clock_stats *cr = TAILQ_FIRST(&rl->record24_stats);
+
+       return (cr) ? cr : add_new_24_clock_stats_record(rl);
+}
+
+static struct pm_port_stats * get_current_24_port_stats_record(struct 
pm_port_recordlist *rl)
+{
+       struct pm_port_stats *cr = TAILQ_FIRST(&rl->record24_stats);
+
+       return (cr) ? cr : add_new_24_port_stats_record(rl);
+}
+
+static struct pm_port_counters * get_current_24_port_counter_record(struct 
pm_port_recordlist *rl)
+{
+       struct pm_port_counters *cr = TAILQ_FIRST(&rl->record24_cnt);
+
+       return (cr) ? cr : add_new_24_port_counter_record(rl);
+}
+
+static void set_pm_head(struct pm_head *cr,
+                       struct pm_head *cr15,
+                       struct pm_head *cr24)
+{
+       cr15->index  = cr->index;
+       cr15->PMTime = cr->PMTime;
+       if (tmv_is_zero(cr24->PMTime)) {
+               cr24->PMTime = cr->PMTime;
+       }
+}
+
+static void extract_clock_stats(struct pm_clock_stats *cr,
+                               struct pm_clock_stats *cr15,
+                               struct pm_clock_stats *cr24)
+{
+       set_pm_head(&cr->head, &cr15->head, &cr24->head);
+       cr15->measurementValid &= cr->measurementValid;
+       cr24->measurementValid &= cr->measurementValid;
+       stats_copy(cr15->masterSlaveDelay, cr->masterSlaveDelay);
+       stats_combine(cr24->masterSlaveDelay, cr->masterSlaveDelay);
+       stats_copy(cr15->slaveMasterDelay, cr->slaveMasterDelay);
+       stats_combine(cr24->slaveMasterDelay, cr->slaveMasterDelay);
+       stats_copy(cr15->meanPathDelay, cr->meanPathDelay);
+       stats_combine(cr24->meanPathDelay, cr->meanPathDelay);
+       stats_copy(cr15->offsetFromMaster, cr->offsetFromMaster);
+       stats_combine(cr24->offsetFromMaster, cr->offsetFromMaster);
+}
+
+static void extract_port_stats(struct pm_port_stats *cr,
+                              struct pm_port_stats *cr15,
+                              struct pm_port_stats *cr24)
+{
+       set_pm_head(&cr->head, &cr15->head, &cr24->head);
+       stats_copy(cr15->meanLinkDelay, cr->meanLinkDelay);
+       stats_combine(cr24->meanLinkDelay, cr->meanLinkDelay);
+}
+
+static void extract_port_counter_data(struct pm_port_counters *cr,
+                                     struct pm_port_counters *cr15,
+                                     struct pm_port_counters *cr24)
+{
+       int i;
+
+       set_pm_head(&cr->head, &cr15->head, &cr24->head);
+       for (i = 0 ; i < N_MSG_COUNTERS ; i++) {
+               cr15->counter[i] = cr->counter[i] - cr24->counter[i];
+               cr24->counter[i] = cr->counter[i];
+       }
+}
+
+int pm_update_clock_stats_recordlist(struct pm_clock_stats *cr,
+                                    struct pm_clock_recordlist *rl)
+{
+       struct pm_clock_stats *cr15, *cr24, *tmp_s;
+
+       cr24 = get_current_24_clock_stats_record(rl);
+       if (!cr24) {
+               return -1;
+       }
+       cr15 = calloc_new_clock_stats_record();
+       if (!cr15) {
+               return -1;
+       }
+       if (pm_create_clock_stats(cr15)) {
+               pm_destroy_clock_stats(cr15);
+               return -1;
+       }
+
+       extract_clock_stats(cr, cr15, cr24);
+       cr15->periodComplete = 1;
+
+       TAILQ_INSERT_HEAD(&rl->record15_stats, cr15, list);
+       TAILQ_FOREACH(tmp_s, &rl->record15_stats, list) {
+               if (++tmp_s->head.index > CYCLE_24HOUR) {
+                       TAILQ_REMOVE(&rl->record15_stats, tmp_s, list);
+                       pm_destroy_clock_stats(tmp_s);
+                       break;
+               }
+       }
+
+       if (++cr->cycle_index % CYCLE_24HOUR == 0) {
+               cr24->periodComplete = 1;
+               TAILQ_FOREACH(tmp_s, &rl->record24_stats, list) {
+                       if (++tmp_s->head.index > MAX_24HOUR_INDEX) {
+                               TAILQ_REMOVE(&rl->record24_stats, tmp_s, list);
+                               pm_destroy_clock_stats(tmp_s);
+                               break;
+                       }
+               }
+               if (!add_new_24_clock_stats_record(rl)) {
+                       return -1;
+               }
+       }
+
+       pm_reset_clock_stats(cr);
+
+       return 0;
+}
+
+int pm_update_port_stats_recordlist(struct pm_port_stats *cr,
+                                   struct pm_port_recordlist *rl,
+                                   int ci)
+{
+       struct pm_port_stats *cr15, *cr24, *tmp_s;
+
+       cr24 = get_current_24_port_stats_record(rl);
+       if (!cr24) {
+               return -1;
+       }
+       cr15 = calloc_new_port_stats_record();
+       if (!cr15) {
+               return -1;
+       }
+       if (pm_create_port_stats(cr15)) {
+               pm_destroy_port_stats(cr15);
+               return -1;
+       }
+
+       extract_port_stats(cr, cr15, cr24);
+
+       TAILQ_INSERT_HEAD(&rl->record15_stats, cr15, list);
+       TAILQ_FOREACH(tmp_s, &rl->record15_stats, list) {
+               if (++tmp_s->head.index > CYCLE_24HOUR) {
+                       TAILQ_REMOVE(&rl->record15_stats, tmp_s, list);
+                       pm_destroy_port_stats(tmp_s);
+                       break;
+               }
+       }
+
+       if (ci % CYCLE_24HOUR == 0) {
+               TAILQ_FOREACH(tmp_s, &rl->record24_stats, list) {
+                       if (++tmp_s->head.index > MAX_24HOUR_INDEX) {
+                               TAILQ_REMOVE(&rl->record24_stats, tmp_s, list);
+                               pm_destroy_port_stats(tmp_s);
+                               break;
+                       }
+               }
+               if (!add_new_24_port_stats_record(rl)) {
+                       return -1;
+               }
+       }
+
+       pm_reset_port_stats(cr);
+       return 0;
+}
+
+int pm_update_port_counters_recordlist(struct pm_port_counters *cr,
+                                      struct pm_port_recordlist *rl,
+                                      int ci)
+{
+       struct pm_port_counters *cr15, *cr24, *tmp_c;
+
+       cr24 = get_current_24_port_counter_record(rl);
+       if (!cr24) {
+               return -1;
+       }
+
+       cr15 = calloc_new_port_counter_record();
+       if (!cr15) {
+               return -1;
+       }
+
+       extract_port_counter_data(cr, cr15, cr24);
+
+       TAILQ_INSERT_HEAD(&rl->record15_cnt, cr15, list);
+       TAILQ_FOREACH(tmp_c, &rl->record15_cnt, list) {
+               if (++tmp_c->head.index > CYCLE_24HOUR) {
+                       TAILQ_REMOVE(&rl->record15_cnt, tmp_c, list);
+                       free(tmp_c);
+                       break;
+               }
+       }
+
+       if (ci % CYCLE_24HOUR == 0) {
+               memset(cr, 0, sizeof(*cr));
+               TAILQ_FOREACH(tmp_c, &rl->record24_cnt, list) {
+                       if (++tmp_c->head.index > MAX_24HOUR_INDEX) {
+                               TAILQ_REMOVE(&rl->record24_cnt, tmp_c, list);
+                               free(tmp_c);
+                               break;
+                       }
+               }
+               if (!add_new_24_port_counter_record(rl)) {
+                       return -1;
+               }
+       }
+
+       return 0;
+}
diff --git a/pm.h b/pm.h
index 15263ad..2019c22 100644
--- a/pm.h
+++ b/pm.h
@@ -60,7 +60,8 @@ struct pm_head {
 
 /* E2E and P2P */
 struct pm_clock_stats {
-       TAILQ_ENTRY(clock_pm_stats) list;
+       TAILQ_ENTRY(pm_clock_stats) list;
+       int                 cycle_index;
        struct pm_head      head;
        UInteger8           measurementValid;
        UInteger8           periodComplete;
@@ -72,28 +73,109 @@ struct pm_clock_stats {
 
 /* P2P only */
 struct pm_port_stats {
-       TAILQ_ENTRY(port_pm_stats) list;
+       TAILQ_ENTRY(pm_port_stats) list;
        struct pm_head      head;
        struct stats        *meanLinkDelay;
 };
 
 /* E2E and P2P */
 struct pm_port_counters {
-       TAILQ_ENTRY(port_pm_counters) list;
+       TAILQ_ENTRY(pm_port_counters) list;
        struct pm_head      head;
        UInteger32          counter[N_MSG_COUNTERS];
 };
 
 struct pm_clock_recordlist {
-       TAILQ_HEAD(clock_pm_15_stats_head, clock_pm_stats) record15_stats;
-       TAILQ_HEAD(clock_pm_24_stats_head, clock_pm_stats) record24_stats;
+       TAILQ_HEAD(pm_clock_15_stats_head, pm_clock_stats) record15_stats;
+       TAILQ_HEAD(pm_clock_24_stats_head, pm_clock_stats) record24_stats;
 };
 
 struct pm_port_recordlist {
-       TAILQ_HEAD(port_pm_15_stats_head, port_pm_stats) record15_stats;
-       TAILQ_HEAD(port_pm_24_stats_head, port_pm_stats) record24_stats;
-       TAILQ_HEAD(port_pm_15_counters_head, port_pm_counters) record15_cnt;
-       TAILQ_HEAD(port_pm_24_counters_head, port_pm_counters) record24_cnt;
+       TAILQ_HEAD(pm_port_15_stats_head, pm_port_stats) record15_stats;
+       TAILQ_HEAD(pm_port_24_stats_head, pm_port_stats) record24_stats;
+       TAILQ_HEAD(pm_port_15_counters_head, pm_port_counters) record15_cnt;
+       TAILQ_HEAD(pm_port_24_counters_head, pm_port_counters) record24_cnt;
 };
 
+/**
+ * Creates stats instances for clock statistics.
+ * @param cr Handle to current record.
+ * @return   Zero on success, non-zero if the message is invalid.
+ */
+int pm_create_clock_stats(struct pm_clock_stats *cr);
+
+/**
+ * Creates stats instances for port statistics.
+ * @param cr Handle to current record.
+ * @return   Zero on success, non-zero if the message is invalid.
+ */
+int pm_create_port_stats(struct pm_port_stats *cr);
+
+/**
+ * Reset the stats instances for clock statistics.
+ * @param cr Handle to current record.
+ */
+void pm_reset_clock_stats(struct pm_clock_stats *cr);
+
+/**
+ * Reset the stats instances for port statistics.
+ * @param cr Handle to current record.
+ */
+void pm_reset_port_stats(struct pm_port_stats *cr);
+
+/**
+ * Destroys stats instances for clock statistics.
+ * @param cr Handle to current record.
+ */
+void pm_destroy_clock_stats(struct pm_clock_stats *cr);
+
+/**
+ * Destroys stats instances for port statistics.
+ * @param cr Handle to current record.
+ */
+void pm_destroy_port_stats(struct pm_port_stats *cr);
+
+/**
+ * Clear the record list and frees all the memory.
+ * @param rl Handle to clock recordlist.
+ */
+void pm_free_clock_recordlist(struct pm_clock_recordlist *rl);
+
+/**
+ * Clear the record list and frees all the memory.
+ * @param rl Handle to port recordlist.
+ */
+void pm_free_port_recordlist(struct pm_port_recordlist *rl);
+
+/**
+ * Update clock stats 15 minutes and 24 hour recordlist.
+ * @param cr Handle to current record to store.
+ * @param rl Handle to recordlist.
+ * @return   Zero on success, non-zero if the message is invalid.
+ */
+int pm_update_clock_stats_recordlist(struct pm_clock_stats *cr,
+                                    struct pm_clock_recordlist *rl);
+
+/**
+ * Update port stats 15 minutes and 24 hour recordlist.
+ * @param cr Handle to current record to store.
+ * @param rl Handle to recordlist.
+ * @param ci Cycle index for pm collection.
+ * @return   Zero on success, non-zero if the message is invalid.
+ */
+int pm_update_port_stats_recordlist(struct pm_port_stats *cr,
+                                   struct pm_port_recordlist *rl,
+                                   int ci);
+
+/**
+ * Update port counters 15 minutes and 24 hour recordlist.
+ * @param cr Handle to current record to store.
+ * @param rl Handle to recordlist.
+ * @param ci Cycle index for pm collection.
+ * @return   Zero on success, non-zero if the message is invalid.
+ */
+int pm_update_port_counters_recordlist(struct pm_port_counters *cr,
+                                      struct pm_port_recordlist *rl,
+                                      int ci);
+
 #endif
-- 
1.8.3.1


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Linuxptp-devel mailing list
Linuxptp-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linuxptp-devel

Reply via email to