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