diff options
Diffstat (limited to 'src/core/stats.c')
| -rw-r--r-- | src/core/stats.c | 525 |
1 files changed, 525 insertions, 0 deletions
diff --git a/src/core/stats.c b/src/core/stats.c new file mode 100644 index 00000000..0363a932 --- /dev/null +++ b/src/core/stats.c @@ -0,0 +1,525 @@ +// +// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech> +// Copyright 2018 Capitar IT Group BV <info@capitar.com> +// +// This software is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +#include <stdio.h> +#include <string.h> + +#include "core/nng_impl.h" + +typedef struct nng_stat nni_stat; + +struct nng_stat { + char * s_name; + const char * s_desc; + const char * s_string; + uint64_t s_value; + nni_time s_time; + nni_stat_type s_type; + nni_stat_unit s_unit; + nni_stat_item *s_item; // Used during snapshot collection + nni_list s_children; + nni_stat * s_parent; + nni_list_node s_node; +}; + +#ifdef NNG_ENABLE_STATS +static nni_stat_item stats_root; +static nni_mtx stats_lock; +static nni_mtx * stats_held = NULL; +#endif + +void +nni_stat_append(nni_stat_item *parent, nni_stat_item *child) +{ +#ifdef NNG_ENABLE_STATS + if (parent == NULL) { + parent = &stats_root; + } + nni_mtx_lock(&stats_lock); + // Make sure that the lists for both children and parents + // are correctly initialized. + if (parent->si_children.ll_head.ln_next == NULL) { + NNI_LIST_INIT(&parent->si_children, nni_stat_item, si_node); + } + if (child->si_children.ll_head.ln_next == NULL) { + NNI_LIST_INIT(&child->si_children, nni_stat_item, si_node); + } + nni_list_append(&parent->si_children, child); + child->si_parent = parent; + nni_mtx_unlock(&stats_lock); +#else + NNI_ARG_UNUSED(parent); + NNI_ARG_UNUSED(child); +#endif +} + +void +nni_stat_remove(nni_stat_item *child) +{ +#ifdef NNG_ENABLE_STATS + nni_stat_item *parent; + nni_mtx_lock(&stats_lock); + if ((parent = child->si_parent) != NULL) { + nni_list_remove(&parent->si_children, child); + child->si_parent = NULL; + } + nni_mtx_unlock(&stats_lock); +#else + NNI_ARG_UNUSED(child); +#endif +} + +#ifdef NNG_ENABLE_STATS +void +nni_stat_init(nni_stat_item *stat, const char *name, const char *desc) +{ + NNI_LIST_INIT(&stat->si_children, nni_stat_item, si_node); + stat->si_parent = NULL; + stat->si_name = name; + stat->si_desc = desc; + stat->si_lock = NULL; + stat->si_update = NULL; + stat->si_private = NULL; + stat->si_string = NULL; + stat->si_value = 0; + stat->si_type = NNG_STAT_COUNTER; + stat->si_unit = NNG_UNIT_NONE; +} + +void +nni_stat_init_scope(nni_stat_item *stat, const char *name, const char *desc) +{ + nni_stat_init(stat, name, desc); + stat->si_type = NNG_STAT_SCOPE; + stat->si_unit = NNG_UNIT_NONE; +} + +void +nni_stat_init_string( + nni_stat_item *stat, const char *name, const char *desc, const char *str) +{ + nni_stat_init(stat, name, desc); + stat->si_string = str; + stat->si_type = NNG_STAT_STRING; + stat->si_unit = NNG_UNIT_NONE; +} + +void +nni_stat_init_id( + nni_stat_item *stat, const char *name, const char *desc, uint64_t id) +{ + nni_stat_init(stat, name, desc); + stat->si_value = id; + stat->si_type = NNG_STAT_ID; + stat->si_unit = NNG_UNIT_NONE; +} + +void +nni_stat_init_bool( + nni_stat_item *stat, const char *name, const char *desc, bool v) +{ + nni_stat_init(stat, name, desc); + stat->si_value = v ? 1 : 0; + stat->si_type = NNG_STAT_BOOLEAN; + stat->si_unit = NNG_UNIT_NONE; +} + +static void +stat_atomic_update(nni_stat_item *stat, void *notused) +{ + NNI_ARG_UNUSED(notused); + stat->si_value = nni_atomic_get64(&stat->si_atomic); +} + +void +nni_stat_init_atomic(nni_stat_item *stat, const char *name, const char *desc) +{ + + nni_stat_init(stat, name, desc); + stat->si_value = 0; + stat->si_private = NULL; + stat->si_update = stat_atomic_update; + nni_atomic_init64(&stat->si_atomic); +} + +void +nni_stat_inc_atomic(nni_stat_item *stat, uint64_t inc) +{ + nni_atomic_inc64(&stat->si_atomic, inc); +} + +void +nni_stat_dec_atomic(nni_stat_item *stat, uint64_t inc) +{ + nni_atomic_dec64(&stat->si_atomic, inc); +} +#endif + +void +nni_stat_set_value(nni_stat_item *stat, uint64_t v) +{ +#ifdef NNG_ENABLE_STATS + stat->si_value = v; +#else + NNI_ARG_UNUSED(stat); + NNI_ARG_UNUSED(v); +#endif +} + +void +nni_stat_set_string(nni_stat_item *stat, const char *str) +{ +#ifdef NNG_ENABLE_STATS + stat->si_string = str; +#else + NNI_ARG_UNUSED(stat); + NNI_ARG_UNUSED(str); +#endif +} + +void +nni_stat_set_lock(nni_stat_item *stat, nni_mtx *mtx) +{ +#ifdef NNG_ENABLE_STATS + stat->si_lock = mtx; +#else + NNI_ARG_UNUSED(stat); + NNI_ARG_UNUSED(mtx); +#endif +} + +void +nni_stat_set_update(nni_stat_item *stat, nni_stat_update f, void *a) +{ +#ifdef NNG_ENABLE_STATS + stat->si_update = f; + stat->si_private = a; +#else + NNI_ARG_UNUSED(stat); + NNI_ARG_UNUSED(f); + NNI_ARG_UNUSED(a); +#endif +} + +#ifdef NNG_ENABLE_STATS +void +nni_stat_set_type(nni_stat_item *stat, int type) +{ + stat->si_type = type; +} + +void +nni_stat_set_unit(nni_stat_item *stat, int unit) +{ + stat->si_unit = unit; +} +#endif + +void +nng_stats_free(nni_stat *st) +{ +#ifdef NNG_ENABLE_STATS + nni_stat *child; + + while ((child = nni_list_first(&st->s_children)) != NULL) { + nni_list_remove(&st->s_children, child); + nng_stats_free(child); + } + nni_strfree(st->s_name); + NNI_FREE_STRUCT(st); +#else + NNI_ARG_UNUSED(st); +#endif +} + +#ifdef NNG_ENABLE_STATS +static int +stat_make_tree(nni_stat_item *item, nni_stat **sp) +{ + nni_stat * stat; + nni_stat_item *child; + + if ((stat = NNI_ALLOC_STRUCT(stat)) == NULL) { + return (NNG_ENOMEM); + } + if ((stat->s_name = nni_strdup(item->si_name)) == NULL) { + NNI_FREE_STRUCT(stat); + return (NNG_ENOMEM); + } + NNI_LIST_INIT(&stat->s_children, nni_stat, s_node); + stat->s_item = item; + stat->s_type = item->si_type; + stat->s_unit = item->si_unit; + stat->s_desc = item->si_desc; + stat->s_parent = NULL; + + NNI_LIST_FOREACH (&item->si_children, child) { + nni_stat *cs; + int rv; + if ((rv = stat_make_tree(child, &cs)) != 0) { + nng_stats_free(stat); + return (rv); + } + nni_list_append(&stat->s_children, cs); + cs->s_parent = stat; + } + *sp = stat; + return (0); +} + +static void +stat_update(nni_stat *stat) +{ + nni_stat_item *item = stat->s_item; + + if (item->si_lock != stats_held) { + if (stats_held != NULL) { + nni_mtx_unlock(stats_held); + stats_held = NULL; + } + if (item->si_lock != NULL) { + nni_mtx_lock(item->si_lock); + stats_held = item->si_lock; + } + } + if (item->si_update != NULL) { + item->si_update(item, item->si_private); + } + stat->s_value = item->si_value; + stat->s_string = item->si_string; + stat->s_time = nni_clock(); +} + +static void +stat_update_tree(nni_stat *stat) +{ + nni_stat *child; + stat_update(stat); + NNI_LIST_FOREACH (&stat->s_children, child) { + stat_update_tree(child); + } +} + +int +nni_stat_snapshot(nni_stat **statp, nni_stat_item *item) +{ + int rv; + nni_stat *stat; + + if (item == NULL) { + item = &stats_root; + } + nni_mtx_lock(&stats_lock); + if ((rv = stat_make_tree(item, &stat)) != 0) { + nni_mtx_unlock(&stats_lock); + return (rv); + } + stat_update_tree(stat); + if (stats_held != NULL) { + nni_mtx_unlock(stats_held); + stats_held = NULL; + } + nni_mtx_unlock(&stats_lock); + *statp = stat; + return (0); +} +#endif + +int +nng_stats_get(nng_stat **statp) +{ +#ifdef NNG_ENABLE_STATS + return (nni_stat_snapshot(statp, &stats_root)); +#else + NNI_ARG_UNUSED(statp); + return (NNG_ENOTSUP); +#endif +} + +nng_stat * +nng_stat_parent(nng_stat *stat) +{ + return (stat->s_parent); +} + +nng_stat * +nng_stat_next(nng_stat *stat) +{ + if (stat->s_parent == NULL) { + return (NULL); // Root node, no siblings. + } + return (nni_list_next(&stat->s_parent->s_children, stat)); +} + +nng_stat * +nng_stat_child(nng_stat *stat) +{ + return (nni_list_first(&stat->s_children)); +} + +const char * +nng_stat_name(nni_stat *stat) +{ + return (stat->s_name); +} + +uint64_t +nng_stat_value(nni_stat *stat) +{ + return (stat->s_value); +} + +const char * +nng_stat_string(nng_stat *stat) +{ + return (stat->s_string); +} + +uint64_t +nng_stat_timestamp(nng_stat *stat) +{ + return ((uint64_t) stat->s_time); +} + +int +nng_stat_type(nng_stat *stat) +{ + return (stat->s_type); +} + +int +nng_stat_unit(nng_stat *stat) +{ + return (stat->s_unit); +} + +const char * +nng_stat_desc(nng_stat *stat) +{ + return (stat->s_desc); +} + +int +nni_stat_sys_init(void) +{ +#ifdef NNG_ENABLE_STATS + nni_mtx_init(&stats_lock); + NNI_LIST_INIT(&stats_root.si_children, nni_stat_item, si_node); + stats_root.si_name = ""; + stats_root.si_desc = "all statistsics"; +#endif + + return (0); +} + +void +nni_stat_sys_fini(void) +{ +#ifdef NNG_ENABLE_STATS + nni_mtx_fini(&stats_lock); +#endif +} + +#ifdef NNG_ENABLE_STATS +void +stat_sprint_scope(nni_stat *stat, char **scope, int *lenp) +{ + if (stat->s_parent != NULL) { + stat_sprint_scope(stat->s_parent, scope, lenp); + } + if (strlen(stat->s_name) > 0) { + snprintf(*scope, *lenp, "%s.", stat->s_name); + } else { + (*scope)[0] = '\0'; + } + *lenp -= strlen(*scope); + *scope += strlen(*scope); +} +#endif + +void +nng_stats_dump(nng_stat *stat) +{ +#ifdef NNG_ENABLE_STATS + static char buf[128]; // to minimize recursion, not thread safe + static char line[128]; + int len; + char * scope; + char * indent = " "; + unsigned long long val; + nni_stat * child; + + switch (nng_stat_type(stat)) { + case NNG_STAT_SCOPE: + scope = buf; + len = sizeof(buf); + stat_sprint_scope(stat, &scope, &len); + len = strlen(buf); + if (len > 0) { + if (buf[len - 1] == '.') { + buf[--len] = '\0'; + } + } + if (len > 0) { + snprintf(line, sizeof(line), "\n%s:", buf); + } + break; + case NNG_STAT_STRING: + snprintf(line, sizeof(line), "%s%-32s\"%s\"", indent, + nng_stat_name(stat), nng_stat_string(stat)); + break; + case NNG_STAT_BOOLEAN: + val = nng_stat_value(stat); + snprintf(line, sizeof(line), "%s%-32s%s", indent, + nng_stat_name(stat), val != 0 ? "true" : "false"); + break; + case NNG_STAT_LEVEL: + case NNG_STAT_COUNTER: + val = nng_stat_value(stat); + switch (nng_stat_unit(stat)) { + case NNG_UNIT_BYTES: + snprintf(line, sizeof(line), "%s%-32s%llu bytes", + indent, nng_stat_name(stat), val); + break; + case NNG_UNIT_MESSAGES: + snprintf(line, sizeof(line), "%s%-32s%llu msgs", + indent, nng_stat_name(stat), val); + break; + case NNG_UNIT_MILLIS: + snprintf(line, sizeof(line), "%s%-32s%llu msec", + indent, nng_stat_name(stat), val); + break; + case NNG_UNIT_NONE: + case NNG_UNIT_EVENTS: + default: + snprintf(line, sizeof(line), "%s%-32s%llu", indent, + nng_stat_name(stat), val); + break; + } + break; + case NNG_STAT_ID: + val = nng_stat_value(stat); + snprintf(line, (sizeof line), "%s%-32s%llu", indent, + nng_stat_name(stat), val); + break; + default: + snprintf(line, (sizeof line), "%s%-32s<?>", indent, + nng_stat_name(stat)); + break; + } + nni_plat_println(line); + + NNI_LIST_FOREACH (&stat->s_children, child) { + nng_stats_dump(child); + } +#else + NNI_ARG_UNUSED(stat); +#endif +} |
