xref: /third_party/toybox/toys/other/vmstat.c (revision 0f66f451)
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