slstatus-diskio-4bd78c9.patch (5402B)
1 Author: K. Eugene Carlson <kvngncrlsn@gmail.com> 2 Date: Fri Sep 3 01:09:02 2021 +0900 3 4 Get disk IO stats on Linux (read, write, %) 5 6 This patch lets slstatus report on disk IO on Linux systems: reads 7 from disk, writes to disk and IO percentage. 8 9 diff --git a/Makefile b/Makefile 10 index 3be46cc..1ecc8db 100644 11 --- a/Makefile 12 +++ b/Makefile 13 @@ -12,6 +12,7 @@ COM =\ 14 components/disk\ 15 components/entropy\ 16 components/hostname\ 17 + components/iocheck\ 18 components/ip\ 19 components/kernel_release\ 20 components/keyboard_indicators\ 21 diff --git a/README b/README 22 index 4da0756..1a64914 100644 23 --- a/README 24 +++ b/README 25 @@ -15,6 +15,7 @@ Features 26 - Available entropy 27 - Username/GID/UID 28 - Hostname 29 +- Disk IO (read, write and percentage) (Linux only) 30 - IP address (IPv4 and IPv6) 31 - Kernel version 32 - Keyboard indicators 33 diff --git a/components/iocheck.c b/components/iocheck.c 34 new file mode 100644 35 index 0000000..7fa102d 36 --- /dev/null 37 +++ b/components/iocheck.c 38 @@ -0,0 +1,170 @@ 39 +/* See LICENSE file for copyright and license details. */ 40 +#include <stdio.h> 41 +#include <string.h> 42 +#include <stdint.h> 43 +#include <stdlib.h> 44 +#include <dirent.h> 45 +#include <unistd.h> 46 + 47 +#include "../util.h" 48 + 49 +#if defined(__linux__) 50 + static int 51 + get_io(uintmax_t *s_in, uintmax_t *s_out) 52 + { 53 + FILE *fp; 54 + struct { 55 + const char *name; 56 + const size_t len; 57 + uintmax_t *var; 58 + } ent[] = { 59 + { "pgpgin", sizeof("pgpgin") - 1, s_in }, 60 + { "pgpgout", sizeof("pgpgout") - 1, s_out }, 61 + }; 62 + size_t line_len = 0, i, left; 63 + char *line = NULL; 64 + 65 + /* get number of fields we want to extract */ 66 + for (i = 0, left = 0; i < LEN(ent); i++) { 67 + if (ent[i].var) { 68 + left++; 69 + } 70 + } 71 + 72 + if (!(fp = fopen("/proc/vmstat", "r"))) { 73 + warn("fopen '/proc/vmstat':"); 74 + return 1; 75 + } 76 + 77 + /* read file line by line and extract field information */ 78 + while (left > 0 && getline(&line, &line_len, fp) >= 0) { 79 + for (i = 0; i < LEN(ent); i++) { 80 + if (ent[i].var && 81 + !strncmp(line,ent[i].name, ent[i].len)) { 82 + sscanf(line + ent[i].len + 1, 83 + "%ju\n", ent[i].var); 84 + left--; 85 + break; 86 + } 87 + } 88 + } 89 + free(line); 90 + if(ferror(fp)) { 91 + warn("getline '/proc/vmstat':"); 92 + return 1; 93 + } 94 + 95 + fclose(fp); 96 + return 0; 97 + } 98 + 99 + const char * 100 + io_in(void) 101 + { 102 + uintmax_t oldin; 103 + static uintmax_t newin; 104 + 105 + oldin = newin; 106 + 107 + if (get_io(&newin, NULL)) { 108 + return NULL; 109 + } 110 + if (oldin == 0) { 111 + return NULL; 112 + } 113 + 114 + return fmt_human((newin-oldin) * 1024, 1024); 115 + } 116 + 117 + const char * 118 + io_out(void) 119 + { 120 + uintmax_t oldout; 121 + static uintmax_t newout; 122 + 123 + oldout = newout; 124 + 125 + if (get_io(NULL, &newout)) { 126 + return NULL; 127 + } 128 + if (oldout == 0) { 129 + return NULL; 130 + } 131 + 132 + return fmt_human((newout - oldout) * 1024, 1024); 133 + } 134 + 135 + const char * 136 + io_perc(void) 137 + { 138 + struct dirent *dp; 139 + DIR *bd; 140 + uintmax_t oldwait; 141 + static uintmax_t newwait; 142 + extern const unsigned int interval; 143 + 144 + oldwait = newwait; 145 + 146 + if (!(bd = opendir("/sys/block"))) { 147 + warn("opendir '%s':", "/sys/block"); 148 + return NULL; 149 + } 150 + 151 + newwait = 0; 152 + /* get IO wait stats from the /sys/block directories */ 153 + while ((dp = readdir(bd))) { 154 + if (strstr(dp->d_name, "loop") || 155 + strstr(dp->d_name, "ram")) { 156 + continue; 157 + } 158 + if (!strcmp(dp->d_name, ".") || 159 + !strcmp(dp->d_name, "..")) { 160 + continue; 161 + } 162 + /* virtual devices don't count */ 163 + char virtpath[50]; 164 + strcpy(virtpath, "/sys/devices/virtual/block/"); 165 + strcat(virtpath, dp->d_name); 166 + if (access(virtpath, R_OK) == 0) { 167 + continue; 168 + } 169 + char statpath[34]; 170 + strcpy(statpath, "/sys/block/"); 171 + strcat(statpath, dp->d_name); 172 + strcat(statpath, "/stat"); 173 + uintmax_t partwait; 174 + if (pscanf(statpath, 175 + "%*d %*d %*d %*d %*d %*d %*d %*d %*d %ju %*d", 176 + &partwait) != 1) { 177 + continue; 178 + } 179 + newwait += partwait; 180 + } 181 + closedir(bd); 182 + if (oldwait == 0 || newwait < oldwait) { 183 + return NULL; 184 + } 185 + 186 + return bprintf("%0.1f", 100 * 187 + (newwait - oldwait) / (float)interval); 188 + } 189 + 190 +#else 191 + const char * 192 + io_in(void) 193 + { 194 + return NULL; 195 + } 196 + 197 + const char * 198 + io_out(void) 199 + { 200 + return NULL; 201 + } 202 + 203 + const char * 204 + io_perc(void) 205 + { 206 + return NULL; 207 + } 208 +#endif 209 diff --git a/config.def.h b/config.def.h 210 index 5f6c114..4d49881 100644 211 --- a/config.def.h 212 +++ b/config.def.h 213 @@ -28,6 +28,9 @@ static const char unknown_str[] = "n/a"; 214 * entropy available entropy NULL 215 * gid GID of current user NULL 216 * hostname hostname NULL 217 + * io_in disk IO (read) NULL 218 + * io_out disk IO (write) NULL 219 + * io_perc disk IO (percentage) NULL 220 * ipv4 IPv4 address interface name (eth0) 221 * ipv6 IPv6 address interface name (eth0) 222 * kernel_release `uname -r` NULL 223 diff --git a/slstatus.h b/slstatus.h 224 index f3b4979..8b14b75 100644 225 --- a/slstatus.h 226 +++ b/slstatus.h 227 @@ -24,6 +24,11 @@ const char *entropy(const char *unused); 228 /* hostname */ 229 const char *hostname(const char *unused); 230 231 +/* iocheck */ 232 +const char *io_in(void); 233 +const char *io_out(void); 234 +const char *io_perc(void); 235 + 236 /* ip */ 237 const char *ipv4(const char *interface); 238 const char *ipv6(const char *interface);