10f66f451Sopenharmony_ci/* vmstat.c - Report virtual memory statistics. 20f66f451Sopenharmony_ci * 30f66f451Sopenharmony_ci * Copyright 2012 Elie De Brauwer <eliedebrauwer@gmail.com> 40f66f451Sopenharmony_ci * 50f66f451Sopenharmony_ci * TODO: I have no idea how "system" category is calculated. 60f66f451Sopenharmony_ci * whatever we're doing isn't matching what other implementations are doing. 70f66f451Sopenharmony_ci 80f66f451Sopenharmony_ciUSE_VMSTAT(NEWTOY(vmstat, ">2n", TOYFLAG_BIN)) 90f66f451Sopenharmony_ci 100f66f451Sopenharmony_ciconfig VMSTAT 110f66f451Sopenharmony_ci bool "vmstat" 120f66f451Sopenharmony_ci default y 130f66f451Sopenharmony_ci help 140f66f451Sopenharmony_ci usage: vmstat [-n] [DELAY [COUNT]] 150f66f451Sopenharmony_ci 160f66f451Sopenharmony_ci Print virtual memory statistics, repeating each DELAY seconds, COUNT times. 170f66f451Sopenharmony_ci (With no DELAY, prints one line. With no COUNT, repeats until killed.) 180f66f451Sopenharmony_ci 190f66f451Sopenharmony_ci Show processes running and blocked, kilobytes swapped, free, buffered, and 200f66f451Sopenharmony_ci cached, kilobytes swapped in and out per second, file disk blocks input and 210f66f451Sopenharmony_ci output per second, interrupts and context switches per second, percent 220f66f451Sopenharmony_ci of CPU time spent running user code, system code, idle, and awaiting I/O. 230f66f451Sopenharmony_ci First line is since system started, later lines are since last line. 240f66f451Sopenharmony_ci 250f66f451Sopenharmony_ci -n Display the header only once 260f66f451Sopenharmony_ci*/ 270f66f451Sopenharmony_ci 280f66f451Sopenharmony_ci#define FOR_vmstat 290f66f451Sopenharmony_ci#include "toys.h" 300f66f451Sopenharmony_ci 310f66f451Sopenharmony_cistruct vmstat_proc { 320f66f451Sopenharmony_ci // From /proc/stat (jiffies) 330f66f451Sopenharmony_ci uint64_t user, nice, sys, idle, wait, irq, sirq, intr, ctxt, running, blocked; 340f66f451Sopenharmony_ci // From /proc/meminfo (units are kb) 350f66f451Sopenharmony_ci uint64_t memfree, buffers, cached, swapfree, swaptotal; 360f66f451Sopenharmony_ci // From /proc/vmstat (units are kb) 370f66f451Sopenharmony_ci uint64_t io_in, io_out; 380f66f451Sopenharmony_ci // From /proc/vmstat (units are pages) 390f66f451Sopenharmony_ci uint64_t swap_in, swap_out; 400f66f451Sopenharmony_ci}; 410f66f451Sopenharmony_ci 420f66f451Sopenharmony_ci// All the elements of vmstat_proc are the same size, so we can populate it as 430f66f451Sopenharmony_ci// a big array, then read the elements back out by name 440f66f451Sopenharmony_cistatic void get_vmstat_proc(struct vmstat_proc *vmstat_proc) 450f66f451Sopenharmony_ci{ 460f66f451Sopenharmony_ci char *vmstuff[] = { "/proc/stat", "cpu ", 0, 0, 0, 0, 0, 0, 470f66f451Sopenharmony_ci "intr ", "ctxt ", "procs_running ", "procs_blocked ", "/proc/meminfo", 480f66f451Sopenharmony_ci "MemFree: ", "Buffers: ", "Cached: ", "SwapFree: ", "SwapTotal: ", 490f66f451Sopenharmony_ci "/proc/vmstat", "pgpgin ", "pgpgout ", "pswpin ", "pswpout " }; 500f66f451Sopenharmony_ci uint64_t *new = (uint64_t *)vmstat_proc; 510f66f451Sopenharmony_ci char *p = p, *name = name, *file = NULL; 520f66f451Sopenharmony_ci int i, j; 530f66f451Sopenharmony_ci 540f66f451Sopenharmony_ci // We use vmstuff to fill out vmstat_proc as an array of uint64_t: 550f66f451Sopenharmony_ci // Strings starting with / are the file to find next entries in 560f66f451Sopenharmony_ci // Any other string is a key to search for, with decimal value right after 570f66f451Sopenharmony_ci // 0 means parse another value on same line as last key 580f66f451Sopenharmony_ci 590f66f451Sopenharmony_ci for (i = 0; i<ARRAY_LEN(vmstuff); i++) { 600f66f451Sopenharmony_ci if (!vmstuff[i]) p++; 610f66f451Sopenharmony_ci else if (*vmstuff[i] == '/') { 620f66f451Sopenharmony_ci // /proc/stat for a 48-core machine doesn't fit in toybuf. 630f66f451Sopenharmony_ci free(file); 640f66f451Sopenharmony_ci file = xreadfile(name = vmstuff[i], 0, 0); 650f66f451Sopenharmony_ci 660f66f451Sopenharmony_ci continue; 670f66f451Sopenharmony_ci } else p = strafter(file, vmstuff[i]); 680f66f451Sopenharmony_ci if (!p || 1!=sscanf(p, "%"PRIu64"%n", new++, &j)) 690f66f451Sopenharmony_ci error_exit("Bad %sin %s: %s", vmstuff[i], name, p ? p : ""); 700f66f451Sopenharmony_ci p += j; 710f66f451Sopenharmony_ci } 720f66f451Sopenharmony_ci free(file); 730f66f451Sopenharmony_ci} 740f66f451Sopenharmony_ci 750f66f451Sopenharmony_civoid vmstat_main(void) 760f66f451Sopenharmony_ci{ 770f66f451Sopenharmony_ci struct vmstat_proc top[2]; 780f66f451Sopenharmony_ci int i, loop_delay = 0, loop_max = 0; 790f66f451Sopenharmony_ci unsigned loop, rows = 25, page_kb = sysconf(_SC_PAGESIZE)/1024; 800f66f451Sopenharmony_ci char *headers="r\0b\0swpd\0free\0buff\0cache\0si\0so\0bi\0bo\0in\0cs\0us\0" 810f66f451Sopenharmony_ci "sy\0id\0wa", lengths[] = {2,2,7,7,6,7,5,5,5,5,5,5,2,2,2,2}; 820f66f451Sopenharmony_ci 830f66f451Sopenharmony_ci memset(top, 0, sizeof(top)); 840f66f451Sopenharmony_ci if (toys.optc) loop_delay = atolx_range(toys.optargs[0], 0, INT_MAX); 850f66f451Sopenharmony_ci if (toys.optc > 1) loop_max = atolx_range(toys.optargs[1], 1, INT_MAX); 860f66f451Sopenharmony_ci 870f66f451Sopenharmony_ci for (loop = 0; !loop_max || loop < loop_max; loop++) { 880f66f451Sopenharmony_ci unsigned idx = loop&1, offset = 0, expected = 0; 890f66f451Sopenharmony_ci uint64_t units, total_hz, *ptr = (uint64_t *)(top+idx), 900f66f451Sopenharmony_ci *oldptr = (uint64_t *)(top+!idx); 910f66f451Sopenharmony_ci 920f66f451Sopenharmony_ci if (loop && loop_delay) sleep(loop_delay); 930f66f451Sopenharmony_ci 940f66f451Sopenharmony_ci // Print headers 950f66f451Sopenharmony_ci if (rows>3 && !(loop % (rows-3))) { 960f66f451Sopenharmony_ci char *header = headers; 970f66f451Sopenharmony_ci 980f66f451Sopenharmony_ci if (!(toys.optflags&FLAG_n) && isatty(1)) terminal_size(0, &rows); 990f66f451Sopenharmony_ci else rows = 0; 1000f66f451Sopenharmony_ci 1010f66f451Sopenharmony_ci printf("procs ------------memory------------ ----swap--- -----io---- ---system-- ----cpu----\n"); 1020f66f451Sopenharmony_ci for (i=0; i<sizeof(lengths); i++) { 1030f66f451Sopenharmony_ci printf(" %*s"+!i, lengths[i], header); 1040f66f451Sopenharmony_ci header += strlen(header)+1; 1050f66f451Sopenharmony_ci } 1060f66f451Sopenharmony_ci xputc('\n'); 1070f66f451Sopenharmony_ci } 1080f66f451Sopenharmony_ci 1090f66f451Sopenharmony_ci // Read data and combine some fields we display as aggregates 1100f66f451Sopenharmony_ci get_vmstat_proc(top+idx); 1110f66f451Sopenharmony_ci top[idx].running--; // Don't include ourselves 1120f66f451Sopenharmony_ci top[idx].user += top[idx].nice; 1130f66f451Sopenharmony_ci top[idx].sys += top[idx].irq + top[idx].sirq; 1140f66f451Sopenharmony_ci top[idx].swaptotal -= top[idx].swapfree; 1150f66f451Sopenharmony_ci 1160f66f451Sopenharmony_ci // Collect unit adjustments (outside the inner loop to save time) 1170f66f451Sopenharmony_ci 1180f66f451Sopenharmony_ci if (!loop) { 1190f66f451Sopenharmony_ci char *s = toybuf; 1200f66f451Sopenharmony_ci 1210f66f451Sopenharmony_ci xreadfile("/proc/uptime", toybuf, sizeof(toybuf)); 1220f66f451Sopenharmony_ci while (*(s++) > ' '); 1230f66f451Sopenharmony_ci sscanf(s, "%"PRIu64, &units); 1240f66f451Sopenharmony_ci } else units = loop_delay; 1250f66f451Sopenharmony_ci 1260f66f451Sopenharmony_ci // add up user, sys, idle, and wait time used since last time 1270f66f451Sopenharmony_ci // (Already appended nice to user) 1280f66f451Sopenharmony_ci total_hz = 0; 1290f66f451Sopenharmony_ci for (i=0; i<4; i++) total_hz += ptr[i+!!i] - oldptr[i+!!i]; 1300f66f451Sopenharmony_ci 1310f66f451Sopenharmony_ci // Output values in order[]: running, blocked, swaptotal, memfree, buffers, 1320f66f451Sopenharmony_ci // cache, swap_in, swap_out, io_in, io_out, sirq, ctxt, user, sys, idle,wait 1330f66f451Sopenharmony_ci 1340f66f451Sopenharmony_ci for (i=0; i<sizeof(lengths); i++) { 1350f66f451Sopenharmony_ci char order[] = {9, 10, 15, 11, 12, 13, 18, 19, 16, 17, 6, 8, 0, 2, 3, 4}; 1360f66f451Sopenharmony_ci uint64_t out = ptr[order[i]]; 1370f66f451Sopenharmony_ci int len; 1380f66f451Sopenharmony_ci 1390f66f451Sopenharmony_ci // Adjust rate and units 1400f66f451Sopenharmony_ci if (i>5) out -= oldptr[order[i]]; 1410f66f451Sopenharmony_ci if (order[i]<7) out = ((out*100) + (total_hz/2)) / total_hz; 1420f66f451Sopenharmony_ci else if (order[i]>17) out = ((out * page_kb)+(units-1))/units; 1430f66f451Sopenharmony_ci else if (order[i]>15) out = ((out)+(units-1))/units; 1440f66f451Sopenharmony_ci else if (order[i]<9) out = (out+(units-1)) / units; 1450f66f451Sopenharmony_ci 1460f66f451Sopenharmony_ci // If a field was too big to fit in its slot, try to compensate later 1470f66f451Sopenharmony_ci expected += lengths[i] + !!i; 1480f66f451Sopenharmony_ci len = expected - offset - !!i; 1490f66f451Sopenharmony_ci if (len < 0) len = 0; 1500f66f451Sopenharmony_ci offset += printf(" %*"PRIu64+!i, len, out); 1510f66f451Sopenharmony_ci } 1520f66f451Sopenharmony_ci xputc('\n'); 1530f66f451Sopenharmony_ci 1540f66f451Sopenharmony_ci if (!loop_delay) break; 1550f66f451Sopenharmony_ci } 1560f66f451Sopenharmony_ci} 157