From 97e01009d69b8fbebfebf68f51e3d126d0ed43fc Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 30 Nov 2022 19:47:05 +0100 Subject: Merging upstream version 1.37.0. Signed-off-by: Daniel Baumann --- libnetdata/worker_utilization/worker_utilization.c | 218 ++++++++++++++++----- libnetdata/worker_utilization/worker_utilization.h | 39 +++- 2 files changed, 201 insertions(+), 56 deletions(-) (limited to 'libnetdata/worker_utilization') diff --git a/libnetdata/worker_utilization/worker_utilization.c b/libnetdata/worker_utilization/worker_utilization.c index bd3ad60e0..14b8926e0 100644 --- a/libnetdata/worker_utilization/worker_utilization.c +++ b/libnetdata/worker_utilization/worker_utilization.c @@ -4,22 +4,26 @@ #define WORKER_BUSY 'B' struct worker_job_type { - char name[WORKER_UTILIZATION_MAX_JOB_NAME_LENGTH + 1]; + STRING *name; + STRING *units; // statistics controlled variables size_t statistics_last_jobs_started; usec_t statistics_last_busy_time; + NETDATA_DOUBLE statistics_last_custom_value; // worker controlled variables volatile size_t worker_jobs_started; volatile usec_t worker_busy_time; + + WORKER_METRIC_TYPE type; + NETDATA_DOUBLE custom_value; }; struct worker { pid_t pid; const char *tag; const char *workname; - uint32_t workname_hash; // statistics controlled variables volatile usec_t statistics_last_checkpoint; @@ -27,6 +31,7 @@ struct worker { usec_t statistics_last_busy_time; // the worker controlled variables + size_t worker_max_job_id; volatile size_t job_id; volatile size_t jobs_started; volatile usec_t busy_time; @@ -36,11 +41,12 @@ struct worker { struct worker_job_type per_job_type[WORKER_UTILIZATION_MAX_JOB_TYPES]; struct worker *next; + struct worker *prev; }; -static netdata_mutex_t base_lock = NETDATA_MUTEX_INITIALIZER; -static struct worker *base = NULL; +static netdata_mutex_t workers_base_lock = NETDATA_MUTEX_INITIALIZER; static __thread struct worker *worker = NULL; +static Pvoid_t workers_per_workname_JudyHS_array = NULL; void worker_register(const char *workname) { if(unlikely(worker)) return; @@ -49,47 +55,72 @@ void worker_register(const char *workname) { worker->pid = gettid(); worker->tag = strdupz(netdata_thread_tag()); worker->workname = strdupz(workname); - worker->workname_hash = simple_hash(worker->workname); - usec_t now = now_realtime_usec(); + usec_t now = now_monotonic_usec(); worker->statistics_last_checkpoint = now; worker->last_action_timestamp = now; worker->last_action = WORKER_IDLE; - netdata_mutex_lock(&base_lock); - worker->next = base; - base = worker; - netdata_mutex_unlock(&base_lock); + size_t workname_size = strlen(workname) + 1; + netdata_mutex_lock(&workers_base_lock); + + Pvoid_t *PValue = JudyHSGet(workers_per_workname_JudyHS_array, (void *)workname, workname_size); + if(!PValue) + PValue = JudyHSIns(&workers_per_workname_JudyHS_array, (void *)workname, workname_size, PJE0); + + struct worker *base = *PValue; + DOUBLE_LINKED_LIST_APPEND_UNSAFE(base, worker, prev, next); + *PValue = base; + + netdata_mutex_unlock(&workers_base_lock); } -void worker_register_job_name(size_t job_id, const char *name) { +void worker_register_job_custom_metric(size_t job_id, const char *name, const char *units, WORKER_METRIC_TYPE type) { if(unlikely(!worker)) return; if(unlikely(job_id >= WORKER_UTILIZATION_MAX_JOB_TYPES)) { error("WORKER_UTILIZATION: job_id %zu is too big. Max is %zu", job_id, (size_t)(WORKER_UTILIZATION_MAX_JOB_TYPES - 1)); return; } - if (*worker->per_job_type[job_id].name) { - error("WORKER_UTILIZATION: duplicate job registration: worker '%s' job id %zu is '%s', ignoring '%s'", worker->workname, job_id, worker->per_job_type[job_id].name, name); + + if(job_id > worker->worker_max_job_id) + worker->worker_max_job_id = job_id; + + if(worker->per_job_type[job_id].name) { + if(strcmp(string2str(worker->per_job_type[job_id].name), name) != 0 || worker->per_job_type[job_id].type != type || strcmp(string2str(worker->per_job_type[job_id].units), units) != 0) + error("WORKER_UTILIZATION: duplicate job registration: worker '%s' job id %zu is '%s', ignoring the later '%s'", worker->workname, job_id, string2str(worker->per_job_type[job_id].name), name); return; } - strncpy(worker->per_job_type[job_id].name, name, WORKER_UTILIZATION_MAX_JOB_NAME_LENGTH); + worker->per_job_type[job_id].name = string_strdupz(name); + worker->per_job_type[job_id].units = string_strdupz(units); + worker->per_job_type[job_id].type = type; +} + +void worker_register_job_name(size_t job_id, const char *name) { + worker_register_job_custom_metric(job_id, name, "", WORKER_METRIC_IDLE_BUSY); } void worker_unregister(void) { if(unlikely(!worker)) return; - netdata_mutex_lock(&base_lock); - if(base == worker) - base = worker->next; - else { - struct worker *p; - for(p = base; p && p->next && p->next != worker ;p = p->next); - if(p && p->next == worker) - p->next = worker->next; + size_t workname_size = strlen(worker->workname) + 1; + netdata_mutex_lock(&workers_base_lock); + Pvoid_t *PValue = JudyHSGet(workers_per_workname_JudyHS_array, (void *)worker->workname, workname_size); + if(PValue) { + struct worker *base = *PValue; + DOUBLE_LINKED_LIST_REMOVE_UNSAFE(base, worker, prev, next); + *PValue = base; + + if(!base) + JudyHSDel(&workers_per_workname_JudyHS_array, (void *)worker->workname, workname_size, PJE0); + } + netdata_mutex_unlock(&workers_base_lock); + + for(int i = 0; i < WORKER_UTILIZATION_MAX_JOB_TYPES ;i++) { + string_freez(worker->per_job_type[i].name); + string_freez(worker->per_job_type[i].units); } - netdata_mutex_unlock(&base_lock); freez((void *)worker->tag); freez((void *)worker->workname); @@ -112,18 +143,16 @@ static inline void worker_is_idle_with_time(usec_t now) { } void worker_is_idle(void) { - if(unlikely(!worker)) return; - if(unlikely(worker->last_action != WORKER_BUSY)) return; + if(unlikely(!worker || worker->last_action != WORKER_BUSY)) return; - worker_is_idle_with_time(now_realtime_usec()); + worker_is_idle_with_time(now_monotonic_usec()); } void worker_is_busy(size_t job_id) { - if(unlikely(!worker)) return; - if(unlikely(job_id >= WORKER_UTILIZATION_MAX_JOB_TYPES)) - job_id = 0; + if(unlikely(!worker || job_id >= WORKER_UTILIZATION_MAX_JOB_TYPES)) + return; - usec_t now = now_realtime_usec(); + usec_t now = now_monotonic_usec(); if(worker->last_action == WORKER_BUSY) worker_is_idle_with_time(now); @@ -138,35 +167,112 @@ void worker_is_busy(size_t job_id) { worker->last_action = WORKER_BUSY; } +void worker_set_metric(size_t job_id, NETDATA_DOUBLE value) { + if(unlikely(!worker)) return; + if(unlikely(job_id >= WORKER_UTILIZATION_MAX_JOB_TYPES)) + return; + + switch(worker->per_job_type[job_id].type) { + case WORKER_METRIC_INCREMENT: + worker->per_job_type[job_id].custom_value += value; + break; + + case WORKER_METRIC_INCREMENTAL_TOTAL: + case WORKER_METRIC_ABSOLUTE: + default: + worker->per_job_type[job_id].custom_value = value; + break; + } +} // statistics interface -void workers_foreach(const char *workname, void (*callback)(void *data, pid_t pid, const char *thread_tag, size_t utilization_usec, size_t duration_usec, size_t jobs_started, size_t is_running, const char **job_types_names, size_t *job_types_jobs_started, usec_t *job_types_busy_time), void *data) { - netdata_mutex_lock(&base_lock); - uint32_t hash = simple_hash(workname); +void workers_foreach(const char *workname, void (*callback)( + void *data + , pid_t pid + , const char *thread_tag + , size_t max_job_id + , size_t utilization_usec + , size_t duration_usec + , size_t jobs_started, size_t is_running + , STRING **job_types_names + , STRING **job_types_units + , WORKER_METRIC_TYPE *job_metric_types + , size_t *job_types_jobs_started + , usec_t *job_types_busy_time + , NETDATA_DOUBLE *job_custom_values + ) + , void *data) { + netdata_mutex_lock(&workers_base_lock); usec_t busy_time, delta; size_t i, jobs_started, jobs_running; - struct worker *p; - for(p = base; p ; p = p->next) { - if(hash != p->workname_hash || strcmp(workname, p->workname)) continue; + size_t workname_size = strlen(workname) + 1; + struct worker *base = NULL; + Pvoid_t *PValue = JudyHSGet(workers_per_workname_JudyHS_array, (void *)workname, workname_size); + if(PValue) + base = *PValue; - usec_t now = now_realtime_usec(); + struct worker *p; + DOUBLE_LINKED_LIST_FOREACH_FORWARD(base, p, prev, next) { + usec_t now = now_monotonic_usec(); // find per job type statistics - const char *per_job_type_name[WORKER_UTILIZATION_MAX_JOB_TYPES]; + STRING *per_job_type_name[WORKER_UTILIZATION_MAX_JOB_TYPES]; + STRING *per_job_type_units[WORKER_UTILIZATION_MAX_JOB_TYPES]; + WORKER_METRIC_TYPE per_job_metric_type[WORKER_UTILIZATION_MAX_JOB_TYPES]; size_t per_job_type_jobs_started[WORKER_UTILIZATION_MAX_JOB_TYPES]; usec_t per_job_type_busy_time[WORKER_UTILIZATION_MAX_JOB_TYPES]; - for(i = 0; i < WORKER_UTILIZATION_MAX_JOB_TYPES ;i++) { - per_job_type_name[i] = p->per_job_type[i].name; - - size_t tmp_jobs_started = p->per_job_type[i].worker_jobs_started; - per_job_type_jobs_started[i] = tmp_jobs_started - p->per_job_type[i].statistics_last_jobs_started; - p->per_job_type[i].statistics_last_jobs_started = tmp_jobs_started; + NETDATA_DOUBLE per_job_custom_values[WORKER_UTILIZATION_MAX_JOB_TYPES]; - usec_t tmp_busy_time = p->per_job_type[i].worker_busy_time; - per_job_type_busy_time[i] = tmp_busy_time - p->per_job_type[i].statistics_last_busy_time; - p->per_job_type[i].statistics_last_busy_time = tmp_busy_time; + size_t max_job_id = p->worker_max_job_id; + for(i = 0; i <= max_job_id ;i++) { + per_job_type_name[i] = p->per_job_type[i].name; + per_job_type_units[i] = p->per_job_type[i].units; + per_job_metric_type[i] = p->per_job_type[i].type; + + switch(p->per_job_type[i].type) { + default: + case WORKER_METRIC_EMPTY: { + per_job_type_jobs_started[i] = 0; + per_job_type_busy_time[i] = 0; + per_job_custom_values[i] = NAN; + break; + } + + case WORKER_METRIC_IDLE_BUSY: { + size_t tmp_jobs_started = p->per_job_type[i].worker_jobs_started; + per_job_type_jobs_started[i] = tmp_jobs_started - p->per_job_type[i].statistics_last_jobs_started; + p->per_job_type[i].statistics_last_jobs_started = tmp_jobs_started; + + usec_t tmp_busy_time = p->per_job_type[i].worker_busy_time; + per_job_type_busy_time[i] = tmp_busy_time - p->per_job_type[i].statistics_last_busy_time; + p->per_job_type[i].statistics_last_busy_time = tmp_busy_time; + + per_job_custom_values[i] = NAN; + break; + } + + case WORKER_METRIC_ABSOLUTE: { + per_job_type_jobs_started[i] = 0; + per_job_type_busy_time[i] = 0; + + per_job_custom_values[i] = p->per_job_type[i].custom_value; + break; + } + + case WORKER_METRIC_INCREMENTAL_TOTAL: + case WORKER_METRIC_INCREMENT: { + per_job_type_jobs_started[i] = 0; + per_job_type_busy_time[i] = 0; + + NETDATA_DOUBLE tmp_custom_value = p->per_job_type[i].custom_value; + per_job_custom_values[i] = tmp_custom_value - p->per_job_type[i].statistics_last_custom_value; + p->per_job_type[i].statistics_last_custom_value = tmp_custom_value; + + break; + } + } } // get a copy of the worker variables @@ -203,8 +309,22 @@ void workers_foreach(const char *workname, void (*callback)(void *data, pid_t pi jobs_running = 1; } - callback(data, p->pid, p->tag, busy_time, delta, jobs_started, jobs_running, per_job_type_name, per_job_type_jobs_started, per_job_type_busy_time); + callback(data + , p->pid + , p->tag + , max_job_id + , busy_time + , delta + , jobs_started + , jobs_running + , per_job_type_name + , per_job_type_units + , per_job_metric_type + , per_job_type_jobs_started + , per_job_type_busy_time + , per_job_custom_values + ); } - netdata_mutex_unlock(&base_lock); + netdata_mutex_unlock(&workers_base_lock); } diff --git a/libnetdata/worker_utilization/worker_utilization.h b/libnetdata/worker_utilization/worker_utilization.h index 8f16fe054..04d24f1f7 100644 --- a/libnetdata/worker_utilization/worker_utilization.h +++ b/libnetdata/worker_utilization/worker_utilization.h @@ -6,17 +6,42 @@ // workers interfaces #define WORKER_UTILIZATION_MAX_JOB_TYPES 50 -#define WORKER_UTILIZATION_MAX_JOB_NAME_LENGTH 25 -extern void worker_register(const char *workname); -extern void worker_register_job_name(size_t job_id, const char *name); -extern void worker_unregister(void); +typedef enum { + WORKER_METRIC_EMPTY = 0, + WORKER_METRIC_IDLE_BUSY = 1, + WORKER_METRIC_ABSOLUTE = 2, + WORKER_METRIC_INCREMENT = 3, + WORKER_METRIC_INCREMENTAL_TOTAL = 4, +} WORKER_METRIC_TYPE; -extern void worker_is_idle(void); -extern void worker_is_busy(size_t job_id); +void worker_register(const char *workname); +void worker_register_job_name(size_t job_id, const char *name); +void worker_register_job_custom_metric(size_t job_id, const char *name, const char *units, WORKER_METRIC_TYPE type); +void worker_unregister(void); + +void worker_is_idle(void); +void worker_is_busy(size_t job_id); +void worker_set_metric(size_t job_id, NETDATA_DOUBLE value); // statistics interface -extern void workers_foreach(const char *workname, void (*callback)(void *data, pid_t pid, const char *thread_tag, size_t utilization_usec, size_t duration_usec, size_t jobs_started, size_t is_running, const char **job_types_names, size_t *job_types_jobs_started, usec_t *job_types_busy_time), void *data); +void workers_foreach(const char *workname, void (*callback)( + void *data + , pid_t pid + , const char *thread_tag + , size_t max_job_id + , size_t utilization_usec + , size_t duration_usec + , size_t jobs_started + , size_t is_running + , STRING **job_types_names + , STRING **job_types_units + , WORKER_METRIC_TYPE *job_metric_types + , size_t *job_types_jobs_started + , usec_t *job_types_busy_time + , NETDATA_DOUBLE *job_custom_values + ) + , void *data); #endif // WORKER_UTILIZATION_H -- cgit v1.2.3