summaryrefslogtreecommitdiffstats
path: root/libnetdata/worker_utilization/worker_utilization.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-05 12:08:03 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-05 12:08:18 +0000
commit5da14042f70711ea5cf66e034699730335462f66 (patch)
tree0f6354ccac934ed87a2d555f45be4c831cf92f4a /libnetdata/worker_utilization/worker_utilization.c
parentReleasing debian version 1.44.3-2. (diff)
downloadnetdata-5da14042f70711ea5cf66e034699730335462f66.tar.xz
netdata-5da14042f70711ea5cf66e034699730335462f66.zip
Merging upstream version 1.45.3+dfsg.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'libnetdata/worker_utilization/worker_utilization.c')
-rw-r--r--libnetdata/worker_utilization/worker_utilization.c398
1 files changed, 0 insertions, 398 deletions
diff --git a/libnetdata/worker_utilization/worker_utilization.c b/libnetdata/worker_utilization/worker_utilization.c
deleted file mode 100644
index f39cea8a0..000000000
--- a/libnetdata/worker_utilization/worker_utilization.c
+++ /dev/null
@@ -1,398 +0,0 @@
-#include "worker_utilization.h"
-
-#define WORKER_IDLE 'I'
-#define WORKER_BUSY 'B'
-
-struct worker_job_type {
- 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;
-
- // statistics controlled variables
- volatile usec_t statistics_last_checkpoint;
- size_t statistics_last_jobs_started;
- 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;
- volatile usec_t last_action_timestamp;
- volatile char last_action;
-
- struct worker_job_type per_job_type[WORKER_UTILIZATION_MAX_JOB_TYPES];
-
- struct worker *next;
- struct worker *prev;
-};
-
-struct workers_workname { // this is what we add to JudyHS
- SPINLOCK spinlock;
- struct worker *base;
-};
-
-static struct workers_globals {
- bool enabled;
-
- SPINLOCK spinlock;
- Pvoid_t worknames_JudyHS;
- size_t memory;
-
-} workers_globals = { // workers globals, the base of all worknames
- .enabled = false,
- .spinlock = NETDATA_SPINLOCK_INITIALIZER, // a lock for the worknames index
- .worknames_JudyHS = NULL, // the worknames index
-};
-
-static __thread struct worker *worker = NULL; // the current thread worker
-
-static inline usec_t worker_now_monotonic_usec(void) {
-#ifdef NETDATA_WITHOUT_WORKERS_LATENCY
- return 0;
-#else
- return now_monotonic_usec();
-#endif
-}
-
-void workers_utilization_enable(void) {
- workers_globals.enabled = true;
-}
-
-size_t workers_allocated_memory(void) {
- if(!workers_globals.enabled)
- return 0;
-
- spinlock_lock(&workers_globals.spinlock);
- size_t memory = workers_globals.memory;
- spinlock_unlock(&workers_globals.spinlock);
-
- return memory;
-}
-
-void worker_register(const char *name) {
- if(unlikely(worker || !workers_globals.enabled))
- return;
-
- worker = callocz(1, sizeof(struct worker));
- worker->pid = gettid();
- worker->tag = strdupz(netdata_thread_tag());
- worker->workname = strdupz(name);
-
- usec_t now = worker_now_monotonic_usec();
- worker->statistics_last_checkpoint = now;
- worker->last_action_timestamp = now;
- worker->last_action = WORKER_IDLE;
-
- size_t name_size = strlen(name) + 1;
- spinlock_lock(&workers_globals.spinlock);
-
- workers_globals.memory += sizeof(struct worker) + strlen(worker->tag) + 1 + strlen(worker->workname) + 1;
-
- Pvoid_t *PValue = JudyHSIns(&workers_globals.worknames_JudyHS, (void *)name, name_size, PJE0);
-
- struct workers_workname *workname = *PValue;
- if(!workname) {
- workname = mallocz(sizeof(struct workers_workname));
- spinlock_init(&workname->spinlock);
- workname->base = NULL;
- *PValue = workname;
-
- workers_globals.memory += sizeof(struct workers_workname) + JUDYHS_INDEX_SIZE_ESTIMATE(name_size);
- }
-
- spinlock_lock(&workname->spinlock);
- DOUBLE_LINKED_LIST_APPEND_ITEM_UNSAFE(workname->base, worker, prev, next);
- spinlock_unlock(&workname->spinlock);
-
- spinlock_unlock(&workers_globals.spinlock);
-}
-
-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)) {
- netdata_log_error("WORKER_UTILIZATION: job_id %zu is too big. Max is %zu", job_id, (size_t)(WORKER_UTILIZATION_MAX_JOB_TYPES - 1));
- return;
- }
-
- 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)
- netdata_log_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;
- }
-
- 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;
-
- size_t workname_size = strlen(worker->workname) + 1;
- spinlock_lock(&workers_globals.spinlock);
- Pvoid_t *PValue = JudyHSGet(workers_globals.worknames_JudyHS, (void *)worker->workname, workname_size);
- if(PValue) {
- struct workers_workname *workname = *PValue;
- spinlock_lock(&workname->spinlock);
- DOUBLE_LINKED_LIST_REMOVE_ITEM_UNSAFE(workname->base, worker, prev, next);
- spinlock_unlock(&workname->spinlock);
-
- if(!workname->base) {
- JudyHSDel(&workers_globals.worknames_JudyHS, (void *) worker->workname, workname_size, PJE0);
- freez(workname);
- workers_globals.memory -= sizeof(struct workers_workname) + JUDYHS_INDEX_SIZE_ESTIMATE(workname_size);
- }
- }
- workers_globals.memory -= sizeof(struct worker) + strlen(worker->tag) + 1 + strlen(worker->workname) + 1;
- spinlock_unlock(&workers_globals.spinlock);
-
- 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);
- }
-
- freez((void *)worker->tag);
- freez((void *)worker->workname);
- freez(worker);
-
- worker = NULL;
-}
-
-static inline void worker_is_idle_with_time(usec_t now) {
- usec_t delta = now - worker->last_action_timestamp;
- worker->busy_time += delta;
- worker->per_job_type[worker->job_id].worker_busy_time += delta;
-
- // the worker was busy
- // set it to idle before we set the timestamp
-
- worker->last_action = WORKER_IDLE;
- if(likely(worker->last_action_timestamp < now))
- worker->last_action_timestamp = now;
-}
-
-void worker_is_idle(void) {
- if(unlikely(!worker || worker->last_action != WORKER_BUSY)) return;
-
- worker_is_idle_with_time(worker_now_monotonic_usec());
-}
-
-void worker_is_busy(size_t job_id) {
- if(unlikely(!worker || job_id >= WORKER_UTILIZATION_MAX_JOB_TYPES))
- return;
-
- usec_t now = worker_now_monotonic_usec();
-
- if(worker->last_action == WORKER_BUSY)
- worker_is_idle_with_time(now);
-
- // the worker was idle
- // set the timestamp and then set it to busy
-
- worker->job_id = job_id;
- worker->per_job_type[job_id].worker_jobs_started++;
- worker->jobs_started++;
- worker->last_action_timestamp = now;
- 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 *name, 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) {
- if(!workers_globals.enabled)
- return;
-
- spinlock_lock(&workers_globals.spinlock);
- usec_t busy_time, delta;
- size_t i, jobs_started, jobs_running;
-
- size_t workname_size = strlen(name) + 1;
- struct workers_workname *workname;
- Pvoid_t *PValue = JudyHSGet(workers_globals.worknames_JudyHS, (void *)name, workname_size);
- if(PValue) {
- workname = *PValue;
- spinlock_lock(&workname->spinlock);
- }
- else
- workname = NULL;
-
- spinlock_unlock(&workers_globals.spinlock);
-
- if(!workname)
- return;
-
- struct worker *p;
- DOUBLE_LINKED_LIST_FOREACH_FORWARD(workname->base, p, prev, next) {
- usec_t now = worker_now_monotonic_usec();
-
- // find per job type statistics
- 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];
- NETDATA_DOUBLE per_job_custom_values[WORKER_UTILIZATION_MAX_JOB_TYPES];
-
- 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
- size_t worker_job_id = p->job_id;
- usec_t worker_busy_time = p->busy_time;
- size_t worker_jobs_started = p->jobs_started;
- char worker_last_action = p->last_action;
- usec_t worker_last_action_timestamp = p->last_action_timestamp;
-
- delta = now - p->statistics_last_checkpoint;
- p->statistics_last_checkpoint = now;
-
- // this is the only variable both the worker thread and the statistics thread are writing
- // we set this only when the worker is busy, so that the worker will not
- // accumulate all the busy time, but only the time after the point we collected statistics
- if(worker_last_action == WORKER_BUSY && p->last_action_timestamp == worker_last_action_timestamp && p->last_action == WORKER_BUSY)
- p->last_action_timestamp = now;
-
- // calculate delta busy time
- busy_time = worker_busy_time - p->statistics_last_busy_time;
- p->statistics_last_busy_time = worker_busy_time;
-
- // calculate delta jobs done
- jobs_started = worker_jobs_started - p->statistics_last_jobs_started;
- p->statistics_last_jobs_started = worker_jobs_started;
-
- jobs_running = 0;
- if(worker_last_action == WORKER_BUSY) {
- // the worker is still busy with something
- // let's add that busy time to the reported one
- usec_t dt = now - worker_last_action_timestamp;
- busy_time += dt;
- per_job_type_busy_time[worker_job_id] += dt;
- jobs_running = 1;
- }
-
- 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
- );
- }
-
- spinlock_unlock(&workname->spinlock);
-}