From 66ff33813a8cd9d4cba96280bb613762fb0c2ce2 Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Wed, 11 Nov 2020 21:29:54 -0800 Subject: fixes #1323 stats framework is *way* to heavy This should reduce the amount of copying, and the overall size used by pipes and other objects quite a bit. (On my system, the sizeof nni_pipe shrank by 400 bytes, for example.) --- src/core/stats.c | 363 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 211 insertions(+), 152 deletions(-) (limited to 'src/core/stats.c') diff --git a/src/core/stats.c b/src/core/stats.c index d6f98e3e..14cf7978 100644 --- a/src/core/stats.c +++ b/src/core/stats.c @@ -16,23 +16,24 @@ typedef struct nng_stat nni_stat; struct nng_stat { - char * s_name; - char * s_desc; - 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; + const nni_stat_info *s_info; + const nni_stat_item *s_item; // Used during snapshot collection + nni_list s_children; + nni_stat * s_parent; + nni_list_node s_node; + nni_time s_timestamp; + union { + int sv_id; + bool sv_bool; + uint64_t sv_value; + char * sv_string; + } s_val; }; #ifdef NNG_ENABLE_STATS static nni_stat_item stats_root; static nni_mtx stats_lock; -static nni_mtx * stats_held = NULL; +static nni_mtx stats_val_lock; #endif void @@ -68,135 +69,149 @@ nni_stat_register(nni_stat_item *child) #endif } +#ifdef NNG_ENABLE_STATS +void +stat_unregister(nni_stat_item *item) +{ + nni_stat_item *child; + while ((child = nni_list_first(&item->si_children)) != NULL) { + stat_unregister(child); + } + if ((item->si_info->si_alloc) && + (item->si_info->si_type == NNG_STAT_STRING)) { + nni_strfree(item->si_value.sv_string); + item->si_value.sv_string = NULL; + } + nni_list_node_remove(&item->si_node); +} +#endif + void -nni_stat_unregister(nni_stat_item *stat) +nni_stat_unregister(nni_stat_item *item) { #ifdef NNG_ENABLE_STATS nni_mtx_lock(&stats_lock); - nni_list_node_remove(&stat->si_node); + stat_unregister(item); nni_mtx_unlock(&stats_lock); #else - NNI_ARG_UNUSED(child); + NNI_ARG_UNUSED(item); #endif } -#ifdef NNG_ENABLE_STATS void -nni_stat_init(nni_stat_item *stat, const char *name, const char *desc) +nni_stat_init(nni_stat_item *item, const nni_stat_info *info) { - NNI_LIST_INIT(&stat->si_children, nni_stat_item, si_node); - stat->si_name = name; - stat->si_desc = desc; - stat->si_lock = NULL; - stat->si_update = NULL; - stat->si_string = NULL; - stat->si_number = 0; - stat->si_type = NNG_STAT_COUNTER; - stat->si_unit = NNG_UNIT_NONE; +#ifdef NNG_ENABLE_STATS + memset(item, 0, sizeof(*item)); + NNI_LIST_INIT(&item->si_children, nni_stat_item, si_node); + item->si_info = info; +#else + NNI_ARG_UNUSED(item); + NNI_ARG_UNUSED(info); +#endif } void -nni_stat_init_scope(nni_stat_item *stat, const char *name, const char *desc) +nni_stat_inc(nni_stat_item *item, uint64_t inc) { - nni_stat_init(stat, name, desc); - stat->si_type = NNG_STAT_SCOPE; - stat->si_unit = NNG_UNIT_NONE; +#ifdef NNG_ENABLE_STATS + if (item->si_info->si_atomic) { + nni_atomic_add64(&item->si_value.sv_atomic, inc); + } else { + item->si_value.sv_number += inc; + } +#else + NNI_ARG_UNUSED(item); + NNI_ARG_UNUSED(inc); +#endif } void -nni_stat_init_string( - nni_stat_item *stat, const char *name, const char *desc, const char *str) +nni_stat_dec(nni_stat_item *item, uint64_t inc) { - nni_stat_init(stat, name, desc); - stat->si_string = str; - stat->si_type = NNG_STAT_STRING; - stat->si_unit = NNG_UNIT_NONE; -} +#ifdef NNG_ENABLE_STATS -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_number = id; - stat->si_type = NNG_STAT_ID; - stat->si_unit = NNG_UNIT_NONE; + if (item->si_info->si_atomic) { + nni_atomic_sub64(&item->si_value.sv_atomic, inc); + } else { + item->si_value.sv_number -= inc; + } +#else + NNI_ARG_UNUSED(item); + NNI_ARG_UNUSED(inc); +#endif } void -nni_stat_init_bool( - nni_stat_item *stat, const char *name, const char *desc, bool v) +nni_stat_set_id(nni_stat_item *item, int id) { - nni_stat_init(stat, name, desc); - stat->si_number = v ? 1 : 0; - stat->si_type = NNG_STAT_BOOLEAN; - stat->si_unit = NNG_UNIT_NONE; -} - -static void -stat_atomic_update(nni_stat_item *stat) -{ - stat->si_number = nni_atomic_get64(&stat->si_atomic); +#ifdef NNG_ENABLE_STATS + // IDs don't change, so just set it. + item->si_value.sv_id = id; +#else + NNI_ARG_UNUSED(item); + NNI_ARG_UNUSED(id); +#endif } void -nni_stat_init_atomic(nni_stat_item *stat, const char *name, const char *desc) +nni_stat_set_bool(nni_stat_item *item, bool b) { - nni_stat_init(stat, name, desc); - stat->si_number = 0; - stat->si_update = stat_atomic_update; - nni_atomic_init64(&stat->si_atomic); +#ifdef NNG_ENABLE_STATS + // bool is atomic by definitions. + item->si_value.sv_bool = b; +#else + NNI_ARG_UNUSED(item); + NNI_ARG_UNUSED(id); +#endif } void -nni_stat_inc_atomic(nni_stat_item *stat, uint64_t inc) +nni_stat_set_string(nni_stat_item *item, const char *s) { - nni_atomic_add64(&stat->si_atomic, inc); -} +#ifdef NNG_ENABLE_STATS + const nni_stat_info *info = item->si_info; + char * old = item->si_value.sv_string; + + nni_mtx_lock(&stats_val_lock); + if ((s != NULL) && (old != NULL) && (strcmp(s, old) == 0)) { + // no change + nni_mtx_unlock(&stats_val_lock); + return; + } -void -nni_stat_dec_atomic(nni_stat_item *stat, uint64_t inc) -{ - nni_atomic_sub64(&stat->si_atomic, inc); -} -#endif + if (!info->si_alloc) { + // no allocation, just set it. + item->si_value.sv_string = (char *) s; + nni_mtx_unlock(&stats_val_lock); + return; + } -void -nni_stat_set_value(nni_stat_item *stat, uint64_t v) -{ -#ifdef NNG_ENABLE_STATS - stat->si_number = v; + item->si_value.sv_string = nni_strdup(s); + nni_mtx_unlock(&stats_val_lock); + + nni_strfree(old); #else - NNI_ARG_UNUSED(stat); - NNI_ARG_UNUSED(v); + NNG_ARG_UNUSED(item); + NNG_ARG_UNUSED(s); #endif } void -nni_stat_set_lock(nni_stat_item *stat, nni_mtx *mtx) +nni_stat_set_value(nni_stat_item *item, uint64_t v) { #ifdef NNG_ENABLE_STATS - stat->si_lock = mtx; + if (item->si_info->si_atomic) { + nni_atomic_set64(&item->si_value.sv_atomic, v); + } else { + item->si_value.sv_number = v; + } #else NNI_ARG_UNUSED(stat); - NNI_ARG_UNUSED(mtx); + NNI_ARG_UNUSED(v); #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) { @@ -207,9 +222,9 @@ nng_stats_free(nni_stat *st) nni_list_remove(&st->s_children, child); nng_stats_free(child); } - nni_strfree(st->s_name); - nni_strfree(st->s_desc); - nni_strfree(st->s_string); + if (st->s_info->si_alloc) { + nni_strfree(st->s_val.sv_string); + } NNI_FREE_STRUCT(st); #else NNI_ARG_UNUSED(st); @@ -228,19 +243,8 @@ stat_make_tree(nni_stat_item *item, nni_stat **sp) } NNI_LIST_INIT(&stat->s_children, nni_stat, s_node); - if (((stat->s_name = nni_strdup(item->si_name)) == NULL) || - ((stat->s_desc = nni_strdup(item->si_desc)) == NULL)) { - nng_stats_free(stat); - return (NNG_ENOMEM); - } - if ((item->si_type == NNG_STAT_STRING) && - ((stat->s_string = nni_strdup(item->si_string)) == NULL)) { - nng_stats_free(stat); - return (NNG_ENOMEM); - } + stat->s_info = item->si_info; stat->s_item = item; - stat->s_type = item->si_type; - stat->s_unit = item->si_unit; stat->s_parent = NULL; NNI_LIST_FOREACH (&item->si_children, child) { @@ -260,23 +264,52 @@ stat_make_tree(nni_stat_item *item, nni_stat **sp) static void stat_update(nni_stat *stat) { - nni_stat_item *item = stat->s_item; + const nni_stat_item *item = stat->s_item; + const nni_stat_info *info = item->si_info; + char * old; + char * str; - if (item->si_lock != stats_held) { - if (stats_held != NULL) { - nni_mtx_unlock(stats_held); - stats_held = NULL; + switch (info->si_type) { + case NNG_STAT_SCOPE: + case NNG_STAT_ID: + stat->s_val.sv_id = item->si_value.sv_id; + break; + case NNG_STAT_BOOLEAN: + stat->s_val.sv_bool = item->si_value.sv_bool; + break; + case NNG_STAT_COUNTER: + case NNG_STAT_LEVEL: + if (info->si_atomic) { + stat->s_val.sv_value = nni_atomic_get64( + (nni_atomic_u64 *) &item->si_value.sv_atomic); + } else { + stat->s_val.sv_value = item->si_value.sv_number; } - if (item->si_lock != NULL) { - nni_mtx_lock(item->si_lock); - stats_held = item->si_lock; + break; + case NNG_STAT_STRING: + nni_mtx_lock(&stats_val_lock); + old = stat->s_val.sv_string; + str = item->si_value.sv_string; + + // If we have to allocate a new string, do so. But + // only do it if new string is different. + if ((info->si_alloc) && (str != NULL) && + ((old == NULL) || (strcmp(str, old) != 0))) { + + stat->s_val.sv_string = nni_strdup(str); + nni_strfree(old); + + } else if (info->si_alloc) { + nni_strfree(stat->s_val.sv_string); + stat->s_val.sv_string = NULL; + + } else { + stat->s_val.sv_string = str; } + nni_mtx_unlock(&stats_val_lock); + break; } - if (item->si_update != NULL) { - item->si_update(item); - } - stat->s_value = item->si_number; - stat->s_time = nni_clock(); + stat->s_timestamp = nni_clock(); } static void @@ -304,10 +337,6 @@ nni_stat_snapshot(nni_stat **statp, nni_stat_item *item) 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); @@ -353,43 +382,53 @@ nng_stat_child(nng_stat *stat) const char * nng_stat_name(nni_stat *stat) { - return (stat->s_name); + return (stat->s_info->si_name); } uint64_t nng_stat_value(nni_stat *stat) { - return (stat->s_value); + return (stat->s_val.sv_value); +} + +bool +nng_stat_bool(nni_stat *stat) +{ + return (stat->s_val.sv_bool); } + const char * nng_stat_string(nng_stat *stat) { - return (stat->s_string); + if (stat->s_info->si_type != NNG_STAT_STRING) { + return (""); + } + return (stat->s_val.sv_string); } uint64_t nng_stat_timestamp(nng_stat *stat) { - return ((uint64_t) stat->s_time); + return ((uint64_t) stat->s_timestamp); } int nng_stat_type(nng_stat *stat) { - return (stat->s_type); + return (stat->s_info->si_type); } int nng_stat_unit(nng_stat *stat) { - return (stat->s_unit); + return (stat->s_info->si_unit); } const char * nng_stat_desc(nng_stat *stat) { - return (stat->s_desc); + return (stat->s_info->si_desc); } nng_stat * @@ -399,7 +438,28 @@ nng_stat_find(nng_stat *stat, const char *name) if (stat == NULL) { return (NULL); } - if (strcmp(name, stat->s_name) == 0) { + if (strcmp(name, stat->s_info->si_name) == 0) { + return (stat); + } + NNI_LIST_FOREACH (&stat->s_children, child) { + nng_stat *result; + if ((result = nng_stat_find(child, name)) != NULL) { + return (result); + } + } + return (NULL); +} + +nng_stat * +nng_stat_find_scope(nng_stat *stat, const char *name, int id) +{ + nng_stat *child; + if (stat == NULL) { + return (NULL); + } + if ((stat->s_val.sv_id == id) && + (stat->s_info->si_type == NNG_STAT_SCOPE) && + (strcmp(name, stat->s_info->si_name) == 0)) { return (stat); } NNI_LIST_FOREACH (&stat->s_children, child) { @@ -414,35 +474,33 @@ nng_stat_find(nng_stat *stat, const char *name) nng_stat * nng_stat_find_socket(nng_stat *stat, nng_socket s) { - char name[16]; - (void) snprintf(name, sizeof(name), "socket%d", nng_socket_id(s)); - return (nng_stat_find(stat, name)); + return (nng_stat_find_scope(stat, "socket", nng_socket_id(s))); } nng_stat * nng_stat_find_dialer(nng_stat *stat, nng_dialer d) { - char name[16]; - (void) snprintf(name, sizeof(name), "dialer%d", nng_dialer_id(d)); - return (nng_stat_find(stat, name)); + return (nng_stat_find_scope(stat, "dialer", nng_dialer_id(d))); } nng_stat * nng_stat_find_listener(nng_stat *stat, nng_listener l) { - char name[16]; - (void) snprintf(name, sizeof(name), "listener%d", nng_listener_id(l)); - return (nng_stat_find(stat, name)); + return (nng_stat_find_scope(stat, "listener", nng_listener_id(l))); } int nni_stat_sys_init(void) { #ifdef NNG_ENABLE_STATS + static const nni_stat_info root = { + .si_name = "", + .si_desc = "all statistics", + .si_type = NNG_STAT_SCOPE, + }; 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 statistics"; + nni_mtx_init(&stats_val_lock); + nni_stat_init(&stats_root, &root); #endif return (0); } @@ -452,6 +510,7 @@ nni_stat_sys_fini(void) { #ifdef NNG_ENABLE_STATS nni_mtx_fini(&stats_lock); + nni_mtx_fini(&stats_val_lock); #endif } @@ -462,8 +521,9 @@ 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); + if (strlen(stat->s_info->si_name) > 0) { + snprintf(*scope, *lenp, "%s#%d.", stat->s_info->si_name, + stat->s_val.sv_id); } else { (*scope)[0] = '\0'; } @@ -503,9 +563,8 @@ nng_stats_dump(nng_stat *stat) nng_stat_string(stat)); break; case NNG_STAT_BOOLEAN: - val = nng_stat_value(stat); nni_plat_printf("%s%-32s%s\n", indent, nng_stat_name(stat), - val != 0 ? "true" : "false"); + nng_stat_bool(stat) ? "true" : "false"); break; case NNG_STAT_LEVEL: case NNG_STAT_COUNTER: @@ -520,7 +579,7 @@ nng_stats_dump(nng_stat *stat) nni_plat_printf(" msgs\n"); break; case NNG_UNIT_MILLIS: - nni_plat_printf(" msec\n"); + nni_plat_printf(" ms\n"); break; case NNG_UNIT_NONE: case NNG_UNIT_EVENTS: -- cgit v1.2.3-70-g09d2