X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fprint_cpu_usage.c;h=411d5f4ca7c3325eccca57f21c63cb9348fa4b6a;hb=0b8aa86ecbec930ef0315bc4627c0f48966769d2;hp=7fdd11c50807744bf6a0348c4000686157d79884;hpb=1b3aa404858b476015a2b29d0c42f7dbbed915bc;p=i3%2Fi3status diff --git a/src/print_cpu_usage.c b/src/print_cpu_usage.c index 7fdd11c..411d5f4 100644 --- a/src/print_cpu_usage.c +++ b/src/print_cpu_usage.c @@ -1,4 +1,4 @@ -// vim:sw=8:sts=8:ts=8:expandtab +// vim:ts=4:sw=4:expandtab #include #include #include @@ -6,76 +6,184 @@ #include #include -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) || defined(__OpenBSD__) +#include #include #include +#if defined(__OpenBSD__) +#include +#else #include #endif +#endif + +#if defined(__DragonFly__) +#include +#include +#include +#include +#endif + +#if defined(__NetBSD__) +#include +#include +#include +#include +#endif #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 *walk; - char *outwalk = buffer; - char buf[1024]; - int curr_user = 0, curr_nice = 0, curr_system = 0, curr_idle = 0, curr_total; - int diff_idle, diff_total, diff_usage; +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; + 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]; - 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) - goto error; - - curr_total = curr_user + curr_nice + curr_system + curr_idle; - diff_idle = curr_idle - prev_idle; - diff_total = curr_total - prev_total; - diff_usage = (1000 * (diff_total - diff_idle)/diff_total + 5)/10; - prev_total = curr_total; - prev_idle = curr_idle; -#elif defined(__FreeBSD__) - size_t size; - long cp_time[CPUSTATES]; - size = sizeof cp_time; - if (sysctlbyname("kern.cp_time", &cp_time, &size, NULL, 0) < 0) - goto error; - - 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; - diff_usage = (1000 * (diff_total - diff_idle)/diff_total + 5)/10; - prev_total = curr_total; - prev_idle = curr_idle; + + // 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; + } + + 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_all = curr_all; +#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) + +#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) + size_t size; + long cp_time[CPUSTATES]; + size = sizeof cp_time; + if (sysctlbyname("kern.cp_time", &cp_time, &size, NULL, 0) < 0) + goto error; #else + /* This information is taken from the boot cpu, any other cpus are currently ignored. */ + long cp_time[CPUSTATES]; + int mib[2]; + size_t size = sizeof(cp_time); + + mib[0] = CTL_KERN; + mib[1] = KERN_CPTIME; + + if (sysctl(mib, 2, cp_time, &size, NULL, 0)) goto error; #endif - for (walk = format; *walk != '\0'; walk++) { - if (*walk != '%') { - *(outwalk++) = *walk; - continue; - } - - if (strncmp(walk+1, "usage", strlen("usage")) == 0) { - outwalk += sprintf(outwalk, "%02d%%", diff_usage); - walk += strlen("usage"); - } + + 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_all = curr_all; +#else + goto error; +#endif + + if (diff_usage >= max_threshold) { + START_COLOR("color_bad"); + colorful_output = true; + if (format_above_threshold != NULL) + selected_format = format_above_threshold; + } else if (diff_usage >= degraded_threshold) { + START_COLOR("color_degraded"); + colorful_output = true; + if (format_above_degraded_threshold != NULL) + selected_format = format_above_degraded_threshold; + } + + for (walk = selected_format; *walk != '\0'; walk++) { + if (*walk != '%') { + *(outwalk++) = *walk; + + } else if (BEGINS_WITH(walk + 1, "usage")) { + outwalk += sprintf(outwalk, "%02d%s", diff_usage, pct_mark); + walk += strlen("usage"); + } +#if defined(LINUX) + else if (BEGINS_WITH(walk + 1, "cpu")) { + int number = -1; + 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 + else { + *(outwalk++) = '%'; + } + } + + for (int i = 0; i < cpu_count; i++) + prev_cpus[i] = curr_cpus[i]; + + if (colorful_output) + END_COLOR; - OUTPUT_FULL_TEXT(buffer); - return; + OUTPUT_FULL_TEXT(buffer); + return; error: - (void)fputs("Cannot read usage\n", stderr); + OUTPUT_FULL_TEXT("cant read cpu usage"); + (void)fputs("i3status: Cannot read CPU usage\n", stderr); }