]> granicus.if.org Git - procps-ng/commitdiff
library: adding IO accounting
authorCraig Small <csmall@dropbear.xyz>
Sat, 24 Apr 2021 12:38:48 +0000 (22:38 +1000)
committerCraig Small <csmall@dropbear.xyz>
Sat, 24 Apr 2021 12:38:48 +0000 (22:38 +1000)
This is a modification of MR !122 by @renit1609 to fit the new
library.

Problem statement:
The procps library has no PROC_FILLIO flag to
fetch the proc field "/proc/[pid]/io" data
process-wise.
IO Accounting is not included as part of procps.

Requirement:
We have a requirement to fetch process wise
IO utilization which can be used for monitoring.

When looking through the procps library, I see
that IO Accounting (/proc/[pid]/io) is not being
included as part of procps. There is no such
flag like PROC_FILLIO being included in readproc.h .

Solution:
While looking at the implementation done for
other proc fields, I used the spare bits in app code.
I renamed PROC_SPARE_1 as PROC_FILLIO, the spare bit from
PROC_SPARE_* and used it for fetching /proc/[pid]/io
data as part of the procps library similar to other
fields. I moved the PROC_SPARE_* bits each by 1 bit
to retain the spare bits. Meanwhile added the IO fields
in proc_t structure.

References:
 procps-ng/procps!122
 procps-ng/procps#184

proc/pids.c
proc/pids.h
proc/readproc.c
proc/readproc.h

index 62a4a83b69cab60d0fba95977fd44900bd92316a..bacf85cab490789ceb7f620fda5d009a69a92d30 100644 (file)
@@ -193,6 +193,13 @@ REG_set(ID_SUSER,         str,     suser)
 REG_set(ID_TGID,          s_int,   tgid)
 REG_set(ID_TID,           s_int,   tid)
 REG_set(ID_TPGID,         s_int,   tpgid)
+REG_set(IO_READ_BYTES,    ul_int,  read_bytes)
+REG_set(IO_READ_CHARS,    ul_int,  rchar)
+REG_set(IO_READ_OPS,      ul_int,  syscr)
+REG_set(IO_WRITE_BYTES,   ul_int,  write_bytes)
+REG_set(IO_WRITE_CBYTES,  ul_int,  cancelled_write_bytes)
+REG_set(IO_WRITE_CHARS,   ul_int,  wchar)
+REG_set(IO_WRITE_OPS,     ul_int,  syscw)
 REG_set(LXCNAME,          str,     lxcname)
 CVT_set(MEM_CODE,         ul_int,  trs)
 REG_set(MEM_CODE_PGS,     ul_int,  trs)
