| 1 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 2 | |
| 3 | #include "database/rrd.h" |
| 4 | |
| 5 | #define CPU_IDLEJITTER_SLEEP_TIME_MS 20 |
| 6 | |
| 7 | static void cpuidlejitter_main_cleanup(void *pptr) { |
| 8 | struct netdata_static_thread *static_thread = CLEANUP_FUNCTION_GET_PTR(pptr); |
| 9 | if(!static_thread) return; |
| 10 | |
| 11 | static_thread->enabled = NETDATA_MAIN_THREAD_EXITING; |
| 12 | |
| 13 | worker_unregister(); |
| 14 | |
| 15 | static_thread->enabled = NETDATA_MAIN_THREAD_EXITED; |
| 16 | } |
| 17 | |
| 18 | void cpuidlejitter_main(void *ptr) { |
| 19 | CLEANUP_FUNCTION_REGISTER(cpuidlejitter_main_cleanup) cleanup_ptr = ptr; |
| 20 | |
| 21 | worker_register("IDLEJITTER"); |
| 22 | worker_register_job_name(0, "measurements"); |
| 23 | |
| 24 | usec_t sleep_ut = inicfg_get_duration_ms(&netdata_config, "plugin:idlejitter", "loop time", CPU_IDLEJITTER_SLEEP_TIME_MS) * USEC_PER_MS; |
| 25 | if(sleep_ut <= 0) { |
| 26 | inicfg_set_duration_ms(&netdata_config, "plugin:idlejitter", "loop time", CPU_IDLEJITTER_SLEEP_TIME_MS); |
| 27 | sleep_ut = CPU_IDLEJITTER_SLEEP_TIME_MS * USEC_PER_MS; |
| 28 | } |
| 29 | |
| 30 | RRDSET *st = rrdset_create_localhost( |
| 31 | "system" |
| 32 | , "idlejitter" |
| 33 | , NULL |
| 34 | , "idlejitter" |
| 35 | , NULL |
| 36 | , "CPU Idle Jitter" |
| 37 | , "microseconds lost/s" |
| 38 | , "idlejitter.plugin" |
| 39 | , NULL |
| 40 | , NETDATA_CHART_PRIO_SYSTEM_IDLEJITTER |
| 41 | , localhost->rrd_update_every |
| 42 | , RRDSET_TYPE_AREA |
| 43 | ); |
| 44 | RRDDIM *rd_min = rrddim_add(st, "min", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); |
| 45 | RRDDIM *rd_max = rrddim_add(st, "max", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); |
| 46 | RRDDIM *rd_avg = rrddim_add(st, "average", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); |
| 47 | |
| 48 | usec_t update_every_ut = localhost->rrd_update_every * USEC_PER_SEC; |
| 49 | struct timeval before, after; |
| 50 | |
| 51 | while (service_running(SERVICE_COLLECTORS)) { |
| 52 | int iterations = 0; |
| 53 | usec_t error_total = 0, |
| 54 | error_min = 0, |
| 55 | error_max = 0, |
| 56 | elapsed = 0; |
| 57 | |
| 58 | while (elapsed < update_every_ut) { |
| 59 | now_monotonic_high_precision_timeval(&before); |
| 60 | worker_is_idle(); |
| 61 | sleep_usec(sleep_ut); |
| 62 | worker_is_busy(0); |
| 63 | now_monotonic_high_precision_timeval(&after); |
| 64 | |
| 65 | usec_t dt = dt_usec(&after, &before); |
| 66 | elapsed += dt; |
| 67 | |
| 68 | usec_t error = dt - sleep_ut; |
| 69 | error_total += error; |
| 70 | |
| 71 | if(unlikely(!iterations || error < error_min)) |
| 72 | error_min = error; |
| 73 | |
| 74 | if(error > error_max) |
| 75 | error_max = error; |
| 76 | |
| 77 | iterations++; |
| 78 | } |
| 79 | |
| 80 | if(iterations) { |
| 81 | rrddim_set_by_pointer(st, rd_min, error_min); |
| 82 | rrddim_set_by_pointer(st, rd_max, error_max); |
| 83 | rrddim_set_by_pointer(st, rd_avg, error_total / iterations); |
| 84 | rrdset_done(st); |
| 85 | } |
| 86 | } |
| 87 | } |
| 88 |