diff options
author | eplanet <emeric.planet@gmail.com> | 2017-03-26 12:54:07 +0200 |
---|---|---|
committer | Michael Stapelberg <stapelberg@users.noreply.github.com> | 2017-03-26 06:54:07 -0400 |
commit | 94651257cea4ff419f9cf2143d93193d5a5ccb96 (patch) | |
tree | ca563d7570df6c8e84e93a04ecf85037ab77eae8 /src | |
parent | 3ae0decbb33015fb111cdf7ea3d117bd6988cc05 (diff) |
Multiple CPU support for cpu_usage (#209)
This change addresses the issue #199 asking for multiple CPU support. It
takes an arbitrary CPU number and outputs its usage using the same
arithmetics as for CPU aggregation. It currently doesn't support
FreeBSD.
Diffstat (limited to 'src')
-rw-r--r-- | src/print_cpu_usage.c | 101 |
1 files changed, 78 insertions, 23 deletions
diff --git a/src/print_cpu_usage.c b/src/print_cpu_usage.c index 45a5ef2..c1ea3fd 100644 --- a/src/print_cpu_usage.c +++ b/src/print_cpu_usage.c @@ -33,36 +33,68 @@ #include "i3status.h" -static int prev_total = 0; -static int prev_idle = 0; +struct cpu_usage { + int user; + int nice; + int system; + int idle; + int total; +}; + +static int cpu_count = 0; +static struct cpu_usage prev_all = {0, 0, 0, 0, 0}; +static struct cpu_usage *prev_cpus = NULL; +static struct cpu_usage *curr_cpus = NULL; /* * Reads the CPU utilization from /proc/stat and returns the usage as a * percentage. * */ -void print_cpu_usage(yajl_gen json_gen, char *buffer, const char *format, const char *format_above_threshold, const char *format_above_degraded_threshold, const float max_threshold, const float degraded_threshold) { +void print_cpu_usage(yajl_gen json_gen, char *buffer, const char *format, const char *format_above_threshold, const char *format_above_degraded_threshold, const char *path, const float max_threshold, const float degraded_threshold) { const char *selected_format = format; const char *walk; char *outwalk = buffer; - int curr_user = 0, curr_nice = 0, curr_system = 0, curr_idle = 0, curr_total; + struct cpu_usage curr_all = {0, 0, 0, 0, 0}; int diff_idle, diff_total, diff_usage; bool colorful_output = false; #if defined(LINUX) - static char statpath[512]; - char buf[1024]; - strcpy(statpath, "/proc/stat"); - if (!slurp(statpath, buf, sizeof(buf)) || - sscanf(buf, "cpu %d %d %d %d", &curr_user, &curr_nice, &curr_system, &curr_idle) != 4) + + // Detecting if CPU count has changed + int curr_cpu_count = sysconf(_SC_NPROCESSORS_ONLN); + if (curr_cpu_count != cpu_count) { + cpu_count = curr_cpu_count; + free(prev_cpus); + prev_cpus = (struct cpu_usage *)calloc(cpu_count, sizeof(struct cpu_usage)); + free(curr_cpus); + curr_cpus = (struct cpu_usage *)calloc(cpu_count, sizeof(struct cpu_usage)); + } + + char buf[4096]; + if (!slurp(path, buf, sizeof(buf))) goto error; + // Parsing all cpu values using strtok + if (strtok(buf, "\n") == NULL) + goto error; + char *buf_itr = NULL; + for (int cpu_idx = 0; cpu_idx < cpu_count; cpu_idx++) { + buf_itr = strtok(NULL, "\n"); + int curr_cpu_idx = -1; + if (!buf_itr || sscanf(buf_itr, "cpu%d %d %d %d %d", &curr_cpu_idx, &curr_cpus[cpu_idx].user, &curr_cpus[cpu_idx].nice, &curr_cpus[cpu_idx].system, &curr_cpus[cpu_idx].idle) != 5 || curr_cpu_idx != cpu_idx) + goto error; + curr_cpus[cpu_idx].total = curr_cpus[cpu_idx].user + curr_cpus[cpu_idx].nice + curr_cpus[cpu_idx].system + curr_cpus[cpu_idx].idle; + curr_all.user += curr_cpus[cpu_idx].user; + curr_all.nice += curr_cpus[cpu_idx].nice; + curr_all.system += curr_cpus[cpu_idx].system; + curr_all.idle += curr_cpus[cpu_idx].idle; + curr_all.total += curr_cpus[cpu_idx].total; + } - curr_total = curr_user + curr_nice + curr_system + curr_idle; - diff_idle = curr_idle - prev_idle; - diff_total = curr_total - prev_total; + diff_idle = curr_all.idle - prev_all.idle; + diff_total = curr_all.total - prev_all.total; diff_usage = (diff_total ? (1000 * (diff_total - diff_idle) / diff_total + 5) / 10 : 0); - prev_total = curr_total; - prev_idle = curr_idle; + prev_all = curr_all; #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) @@ -84,16 +116,15 @@ void print_cpu_usage(yajl_gen json_gen, char *buffer, const char *format, const goto error; #endif - curr_user = cp_time[CP_USER]; - curr_nice = cp_time[CP_NICE]; - curr_system = cp_time[CP_SYS]; - curr_idle = cp_time[CP_IDLE]; - curr_total = curr_user + curr_nice + curr_system + curr_idle; - diff_idle = curr_idle - prev_idle; - diff_total = curr_total - prev_total; + curr_all.user = cp_time[CP_USER]; + curr_all.nice = cp_time[CP_NICE]; + curr_all.system = cp_time[CP_SYS]; + curr_all.idle = cp_time[CP_IDLE]; + curr_all.total = curr_all.user + curr_all.nice + curr_all.system + curr_all.idle; + diff_idle = curr_all.idle - prev_all.idle; + diff_total = curr_all.total - prev_all.total; diff_usage = (diff_total ? (1000 * (diff_total - diff_idle) / diff_total + 5) / 10 : 0); - prev_total = curr_total; - prev_idle = curr_idle; + prev_all = curr_all; #else goto error; #endif @@ -120,8 +151,32 @@ void print_cpu_usage(yajl_gen json_gen, char *buffer, const char *format, const outwalk += sprintf(outwalk, "%02d%s", diff_usage, pct_mark); walk += strlen("usage"); } +#if defined(LINUX) + if (BEGINS_WITH(walk + 1, "cpu")) { + int number = 0; + sscanf(walk + 1, "cpu%d", &number); + if (number < 0 || number >= cpu_count) { + fprintf(stderr, "provided CPU number '%d' above detected number of CPU %d\n", number, cpu_count); + } else { + int cpu_diff_idle = curr_cpus[number].idle - prev_cpus[number].idle; + int cpu_diff_total = curr_cpus[number].total - prev_cpus[number].total; + int cpu_diff_usage = (cpu_diff_total ? (1000 * (cpu_diff_total - cpu_diff_idle) / cpu_diff_total + 5) / 10 : 0); + outwalk += sprintf(outwalk, "%02d%s", cpu_diff_usage, pct_mark); + } + int padding = 1; + int step = 10; + while (step < number) { + step *= 10; + padding++; + } + walk += strlen("cpu") + padding; + } +#endif } + for (int i = 0; i < cpu_count; i++) + prev_cpus[i] = curr_cpus[i]; + if (colorful_output) END_COLOR; |