@@ -341,6 +348,7 @@ srtDECL(noop) {
 #define f_grp      PROC_FILLGRP
 #define f_login    PROC_FILL_LUID
 #define f_lxc      PROC_FILL_LXC
+#define f_io       PROC_FILLIO
 #define f_ns       PROC_FILLNS
 #define f_oom      PROC_FILLOOM
 #define f_stat     PROC_FILLSTAT
@@ -442,6 +450,13 @@ static struct {
     { RS(ID_TGID),           0,          NULL,      QS(s_int),     0,        TS(s_int)   }, // oldflags: free w/ simple_nextpid
     { RS(ID_TID),            0,          NULL,      QS(s_int),     0,        TS(s_int)   }, // oldflags: free w/ simple_nexttid
     { RS(ID_TPGID),          f_stat,     NULL,      QS(s_int),     0,        TS(s_int)   },
+    { RS(IO_READ_BYTES),     f_io,       NULL,      QS(ul_int),    0,        TS(ul_int)  },
+    { RS(IO_READ_CHARS),     f_io,       NULL,      QS(ul_int),    0,        TS(ul_int)  },
+    { RS(IO_READ_OPS),       f_io,       NULL,      QS(ul_int),    0,        TS(ul_int)  },
+    { RS(IO_WRITE_BYTES),    f_io,       NULL,      QS(ul_int),    0,        TS(ul_int)  },
+    { RS(IO_WRITE_CBYTES),   f_io,       NULL,      QS(ul_int),    0,        TS(ul_int)  },
+    { RS(IO_WRITE_CHARS),    f_io,       NULL,      QS(ul_int),    0,        TS(ul_int)  },
+    { RS(IO_WRITE_OPS),      f_io,       NULL,      QS(ul_int),    0,        TS(ul_int)  },
     { RS(LXCNAME),           f_lxc,      NULL,      QS(str),       0,        TS(str)     }, // freefunc NULL w/ cached string
     { RS(MEM_CODE),          f_statm,    NULL,      QS(ul_int),    0,        TS(ul_int)  },
     { RS(MEM_CODE_PGS),      f_statm,    NULL,      QS(ul_int),    0,        TS(ul_int)  },
index 60037d7b1870076da09540a8d0d9e17d49489bef..f80a8f4a8b371886546455c77ffbcdd33ec31c6b 100644 (file)
@@ -78,6 +78,13 @@ enum pids_item {
     PIDS_ID_TGID,           //    s_int        status: Tgid
     PIDS_ID_TID,            //    s_int        from /proc/<pid>/task/<tid>
     PIDS_ID_TPGID,          //    s_int        stat: tty_pgrp
+    PIDS_IO_READ_BYTES,     //    ul_int       io: bytes read
+    PIDS_IO_READ_CHARS,     //    ul_int       io: characters read
+    PIDS_IO_READ_OPS,       //    ul_int       io: read operations
+    PIDS_IO_WRITE_BYTES,    //    ul_int       io: bytes written
+    PIDS_IO_WRITE_CBYTES,   //    ul_int       io: cancelled write bytes
+    PIDS_IO_WRITE_CHARS,    //    ul_int       io: characters written
+    PIDS_IO_WRITE_OPS,      //    ul_int       io: write operations
     PIDS_LXCNAME,           //      str        derived from CGROUP 'lxc.payload'
     PIDS_MEM_CODE,          //   ul_int        derived from MEM_CODE_PGS, as KiB
     PIDS_MEM_CODE_PGS,      //   ul_int        statm: trs
index bc92fa7b8eed8b744be03c32d7014f678641341e..9f96741b9a1e45a091853bba1b3716bf460a4c4c 100644 (file)
@@ -641,6 +641,12 @@ static void statm2proc(const char* s, proc_t *restrict P) {
            &P->trs, &P->lrs, &P->drs, &P->dt);
 }
 
+static void io2proc(const char* s, proc_t *restrict P) {
+    int num;
+    num = sscanf(s, "rchar: %lu wchar: %lu syscr: %lu syscw: %lu read_bytes: %lu write_bytes: %lu cancelled_write_bytes: %lu",
+            &P->rchar, &P->wchar, &P->syscr,
+            &P->syscw, &P->read_bytes, &P->write_bytes, &P->cancelled_write_bytes);
+}
 
 static int file2str(const char *directory, const char *what, struct utlbuf_s *ub) {
  #define buffGRW 1024
@@ -1043,6 +1049,11 @@ static proc_t* simple_readproc(PROCTAB *restrict const PT, proc_t *restrict cons
         rc += stat2proc(ub.buf, p);
     }
 
+    if (flags & PROC_FILLIO) {                  // read /proc/#/io
+        if (file2str(path, "io", &ub) != -1)
+            io2proc(ub.buf, p);
+    }
+
     if (flags & PROC_FILLMEM) {                 // read /proc/#/statm
         if (file2str(path, "statm", &ub) != -1)
             statm2proc(ub.buf, p);
@@ -1153,6 +1164,11 @@ static proc_t* simple_readtask(PROCTAB *restrict const PT, proc_t *restrict cons
         rc += stat2proc(ub.buf, t);
     }
 
+    if (flags & PROC_FILLIO) {                          // read /proc/#/io
+        if (file2str(path, "io", &ub) != -1)
+            io2proc(ub.buf, t);
+    }
+
     if (flags & PROC_FILLMEM) {                         // read /proc/#/task/#statm
         if (file2str(path, "statm", &ub) != -1)
             statm2proc(ub.buf, t);
index 46cb825a3f39825d103e70c255bf7f11e2fd99cd..992eb53e0554ba7fa89a3bea284d72e6bbd30be8 100644 (file)
@@ -97,7 +97,14 @@ typedef struct proc_t {
         min_flt,        // stat            number of minor page faults since process start
         maj_flt,        // stat            number of major page faults since process start
         cmin_flt,       // stat            cumulative min_flt of process and child processes
-        cmaj_flt;       // stat            cumulative maj_flt of process and child processes
+        cmaj_flt,       // stat            cumulative maj_flt of process and child processes
+        rchar,          // io              characters read
+        wchar,          // io              characters written
+        syscr,          // io              number of read I/O operations
+        syscw,          // io              number of write I/O operations
+        read_bytes,     // io              number of bytes fetched from the storage layer
+        write_bytes,    // io              number of bytes sent to the storage layer
+        cancelled_write_bytes; // io       number of bytes truncating pagecache
     char
         *environ,       // (special)       environment as string (/proc/#/environ)
         *cmdline,       // (special)       command line as string (/proc/#/cmdline)
@@ -209,6 +216,7 @@ typedef struct PROCTAB {
 #define PROC_FILL_LXC      0x800000 // fill in proc_t lxcname, if possible
 #define PROC_FILL_LUID     0x400000 // fill in proc_t luid (login user id)
 #define PROC_FILL_EXE      0x200000 // fill in proc_t exe path + pgm name
+#define PROC_FILLIO      0x01000000 // fill in proc_t io information
 
 // consider only processes with one of the passed:
 #define PROC_PID             0x1000  // process id numbers ( 0   terminated)
@@ -225,10 +233,10 @@ typedef struct PROCTAB {
 #define PROC_FILL_SUPGRP   ( 0x0400 | PROC_FILLSTATUS ) // obtain supplementary group names
 
 // it helps to give app code a few spare bits
-#define PROC_SPARE_1     0x01000000
-#define PROC_SPARE_2     0x02000000
-#define PROC_SPARE_3     0x04000000
-#define PROC_SPARE_4     0x08000000
+#define PROC_SPARE_1     0x02000000
+#define PROC_SPARE_2     0x04000000
+#define PROC_SPARE_3     0x08000000
+#define PROC_SPARE_4     0x10000000
 
 // Function definitions
 // Initialize a PROCTAB structure holding needed call-to-call persistent data