summaryrefslogtreecommitdiffstats
path: root/libnetdata/worker_utilization/worker_utilization.c
diff options
context:
space:
mode:
Diffstat (limited to 'libnetdata/worker_utilization/worker_utilization.c')
-rw-r--r--libnetdata/worker_utilization/worker_utilization.c218
1 files changed, 169 insertions, 49 deletions
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);
}