summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authoreplanet <emeric.planet@gmail.com>2017-03-26 12:54:07 +0200
committerMichael Stapelberg <stapelberg@users.noreply.github.com>2017-03-26 06:54:07 -0400
commit94651257cea4ff419f9cf2143d93193d5a5ccb96 (patch)
treeca563d7570df6c8e84e93a04ecf85037ab77eae8 /src
parent3ae0decbb33015fb111cdf7ea3d117bd6988cc05 (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.c101
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;