diff options
| -rw-r--r-- | i3status.c | 3 | ||||
| -rw-r--r-- | include/i3status.h | 2 | ||||
| -rw-r--r-- | man/i3status.man | 7 | ||||
| -rw-r--r-- | src/print_cpu_usage.c | 101 | ||||
| -rw-r--r-- | testcases/010-cpu-usage/expected_output.txt | 1 | ||||
| -rw-r--r-- | testcases/010-cpu-usage/i3status.conf | 12 | ||||
| -rw-r--r-- | testcases/010-cpu-usage/stat | 3 | ||||
| -rw-r--r-- | testcases/011-cpu-usage/expected_output.txt | 1 | ||||
| -rw-r--r-- | testcases/011-cpu-usage/i3status.conf | 12 | ||||
| -rw-r--r-- | testcases/011-cpu-usage/stat | 3 | ||||
| -rw-r--r-- | testcases/012-cpu-usage-error/expected_output.txt | 1 | ||||
| -rw-r--r-- | testcases/012-cpu-usage-error/i3status.conf | 12 | ||||
| -rw-r--r-- | testcases/012-cpu-usage-error/stat | 2 | ||||
| -rw-r--r-- | testcases/013-cpu-usage-error/expected_output.txt | 1 | ||||
| -rw-r--r-- | testcases/013-cpu-usage-error/i3status.conf | 12 | ||||
| -rw-r--r-- | testcases/013-cpu-usage-error/stat | 2 | 
16 files changed, 148 insertions, 27 deletions
| @@ -422,6 +422,7 @@ int main(int argc, char *argv[]) {          CFG_STR("format", "%usage", CFGF_NONE),          CFG_STR("format_above_threshold", NULL, CFGF_NONE),          CFG_STR("format_above_degraded_threshold", NULL, CFGF_NONE), +        CFG_STR("path", "/proc/stat", CFGF_NONE),          CFG_FLOAT("max_threshold", 95, CFGF_NONE),          CFG_FLOAT("degraded_threshold", 90, CFGF_NONE),          CFG_CUSTOM_ALIGN_OPT, @@ -751,7 +752,7 @@ int main(int argc, char *argv[]) {              CASE_SEC("cpu_usage") {                  SEC_OPEN_MAP("cpu_usage"); -                print_cpu_usage(json_gen, buffer, cfg_getstr(sec, "format"), cfg_getstr(sec, "format_above_threshold"), cfg_getstr(sec, "format_above_degraded_threshold"), cfg_getfloat(sec, "max_threshold"), cfg_getfloat(sec, "degraded_threshold")); +                print_cpu_usage(json_gen, buffer, cfg_getstr(sec, "format"), cfg_getstr(sec, "format_above_threshold"), cfg_getstr(sec, "format_above_degraded_threshold"), cfg_getstr(sec, "path"), cfg_getfloat(sec, "max_threshold"), cfg_getfloat(sec, "degraded_threshold"));                  SEC_CLOSE_MAP;              }          } diff --git a/include/i3status.h b/include/i3status.h index a0e1e31..5042832 100644 --- a/include/i3status.h +++ b/include/i3status.h @@ -220,7 +220,7 @@ void print_wireless_info(yajl_gen json_gen, char *buffer, const char *interface,  void print_run_watch(yajl_gen json_gen, char *buffer, const char *title, const char *pidfile, const char *format, const char *format_down);  void print_path_exists(yajl_gen json_gen, char *buffer, const char *title, const char *path, const char *format, const char *format_down);  void print_cpu_temperature_info(yajl_gen json_gen, char *buffer, int zone, const char *path, const char *format, const char *format_above_threshold, int); -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);  void print_eth_info(yajl_gen json_gen, char *buffer, const char *interface, const char *format_up, const char *format_down);  void print_load(yajl_gen json_gen, char *buffer, const char *format, const char *format_above_threshold, const float max_threshold);  void print_volume(yajl_gen json_gen, char *buffer, const char *fmt, const char *fmt_muted, const char *device, const char *mixer, int mixer_idx); diff --git a/man/i3status.man b/man/i3status.man index 22d51ca..f1b6221 100644 --- a/man/i3status.man +++ b/man/i3status.man @@ -405,13 +405,16 @@ format_above_threshold.  It is possible to define a degraded_threshold that will color the load  value yellow in case the CPU average over the last interval is getting -higher than the configured threshold.  Defaults to 90. The output format +higher than the configured threshold. Defaults to 90. The output format  when above degraded threshold can be customized with  format_above_degraded_threshold. +For displaying the Nth CPU usage, you can use the %cpu<N> format string, +starting from %cpu0. This feature is currently not supported in FreeBSD. +  *Example order*: +cpu_usage+ -*Example format*: +%usage+ +*Example format*: +all: %usage CPU_0: %cpu0 CPU_1: %cpu1+  *Example max_threshold*: +75+ 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; diff --git a/testcases/010-cpu-usage/expected_output.txt b/testcases/010-cpu-usage/expected_output.txt new file mode 100644 index 0000000..336596e --- /dev/null +++ b/testcases/010-cpu-usage/expected_output.txt @@ -0,0 +1 @@ +all: 75% CPU_0: 100% CPU_1: 50% diff --git a/testcases/010-cpu-usage/i3status.conf b/testcases/010-cpu-usage/i3status.conf new file mode 100644 index 0000000..57cddf2 --- /dev/null +++ b/testcases/010-cpu-usage/i3status.conf @@ -0,0 +1,12 @@ +general { +        output_format = "none" +} + +order += "cpu_usage" + +cpu_usage { +    format = "all: %usage CPU_0: %cpu0 CPU_1: %cpu1" +    path = "testcases/010-cpu-usage/stat" +    max_threshold = 90 +    degraded_threshold = 75 +} diff --git a/testcases/010-cpu-usage/stat b/testcases/010-cpu-usage/stat new file mode 100644 index 0000000..6fbc94e --- /dev/null +++ b/testcases/010-cpu-usage/stat @@ -0,0 +1,3 @@ +cpu  0 0 0 0 0 0 0 0 0 0 +cpu0 100 0 0 0 0 0 0 0 0 0 +cpu1 50 0 0 50 0 0 0 0 0 0 diff --git a/testcases/011-cpu-usage/expected_output.txt b/testcases/011-cpu-usage/expected_output.txt new file mode 100644 index 0000000..930a2b5 --- /dev/null +++ b/testcases/011-cpu-usage/expected_output.txt @@ -0,0 +1 @@ +all: 50% CPU_0: 00% CPU_1: 100% diff --git a/testcases/011-cpu-usage/i3status.conf b/testcases/011-cpu-usage/i3status.conf new file mode 100644 index 0000000..39320d3 --- /dev/null +++ b/testcases/011-cpu-usage/i3status.conf @@ -0,0 +1,12 @@ +general { +        output_format = "none" +} + +order += "cpu_usage" + +cpu_usage { +    format = "all: %usage CPU_0: %cpu0 CPU_1: %cpu1" +    path = "testcases/011-cpu-usage/stat" +    max_threshold = 90 +    degraded_threshold = 75 +} diff --git a/testcases/011-cpu-usage/stat b/testcases/011-cpu-usage/stat new file mode 100644 index 0000000..9c77e7e --- /dev/null +++ b/testcases/011-cpu-usage/stat @@ -0,0 +1,3 @@ +cpu  0 0 0 0 0 0 0 0 0 0 +cpu0 0 0 0 300 0 0 0 0 0 0 +cpu1 100 100 100 0 0 0 0 0 0 0 diff --git a/testcases/012-cpu-usage-error/expected_output.txt b/testcases/012-cpu-usage-error/expected_output.txt new file mode 100644 index 0000000..3a74003 --- /dev/null +++ b/testcases/012-cpu-usage-error/expected_output.txt @@ -0,0 +1 @@ +cant read cpu usage diff --git a/testcases/012-cpu-usage-error/i3status.conf b/testcases/012-cpu-usage-error/i3status.conf new file mode 100644 index 0000000..285d415 --- /dev/null +++ b/testcases/012-cpu-usage-error/i3status.conf @@ -0,0 +1,12 @@ +general { +        output_format = "none" +} + +order += "cpu_usage" + +cpu_usage { +    format = "all: %usage CPU_0: %cpu0 CPU_1: %cpu1" +    path = "testcases/012-cpu-usage-error/stat" +    max_threshold = 90 +    degraded_threshold = 75 +} diff --git a/testcases/012-cpu-usage-error/stat b/testcases/012-cpu-usage-error/stat new file mode 100644 index 0000000..cb9b6e3 --- /dev/null +++ b/testcases/012-cpu-usage-error/stat @@ -0,0 +1,2 @@ +cpu  0 0 0 0 0 0 0 0 0 0 +cpu0 100 0 0 0 0 0 0 0 0 0 diff --git a/testcases/013-cpu-usage-error/expected_output.txt b/testcases/013-cpu-usage-error/expected_output.txt new file mode 100644 index 0000000..3a74003 --- /dev/null +++ b/testcases/013-cpu-usage-error/expected_output.txt @@ -0,0 +1 @@ +cant read cpu usage diff --git a/testcases/013-cpu-usage-error/i3status.conf b/testcases/013-cpu-usage-error/i3status.conf new file mode 100644 index 0000000..a55934e --- /dev/null +++ b/testcases/013-cpu-usage-error/i3status.conf @@ -0,0 +1,12 @@ +general { +        output_format = "none" +} + +order += "cpu_usage" + +cpu_usage { +    format = "all: %usage CPU_0: %cpu0 CPU_1: %cpu1" +    path = "testcases/013-cpu-usage-error/stat" +    max_threshold = 90 +    degraded_threshold = 75 +} diff --git a/testcases/013-cpu-usage-error/stat b/testcases/013-cpu-usage-error/stat new file mode 100644 index 0000000..3ded833 --- /dev/null +++ b/testcases/013-cpu-usage-error/stat @@ -0,0 +1,2 @@ +cpu0 100 0 0 0 0 0 0 0 0 0 +cpu1 50 0 0 50 0 0 0 0 0 0 | 
