library: adding IO accounting

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
This commit is contained in:
Craig Small 2021-04-24 22:38:48 +10:00
parent fa31656f07
commit a7afe06e6f
4 changed files with 51 additions and 5 deletions

View 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) },

View 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

View 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);

View 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