From c55754542ec8f17246415fa19baf06ef7dc6ab87 Mon Sep 17 00:00:00 2001 From: Felix Buehler Date: Tue, 20 Mar 2018 15:35:28 +0100 Subject: Implement support for memory-usage on Linux --- src/print_mem.c | 208 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 208 insertions(+) create mode 100644 src/print_mem.c (limited to 'src') diff --git a/src/print_mem.c b/src/print_mem.c new file mode 100644 index 0000000..c2f48f4 --- /dev/null +++ b/src/print_mem.c @@ -0,0 +1,208 @@ +// vim:ts=4:sw=4:expandtab +#include +#include +#include +#include +#include +#include "i3status.h" + +#define BINARY_BASE UINT64_C(1024) + +#define MAX_EXPONENT 4 +static const char *const iec_symbols[MAX_EXPONENT + 1] = {"", "Ki", "Mi", "Gi", "Ti"}; + +static const char filename[] = "/proc/meminfo"; + +/* + * Prints the given amount of bytes in a human readable manner. + * + */ +static int print_bytes_human(char *outwalk, uint64_t bytes) { + double size = bytes; + int exponent = 0; + int bin_base = BINARY_BASE; + while (size >= bin_base && exponent < MAX_EXPONENT) { + size /= bin_base; + exponent += 1; + } + return sprintf(outwalk, "%.1f %sB", size, iec_symbols[exponent]); +} + +/* + * Determines whether remaining bytes are below given threshold. + * + */ +static bool below_threshold(const long totalRam, const long usedRam, const char *threshold_type, const long low_threshold) { + // empty is available or free, based on "use_available_memory" + long empty = totalRam - usedRam; + if (BEGINS_WITH(threshold_type, "percentage_")) { + return 100.0 * empty / totalRam < low_threshold; + } else if (strcasecmp(threshold_type, "bytes_free") == 0) { + return empty < low_threshold; + } else if (threshold_type[0] != '\0' && strncasecmp(threshold_type + 1, "bytes_", strlen("bytes_")) == 0) { + uint64_t base = BINARY_BASE; + long factor = 1; + + switch (threshold_type[0]) { + case 'T': + case 't': + factor *= base; + case 'G': + case 'g': + factor *= base; + case 'M': + case 'm': + factor *= base; + case 'K': + case 'k': + factor *= base; + break; + default: + return false; + } + return empty < low_threshold * factor; + } + return false; +} + +void print_memory(yajl_gen json_gen, char *buffer, const char *format, const char *degraded_format_below_threshold, const char *degraded_threshold_type, const float degraded_low_threshold, const char *critical_format_below_threshold, const char *critical_threshold_type, const float critical_low_threshold, const bool use_available_memory) { + char *outwalk = buffer; + +#if defined(linux) + const char *selected_format = format; + const char *walk; + bool colorful_output = false; + + long totalRam = -1; + long freeRam = -1; + long availableRam = -1; + long usedRam = -1; + long sharedRam = -1; + long cached = -1; + long buffers = -1; + + FILE *file = fopen(filename, "r"); + if (!file) { + goto error; + } + char line[128]; + while (fgets(line, sizeof line, file)) { + if (BEGINS_WITH(line, "MemTotal:")) { + totalRam = strtol(line + strlen("MemTotal:"), NULL, 10); + } + if (BEGINS_WITH(line, "MemFree:")) { + freeRam = strtol(line + strlen("MemFree:"), NULL, 10); + } + if (BEGINS_WITH(line, "MemAvailable:")) { + availableRam = strtol(line + strlen("MemAvailable:"), NULL, 10); + } + if (BEGINS_WITH(line, "Buffers:")) { + buffers = strtol(line + strlen("Buffers:"), NULL, 10); + } + if (BEGINS_WITH(line, "Cached:")) { + cached = strtol(line + strlen("Cached:"), NULL, 10); + } + if (BEGINS_WITH(line, "Shmem:")) { + sharedRam = strtol(line + strlen("Shmem:"), NULL, 10); + } + if (totalRam != -1 && freeRam != -1 && availableRam != -1 && buffers != -1 && cached != -1 && sharedRam != -1) { + break; + } + } + fclose(file); + + if (totalRam == -1 || freeRam == -1 || availableRam == -1 || buffers == -1 || cached == -1 || sharedRam == -1) { + goto error; + } + + totalRam = totalRam * BINARY_BASE; + freeRam = freeRam * BINARY_BASE; + availableRam = availableRam * BINARY_BASE; + buffers = buffers * BINARY_BASE; + cached = cached * BINARY_BASE; + sharedRam = sharedRam * BINARY_BASE; + if (use_available_memory) { + usedRam = totalRam - availableRam; + } else { + usedRam = totalRam - freeRam - buffers - cached; + } + + if (degraded_low_threshold > 0 && below_threshold(totalRam, usedRam, degraded_threshold_type, degraded_low_threshold)) { + if (critical_low_threshold > 0 && below_threshold(totalRam, usedRam, critical_threshold_type, critical_low_threshold)) { + START_COLOR("color_bad"); + colorful_output = true; + if (critical_format_below_threshold != NULL) + selected_format = critical_format_below_threshold; + } else { + START_COLOR("color_degraded"); + colorful_output = true; + if (degraded_format_below_threshold != NULL) + selected_format = degraded_format_below_threshold; + } + } + + for (walk = selected_format; *walk != '\0'; walk++) { + if (*walk != '%') { + *(outwalk++) = *walk; + continue; + } + if (BEGINS_WITH(walk + 1, "total")) { + outwalk += print_bytes_human(outwalk, totalRam); + walk += strlen("total"); + } + + if (BEGINS_WITH(walk + 1, "used")) { + outwalk += print_bytes_human(outwalk, usedRam); + walk += strlen("used"); + } + + if (BEGINS_WITH(walk + 1, "free")) { + outwalk += print_bytes_human(outwalk, freeRam); + walk += strlen("free"); + } + + if (BEGINS_WITH(walk + 1, "available")) { + outwalk += print_bytes_human(outwalk, availableRam); + walk += strlen("available"); + } + + if (BEGINS_WITH(walk + 1, "shared")) { + outwalk += print_bytes_human(outwalk, sharedRam); + walk += strlen("shared"); + } + + if (BEGINS_WITH(walk + 1, "percentage_free")) { + outwalk += sprintf(outwalk, "%.01f%s", 100.0 * freeRam / totalRam, pct_mark); + walk += strlen("percentage_free"); + } + + if (BEGINS_WITH(walk + 1, "percentage_available")) { + outwalk += sprintf(outwalk, "%.01f%s", 100.0 * availableRam / totalRam, pct_mark); + walk += strlen("percentage_available"); + } + + if (BEGINS_WITH(walk + 1, "percentage_used")) { + outwalk += sprintf(outwalk, "%.01f%s", 100.0 * usedRam / totalRam, pct_mark); + walk += strlen("percentage_used"); + } + + if (BEGINS_WITH(walk + 1, "percentage_shared")) { + outwalk += sprintf(outwalk, "%.01f%s", 100.0 * sharedRam / totalRam, pct_mark); + walk += strlen("percentage_shared"); + } + } + + if (colorful_output) + END_COLOR; + + *outwalk = '\0'; + OUTPUT_FULL_TEXT(buffer); + + return; +error: + OUTPUT_FULL_TEXT("can't read memory"); + fputs("i3status: Cannot read system memory using /proc/meminfo\n", stderr); +#else + fputs("i3status: Memory status information is not supported on this system\n", stderr); +#endif +} -- cgit v1.2.3 From 7839e93c9b9ef9635109a9130edf012a80335897 Mon Sep 17 00:00:00 2001 From: Benedikt Heine Date: Mon, 16 Apr 2018 15:41:13 +0200 Subject: Rename ram variables consistently --- src/print_mem.c | 89 +++++++++++++++++++++++++++++---------------------------- 1 file changed, 45 insertions(+), 44 deletions(-) (limited to 'src') diff --git a/src/print_mem.c b/src/print_mem.c index c2f48f4..fe93d0b 100644 --- a/src/print_mem.c +++ b/src/print_mem.c @@ -11,7 +11,7 @@ #define MAX_EXPONENT 4 static const char *const iec_symbols[MAX_EXPONENT + 1] = {"", "Ki", "Mi", "Gi", "Ti"}; -static const char filename[] = "/proc/meminfo"; +static const char memoryfile_linux[] = "/proc/meminfo"; /* * Prints the given amount of bytes in a human readable manner. @@ -32,30 +32,30 @@ static int print_bytes_human(char *outwalk, uint64_t bytes) { * Determines whether remaining bytes are below given threshold. * */ -static bool below_threshold(const long totalRam, const long usedRam, const char *threshold_type, const long low_threshold) { +static bool below_threshold(const long ram_total, const long ram_used, const char *threshold_type, const long low_threshold) { // empty is available or free, based on "use_available_memory" - long empty = totalRam - usedRam; + long empty = ram_total - ram_used; if (BEGINS_WITH(threshold_type, "percentage_")) { - return 100.0 * empty / totalRam < low_threshold; + return 100.0 * empty / ram_total < low_threshold; } else if (strcasecmp(threshold_type, "bytes_free") == 0) { return empty < low_threshold; } else if (threshold_type[0] != '\0' && strncasecmp(threshold_type + 1, "bytes_", strlen("bytes_")) == 0) { - uint64_t base = BINARY_BASE; + long factor = 1; switch (threshold_type[0]) { case 'T': case 't': - factor *= base; + factor *= BINARY_BASE; case 'G': case 'g': - factor *= base; + factor *= BINARY_BASE; case 'M': case 'm': - factor *= base; + factor *= BINARY_BASE; case 'K': case 'k': - factor *= base; + factor *= BINARY_BASE; break; default: return false; @@ -73,62 +73,62 @@ void print_memory(yajl_gen json_gen, char *buffer, const char *format, const cha const char *walk; bool colorful_output = false; - long totalRam = -1; - long freeRam = -1; - long availableRam = -1; - long usedRam = -1; - long sharedRam = -1; - long cached = -1; - long buffers = -1; + long ram_total = -1; + long ram_free = -1; + long ram_available = -1; + long ram_used = -1; + long ram_shared = -1; + long ram_cached = -1; + long ram_buffers = -1; - FILE *file = fopen(filename, "r"); + FILE *file = fopen(memoryfile_linux, "r"); if (!file) { goto error; } char line[128]; while (fgets(line, sizeof line, file)) { if (BEGINS_WITH(line, "MemTotal:")) { - totalRam = strtol(line + strlen("MemTotal:"), NULL, 10); + ram_total = strtol(line + strlen("MemTotal:"), NULL, 10); } if (BEGINS_WITH(line, "MemFree:")) { - freeRam = strtol(line + strlen("MemFree:"), NULL, 10); + ram_free = strtol(line + strlen("MemFree:"), NULL, 10); } if (BEGINS_WITH(line, "MemAvailable:")) { - availableRam = strtol(line + strlen("MemAvailable:"), NULL, 10); + ram_available = strtol(line + strlen("MemAvailable:"), NULL, 10); } if (BEGINS_WITH(line, "Buffers:")) { - buffers = strtol(line + strlen("Buffers:"), NULL, 10); + ram_buffers = strtol(line + strlen("Buffers:"), NULL, 10); } if (BEGINS_WITH(line, "Cached:")) { - cached = strtol(line + strlen("Cached:"), NULL, 10); + ram_cached = strtol(line + strlen("Cached:"), NULL, 10); } if (BEGINS_WITH(line, "Shmem:")) { - sharedRam = strtol(line + strlen("Shmem:"), NULL, 10); + ram_shared = strtol(line + strlen("Shmem:"), NULL, 10); } - if (totalRam != -1 && freeRam != -1 && availableRam != -1 && buffers != -1 && cached != -1 && sharedRam != -1) { + if (ram_total != -1 && ram_free != -1 && ram_available != -1 && ram_buffers != -1 && ram_cached != -1 && ram_shared != -1) { break; } } fclose(file); - if (totalRam == -1 || freeRam == -1 || availableRam == -1 || buffers == -1 || cached == -1 || sharedRam == -1) { + if (ram_total == -1 || ram_free == -1 || ram_available == -1 || ram_buffers == -1 || ram_cached == -1 || ram_shared == -1) { goto error; } - totalRam = totalRam * BINARY_BASE; - freeRam = freeRam * BINARY_BASE; - availableRam = availableRam * BINARY_BASE; - buffers = buffers * BINARY_BASE; - cached = cached * BINARY_BASE; - sharedRam = sharedRam * BINARY_BASE; + ram_total = ram_total * BINARY_BASE; + ram_free = ram_free * BINARY_BASE; + ram_available = ram_available * BINARY_BASE; + ram_buffers = ram_buffers * BINARY_BASE; + ram_cached = ram_cached * BINARY_BASE; + ram_shared = ram_shared * BINARY_BASE; if (use_available_memory) { - usedRam = totalRam - availableRam; + ram_used = ram_total - ram_available; } else { - usedRam = totalRam - freeRam - buffers - cached; + ram_used = ram_total - ram_free - ram_buffers - ram_cached; } - if (degraded_low_threshold > 0 && below_threshold(totalRam, usedRam, degraded_threshold_type, degraded_low_threshold)) { - if (critical_low_threshold > 0 && below_threshold(totalRam, usedRam, critical_threshold_type, critical_low_threshold)) { + if (degraded_low_threshold > 0 && below_threshold(ram_total, ram_used, degraded_threshold_type, degraded_low_threshold)) { + if (critical_low_threshold > 0 && below_threshold(ram_total, ram_used, critical_threshold_type, critical_low_threshold)) { START_COLOR("color_bad"); colorful_output = true; if (critical_format_below_threshold != NULL) @@ -147,47 +147,47 @@ void print_memory(yajl_gen json_gen, char *buffer, const char *format, const cha continue; } if (BEGINS_WITH(walk + 1, "total")) { - outwalk += print_bytes_human(outwalk, totalRam); + outwalk += print_bytes_human(outwalk, ram_total); walk += strlen("total"); } if (BEGINS_WITH(walk + 1, "used")) { - outwalk += print_bytes_human(outwalk, usedRam); + outwalk += print_bytes_human(outwalk, ram_used); walk += strlen("used"); } if (BEGINS_WITH(walk + 1, "free")) { - outwalk += print_bytes_human(outwalk, freeRam); + outwalk += print_bytes_human(outwalk, ram_free); walk += strlen("free"); } if (BEGINS_WITH(walk + 1, "available")) { - outwalk += print_bytes_human(outwalk, availableRam); + outwalk += print_bytes_human(outwalk, ram_available); walk += strlen("available"); } if (BEGINS_WITH(walk + 1, "shared")) { - outwalk += print_bytes_human(outwalk, sharedRam); + outwalk += print_bytes_human(outwalk, ram_shared); walk += strlen("shared"); } if (BEGINS_WITH(walk + 1, "percentage_free")) { - outwalk += sprintf(outwalk, "%.01f%s", 100.0 * freeRam / totalRam, pct_mark); + outwalk += sprintf(outwalk, "%.01f%s", 100.0 * ram_free / ram_total, pct_mark); walk += strlen("percentage_free"); } if (BEGINS_WITH(walk + 1, "percentage_available")) { - outwalk += sprintf(outwalk, "%.01f%s", 100.0 * availableRam / totalRam, pct_mark); + outwalk += sprintf(outwalk, "%.01f%s", 100.0 * ram_available / ram_total, pct_mark); walk += strlen("percentage_available"); } if (BEGINS_WITH(walk + 1, "percentage_used")) { - outwalk += sprintf(outwalk, "%.01f%s", 100.0 * usedRam / totalRam, pct_mark); + outwalk += sprintf(outwalk, "%.01f%s", 100.0 * ram_used / ram_total, pct_mark); walk += strlen("percentage_used"); } if (BEGINS_WITH(walk + 1, "percentage_shared")) { - outwalk += sprintf(outwalk, "%.01f%s", 100.0 * sharedRam / totalRam, pct_mark); + outwalk += sprintf(outwalk, "%.01f%s", 100.0 * ram_shared / ram_total, pct_mark); walk += strlen("percentage_shared"); } } @@ -203,6 +203,7 @@ error: OUTPUT_FULL_TEXT("can't read memory"); fputs("i3status: Cannot read system memory using /proc/meminfo\n", stderr); #else + OUTPUT_FULL_TEXT(""); fputs("i3status: Memory status information is not supported on this system\n", stderr); #endif } -- cgit v1.2.3 From cba8f559384008f187e7388186b9885343be0678 Mon Sep 17 00:00:00 2001 From: Benedikt Heine Date: Mon, 16 Apr 2018 18:18:50 +0200 Subject: Simplify the memory thresholds --- i3status.c | 13 ++++---- i3status.conf | 7 +++++ include/i3status.h | 2 +- man/i3status.man | 63 +++++++++++++++++++------------------- src/print_mem.c | 88 ++++++++++++++++++++++++++++++++---------------------- 5 files changed, 96 insertions(+), 77 deletions(-) (limited to 'src') diff --git a/i3status.c b/i3status.c index 6232808..6461d6b 100644 --- a/i3status.c +++ b/i3status.c @@ -423,13 +423,10 @@ int main(int argc, char *argv[]) { cfg_opt_t memory_opts[] = { CFG_STR("format", "%used %free %available", CFGF_NONE), - CFG_STR("degraded_format_below_threshold", NULL, CFGF_NONE), - CFG_STR("degraded_threshold_type", "percentage_avail", CFGF_NONE), - CFG_FLOAT("degraded_low_threshold", 0, CFGF_NONE), - CFG_STR("critical_format_below_threshold", NULL, CFGF_NONE), - CFG_STR("critical_threshold_type", "percentage_avail", CFGF_NONE), - CFG_FLOAT("critical_low_threshold", 0, CFGF_NONE), - CFG_BOOL("use_available_memory", true, CFGF_NONE), + CFG_STR("format_degraded", NULL, CFGF_NONE), + CFG_STR("threshold_degraded", NULL, CFGF_NONE), + CFG_STR("threshold_critical", NULL, CFGF_NONE), + CFG_STR("memory_used_method", "classical", CFGF_NONE), CFG_CUSTOM_ALIGN_OPT, CFG_CUSTOM_COLOR_OPTS, CFG_CUSTOM_MIN_WIDTH_OPT, @@ -743,7 +740,7 @@ int main(int argc, char *argv[]) { CASE_SEC("memory") { SEC_OPEN_MAP("memory"); - print_memory(json_gen, buffer, cfg_getstr(sec, "format"), cfg_getstr(sec, "degraded_format_below_threshold"), cfg_getstr(sec, "degraded_threshold_type"), cfg_getfloat(sec, "degraded_low_threshold"), cfg_getstr(sec, "critical_format_below_threshold"), cfg_getstr(sec, "critical_threshold_type"), cfg_getfloat(sec, "critical_low_threshold"), cfg_getbool(sec, "use_available_memory")); + print_memory(json_gen, buffer, cfg_getstr(sec, "format"), cfg_getstr(sec, "format_degraded"), cfg_getstr(sec, "threshold_degraded"), cfg_getstr(sec, "threshold_critical"), cfg_getstr(sec, "memory_used_method")); SEC_CLOSE_MAP; } diff --git a/i3status.conf b/i3status.conf index 7f37964..07ffb74 100644 --- a/i3status.conf +++ b/i3status.conf @@ -17,6 +17,7 @@ order += "wireless _first_" order += "ethernet _first_" order += "battery all" order += "load" +order += "memory" order += "tztime local" wireless _first_ { @@ -42,6 +43,12 @@ load { format = "%1min" } +memory { + format = "%used | %available" + threshold_degraded = "1G" + format_degraded = "MEMORY < %available" +} + disk "/" { format = "%avail" } diff --git a/include/i3status.h b/include/i3status.h index 2aa4317..fe9206e 100644 --- a/include/i3status.h +++ b/include/i3status.h @@ -223,7 +223,7 @@ void print_cpu_temperature_info(yajl_gen json_gen, char *buffer, int zone, const 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_memory(yajl_gen json_gen, char *buffer, const char *format, const char *degraded_format_below_threshold, const char *degraded_threshold_type, const float degraded_low_threshold, const char *critical_format_below_threshold, const char *critical_threshold_type, const float critical_low_threshold, const bool use_available_memory); +void print_memory(yajl_gen json_gen, char *buffer, const char *format, const char *format_degraded, const char *threshold_degraded, const char *threshold_critical, const char *memory_used_method); 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); bool process_runs(const char *path); int volume_pulseaudio(uint32_t sink_idx, const char *sink_name); diff --git a/man/i3status.man b/man/i3status.man index ec02ce1..f8ce219 100644 --- a/man/i3status.man +++ b/man/i3status.man @@ -116,6 +116,8 @@ cpu_temperature 0 { memory { format = "%used" + threshold_degraded = "10%" + format_degraded = "MEMORY: %free" } disk "/" { @@ -197,6 +199,7 @@ double-quote (""") characters need to be replaced with "`&`", "`<`", for generated content (e.g. wireless ESSID, time). *Example configuration*: + ------------------------------------------------------------- general { output_format = "xmobar" @@ -431,46 +434,42 @@ starting from %cpu0. This feature is currently not supported in FreeBSD. === Memory -Gets the memory usage from system. -On Linux, the information is taken from +/proc/meminfo+. - -These values can also be expressed in percentages with the +percentage_used+, -+percentage_free+ and +percentage_shared+ formats. - -If a +critical_low_threshold+ is defined, the output will be colored using -+color_bad+. The unit of this threshold is defined by the unit given in -+critical_threshold_type+, which can be one of "bytes_free", "bytes_avail", -"percentage_free" and "percentage_avail". Additionally, the former two can be -prefixed with one of "k", "m", "g" or "t" to change the exact unit. -For example, setting critical_low_threshold to 2 and threshold_type to "gbytes_avail" -causes available memory below 2 GiB to be colored with +color_bad+. The -defaults are "percentage_avail" with a threshold of 0. -Furthermore, the format used when the threshold is reached can be customized -using the option +critical_format_below_threshold+. -Same applies to +degraded_low_threshold+, +degraded_threshold_type+ and -+degraded_format_below_threshold+ using +color_degraded+. - -The most common one is: -"used memory" = "total memory" - "free memory" - "buffers" - "cache" -This is the default in i3status. Some other programs use -"used memory" = "total memory" - "available memory" -You can disable this behavior using +use_available_memory+. +Gets the memory usage from system on a Linux system from +/proc/meminfo+. Other +systems are currently not supported. -*Example order*: +memory+ +As format placeholders, +total+, +used+, +free+, +available+ and +shared+ are +available. These will print human readable values. It's also possible to prefix +the placeholders with +percentage_+ to get a value in percent. + +It's possible to define a +threshold_degraded+ and a +threshold_critical+ to +color the status bar output in yellow or red, if the available memory falls +below the given threshold. Possible values of the threshold can be any integer, +suffixed with an iec symbol (+T+, +G+, +M+, +K+). Alternatively, the integer +can be suffixed by a percent sign, which then rets evaluated relatively to +total memory. + +If the +format_degraded+ parameter is given and either the critical or the +degraded threshold applies, +format_degraded+ will get used as format string. +It acts equivalently to +format+. -*Example format*: +%free %available (%used)/ %total+ +As Linux' meminfo doesn't expose the overall memory in use, there are multiple +methods to distinguish the actually used memory. -*Example format*: +used %percentage_used , free %percentage_free, shared %percentage_shared+ +*Example used_memory_method*: +memavailable+ ("total memory" - "MemAvailable", matches gnome system monitor) + +*Example used_memory_method*: +classical+ ("total memory" - "free" - "buffers" - "cache", matches gnome system monitor) + +*Example order*: +memory+ -*Example degraded_low_threshold*: +10+ +*Example format*: +%free %available (%used) / %total+ -*Example degraded_threshold_type*: +percentage_free+ +*Example format*: +%percentage_used used, %percentage_free free, %percentage_shared shared+ -*Example critical_low_threshold*: +5+ +*Example threshold_degraded*: +10%+ -*Example critical_format_below_threshold*: +Warning: %percentage_free+ +*Example threshold_critical*: +5%+ -*Example use_available_memory: +false+ +*Example format_degraded*: +Memory LOW: %free+ === Load diff --git a/src/print_mem.c b/src/print_mem.c index fe93d0b..46523d6 100644 --- a/src/print_mem.c +++ b/src/print_mem.c @@ -29,49 +29,57 @@ static int print_bytes_human(char *outwalk, uint64_t bytes) { } /* - * Determines whether remaining bytes are below given threshold. + * Convert a string to its absolute representation based on the total + * memory of `mem_total`. + * + * The string can contain any percentage values, which then return a + * the value of `size` in relation to `mem_total`. + * Alternatively an absolute value can be given, suffixed with an iec + * symbol. * */ -static bool below_threshold(const long ram_total, const long ram_used, const char *threshold_type, const long low_threshold) { - // empty is available or free, based on "use_available_memory" - long empty = ram_total - ram_used; - if (BEGINS_WITH(threshold_type, "percentage_")) { - return 100.0 * empty / ram_total < low_threshold; - } else if (strcasecmp(threshold_type, "bytes_free") == 0) { - return empty < low_threshold; - } else if (threshold_type[0] != '\0' && strncasecmp(threshold_type + 1, "bytes_", strlen("bytes_")) == 0) { - - long factor = 1; - - switch (threshold_type[0]) { +static long memory_absolute(const long mem_total, const char *size) { + long mem_absolute = -1; + char *endptr = NULL; + + mem_absolute = strtol(size, &endptr, 10); + + if (endptr) { + while (endptr[0] != '\0' && isspace(endptr[0])) + endptr++; + + switch (endptr[0]) { case 'T': case 't': - factor *= BINARY_BASE; + mem_absolute *= BINARY_BASE; case 'G': case 'g': - factor *= BINARY_BASE; + mem_absolute *= BINARY_BASE; case 'M': case 'm': - factor *= BINARY_BASE; + mem_absolute *= BINARY_BASE; case 'K': case 'k': - factor *= BINARY_BASE; + mem_absolute *= BINARY_BASE; + break; + case '%': + mem_absolute = mem_total * mem_absolute / 100; break; default: - return false; + break; } - return empty < low_threshold * factor; } - return false; + + return mem_absolute; } -void print_memory(yajl_gen json_gen, char *buffer, const char *format, const char *degraded_format_below_threshold, const char *degraded_threshold_type, const float degraded_low_threshold, const char *critical_format_below_threshold, const char *critical_threshold_type, const float critical_low_threshold, const bool use_available_memory) { +void print_memory(yajl_gen json_gen, char *buffer, const char *format, const char *format_degraded, const char *threshold_degraded, const char *threshold_critical, const char *memory_used_method) { char *outwalk = buffer; #if defined(linux) const char *selected_format = format; const char *walk; - bool colorful_output = false; + const char *output_color = NULL; long ram_total = -1; long ram_free = -1; @@ -121,26 +129,34 @@ void print_memory(yajl_gen json_gen, char *buffer, const char *format, const cha ram_buffers = ram_buffers * BINARY_BASE; ram_cached = ram_cached * BINARY_BASE; ram_shared = ram_shared * BINARY_BASE; - if (use_available_memory) { + + if (BEGINS_WITH(memory_used_method, "memavailable")) { ram_used = ram_total - ram_available; - } else { + } else if (BEGINS_WITH(memory_used_method, "classical")) { ram_used = ram_total - ram_free - ram_buffers - ram_cached; } - if (degraded_low_threshold > 0 && below_threshold(ram_total, ram_used, degraded_threshold_type, degraded_low_threshold)) { - if (critical_low_threshold > 0 && below_threshold(ram_total, ram_used, critical_threshold_type, critical_low_threshold)) { - START_COLOR("color_bad"); - colorful_output = true; - if (critical_format_below_threshold != NULL) - selected_format = critical_format_below_threshold; - } else { - START_COLOR("color_degraded"); - colorful_output = true; - if (degraded_format_below_threshold != NULL) - selected_format = degraded_format_below_threshold; + if (threshold_degraded) { + long abs = memory_absolute(ram_total, threshold_degraded); + if (ram_available < abs) { + output_color = "color_degraded"; + } + } + + if (threshold_critical) { + long abs = memory_absolute(ram_total, threshold_critical); + if (ram_available < abs) { + output_color = "color_bad"; } } + if (output_color) { + START_COLOR(output_color); + + if (format_degraded) + selected_format = format_degraded; + } + for (walk = selected_format; *walk != '\0'; walk++) { if (*walk != '%') { *(outwalk++) = *walk; @@ -192,7 +208,7 @@ void print_memory(yajl_gen json_gen, char *buffer, const char *format, const cha } } - if (colorful_output) + if (output_color) END_COLOR; *outwalk = '\0'; -- cgit v1.2.3