Author: K. Eugene Carlson Date: Fri Sep 3 01:09:02 2021 +0900 Get disk IO stats on Linux (read, write, %) This patch lets slstatus report on disk IO on Linux systems: reads from disk, writes to disk and IO percentage. diff --git a/Makefile b/Makefile index 3be46cc..1ecc8db 100644 --- a/Makefile +++ b/Makefile @@ -12,6 +12,7 @@ COM =\ components/disk\ components/entropy\ components/hostname\ + components/iocheck\ components/ip\ components/kernel_release\ components/keyboard_indicators\ diff --git a/README b/README index 4da0756..1a64914 100644 --- a/README +++ b/README @@ -15,6 +15,7 @@ Features - Available entropy - Username/GID/UID - Hostname +- Disk IO (read, write and percentage) (Linux only) - IP address (IPv4 and IPv6) - Kernel version - Keyboard indicators diff --git a/components/iocheck.c b/components/iocheck.c new file mode 100644 index 0000000..7fa102d --- /dev/null +++ b/components/iocheck.c @@ -0,0 +1,170 @@ +/* See LICENSE file for copyright and license details. */ +#include +#include +#include +#include +#include +#include + +#include "../util.h" + +#if defined(__linux__) + static int + get_io(uintmax_t *s_in, uintmax_t *s_out) + { + FILE *fp; + struct { + const char *name; + const size_t len; + uintmax_t *var; + } ent[] = { + { "pgpgin", sizeof("pgpgin") - 1, s_in }, + { "pgpgout", sizeof("pgpgout") - 1, s_out }, + }; + size_t line_len = 0, i, left; + char *line = NULL; + + /* get number of fields we want to extract */ + for (i = 0, left = 0; i < LEN(ent); i++) { + if (ent[i].var) { + left++; + } + } + + if (!(fp = fopen("/proc/vmstat", "r"))) { + warn("fopen '/proc/vmstat':"); + return 1; + } + + /* read file line by line and extract field information */ + while (left > 0 && getline(&line, &line_len, fp) >= 0) { + for (i = 0; i < LEN(ent); i++) { + if (ent[i].var && + !strncmp(line,ent[i].name, ent[i].len)) { + sscanf(line + ent[i].len + 1, + "%ju\n", ent[i].var); + left--; + break; + } + } + } + free(line); + if(ferror(fp)) { + warn("getline '/proc/vmstat':"); + return 1; + } + + fclose(fp); + return 0; + } + + const char * + io_in(void) + { + uintmax_t oldin; + static uintmax_t newin; + + oldin = newin; + + if (get_io(&newin, NULL)) { + return NULL; + } + if (oldin == 0) { + return NULL; + } + + return fmt_human((newin-oldin) * 1024, 1024); + } + + const char * + io_out(void) + { + uintmax_t oldout; + static uintmax_t newout; + + oldout = newout; + + if (get_io(NULL, &newout)) { + return NULL; + } + if (oldout == 0) { + return NULL; + } + + return fmt_human((newout - oldout) * 1024, 1024); + } + + const char * + io_perc(void) + { + struct dirent *dp; + DIR *bd; + uintmax_t oldwait; + static uintmax_t newwait; + extern const unsigned int interval; + + oldwait = newwait; + + if (!(bd = opendir("/sys/block"))) { + warn("opendir '%s':", "/sys/block"); + return NULL; + } + + newwait = 0; + /* get IO wait stats from the /sys/block directories */ + while ((dp = readdir(bd))) { + if (strstr(dp->d_name, "loop") || + strstr(dp->d_name, "ram")) { + continue; + } + if (!strcmp(dp->d_name, ".") || + !strcmp(dp->d_name, "..")) { + continue; + } + /* virtual devices don't count */ + char virtpath[50]; + strcpy(virtpath, "/sys/devices/virtual/block/"); + strcat(virtpath, dp->d_name); + if (access(virtpath, R_OK) == 0) { + continue; + } + char statpath[34]; + strcpy(statpath, "/sys/block/"); + strcat(statpath, dp->d_name); + strcat(statpath, "/stat"); + uintmax_t partwait; + if (pscanf(statpath, + "%*d %*d %*d %*d %*d %*d %*d %*d %*d %ju %*d", + &partwait) != 1) { + continue; + } + newwait += partwait; + } + closedir(bd); + if (oldwait == 0 || newwait < oldwait) { + return NULL; + } + + return bprintf("%0.1f", 100 * + (newwait - oldwait) / (float)interval); + } + +#else + const char * + io_in(void) + { + return NULL; + } + + const char * + io_out(void) + { + return NULL; + } + + const char * + io_perc(void) + { + return NULL; + } +#endif diff --git a/config.def.h b/config.def.h index 5f6c114..4d49881 100644 --- a/config.def.h +++ b/config.def.h @@ -28,6 +28,9 @@ static const char unknown_str[] = "n/a"; * entropy available entropy NULL * gid GID of current user NULL * hostname hostname NULL + * io_in disk IO (read) NULL + * io_out disk IO (write) NULL + * io_perc disk IO (percentage) NULL * ipv4 IPv4 address interface name (eth0) * ipv6 IPv6 address interface name (eth0) * kernel_release `uname -r` NULL diff --git a/slstatus.h b/slstatus.h index f3b4979..8b14b75 100644 --- a/slstatus.h +++ b/slstatus.h @@ -24,6 +24,11 @@ const char *entropy(const char *unused); /* hostname */ const char *hostname(const char *unused); +/* iocheck */ +const char *io_in(void); +const char *io_out(void); +const char *io_perc(void); + /* ip */ const char *ipv4(const char *interface); const char *ipv6(const char *interface);