diff --git a/proc/pids.c b/proc/pids.c index 172fd656..472e6af9 100644 --- a/proc/pids.c +++ b/proc/pids.c @@ -240,6 +240,26 @@ DUP_set(SIGCATCH, sigcatch) DUP_set(SIGIGNORE, sigignore) DUP_set(SIGNALS, signal) DUP_set(SIGPENDING, _sigpnd) +REG_set(SMAP_ANONYMOUS, ul_int, smap_Anonymous) +REG_set(SMAP_HUGETBL_PRV, ul_int, smap_Private_Hugetlb) +REG_set(SMAP_HUGETBL_SHR, ul_int, smap_Shared_Hugetlb) +REG_set(SMAP_HUGE_ANON, ul_int, smap_AnonHugePages) +REG_set(SMAP_HUGE_FILE, ul_int, smap_FilePmdMapped) +REG_set(SMAP_HUGE_SHMEM, ul_int, smap_ShmemPmdMapped) +REG_set(SMAP_LAZY_FREE, ul_int, smap_LazyFree) +REG_set(SMAP_LOCKED, ul_int, smap_Locked) +REG_set(SMAP_PRV_CLEAN, ul_int, smap_Private_Clean) +REG_set(SMAP_PRV_DIRTY, ul_int, smap_Private_Dirty) +REG_set(SMAP_PSS, ul_int, smap_Pss) +REG_set(SMAP_PSS_ANON, ul_int, smap_Pss_Anon) +REG_set(SMAP_PSS_FILE, ul_int, smap_Pss_File) +REG_set(SMAP_PSS_SHMEM, ul_int, smap_Pss_Shmem) +REG_set(SMAP_REFERENCED, ul_int, smap_Referenced) +REG_set(SMAP_RSS, ul_int, smap_Rss) +REG_set(SMAP_SHR_CLEAN, ul_int, smap_Shared_Clean) +REG_set(SMAP_SHR_DIRTY, ul_int, smap_Shared_Dirty) +REG_set(SMAP_SWAP, ul_int, smap_Swap) +REG_set(SMAP_SWAP_PSS, ul_int, smap_SwapPss) REG_set(STATE, s_ch, state) STR_set(SUPGIDS, supgid) STR_set(SUPGROUPS, supgrp) @@ -351,6 +371,7 @@ srtDECL(noop) { #define f_lxc PROC_FILL_LXC #define f_ns PROC_FILLNS #define f_oom PROC_FILLOOM +#define f_smaps PROC_FILLSMAPS #define f_stat PROC_FILLSTAT #define f_statm PROC_FILLMEM #define f_status PROC_FILLSTATUS @@ -497,6 +518,26 @@ static struct { { RS(SIGIGNORE), f_status, FF(str), QS(str), 0, TS(str) }, { RS(SIGNALS), f_status, FF(str), QS(str), 0, TS(str) }, { RS(SIGPENDING), f_status, FF(str), QS(str), 0, TS(str) }, + { RS(SMAP_ANONYMOUS), f_smaps, NULL, QS(ul_int), 0, TS(ul_int) }, + { RS(SMAP_HUGETBL_PRV), f_smaps, NULL, QS(ul_int), 0, TS(ul_int) }, + { RS(SMAP_HUGETBL_SHR), f_smaps, NULL, QS(ul_int), 0, TS(ul_int) }, + { RS(SMAP_HUGE_ANON), f_smaps, NULL, QS(ul_int), 0, TS(ul_int) }, + { RS(SMAP_HUGE_FILE), f_smaps, NULL, QS(ul_int), 0, TS(ul_int) }, + { RS(SMAP_HUGE_SHMEM), f_smaps, NULL, QS(ul_int), 0, TS(ul_int) }, + { RS(SMAP_LAZY_FREE), f_smaps, NULL, QS(ul_int), 0, TS(ul_int) }, + { RS(SMAP_LOCKED), f_smaps, NULL, QS(ul_int), 0, TS(ul_int) }, + { RS(SMAP_PRV_CLEAN), f_smaps, NULL, QS(ul_int), 0, TS(ul_int) }, + { RS(SMAP_PRV_DIRTY), f_smaps, NULL, QS(ul_int), 0, TS(ul_int) }, + { RS(SMAP_PSS), f_smaps, NULL, QS(ul_int), 0, TS(ul_int) }, + { RS(SMAP_PSS_ANON), f_smaps, NULL, QS(ul_int), 0, TS(ul_int) }, + { RS(SMAP_PSS_FILE), f_smaps, NULL, QS(ul_int), 0, TS(ul_int) }, + { RS(SMAP_PSS_SHMEM), f_smaps, NULL, QS(ul_int), 0, TS(ul_int) }, + { RS(SMAP_REFERENCED), f_smaps, NULL, QS(ul_int), 0, TS(ul_int) }, + { RS(SMAP_RSS), f_smaps, NULL, QS(ul_int), 0, TS(ul_int) }, + { RS(SMAP_SHR_CLEAN), f_smaps, NULL, QS(ul_int), 0, TS(ul_int) }, + { RS(SMAP_SHR_DIRTY), f_smaps, NULL, QS(ul_int), 0, TS(ul_int) }, + { RS(SMAP_SWAP), f_smaps, NULL, QS(ul_int), 0, TS(ul_int) }, + { RS(SMAP_SWAP_PSS), f_smaps, NULL, QS(ul_int), 0, TS(ul_int) }, { RS(STATE), f_either, NULL, QS(s_ch), 0, TS(s_ch) }, { RS(SUPGIDS), f_status, FF(str), QS(str), 0, TS(str) }, { RS(SUPGROUPS), x_supgrp, FF(str), QS(str), 0, TS(str) }, @@ -551,6 +592,7 @@ enum pids_item PIDS_logical_end = MAXTABLE(Item_table); #undef f_lxc #undef f_ns #undef f_oom +#undef f_smaps //#undef f_stat // needed later #undef f_statm //#undef f_status // needed later diff --git a/proc/pids.h b/proc/pids.h index 750fb039..40765025 100644 --- a/proc/pids.h +++ b/proc/pids.h @@ -125,6 +125,26 @@ enum pids_item { PIDS_SIGIGNORE, // str status: SigIgn PIDS_SIGNALS, // str status: ShdPnd PIDS_SIGPENDING, // str status: SigPnd + PIDS_SMAP_ANONYMOUS, // ul_int smaps_rollup: Anonymous + PIDS_SMAP_HUGETBL_PRV, // ul_int smaps_rollup: Private_Hugetlb + PIDS_SMAP_HUGETBL_SHR, // ul_int smaps_rollup: Shared_Hugetlb + PIDS_SMAP_HUGE_ANON, // ul_int smaps_rollup: AnonHugePages + PIDS_SMAP_HUGE_FILE, // ul_int smaps_rollup: FilePmdMapped + PIDS_SMAP_HUGE_SHMEM, // ul_int smaps_rollup: ShmemPmdMapped + PIDS_SMAP_LAZY_FREE, // ul_int smaps_rollup: LazyFree + PIDS_SMAP_LOCKED, // ul_int smaps_rollup: Locked + PIDS_SMAP_PRV_CLEAN, // ul_int smaps_rollup: Private_Clean + PIDS_SMAP_PRV_DIRTY, // ul_int smaps_rollup: Private_Dirty + PIDS_SMAP_PSS, // ul_int smaps_rollup: Pss + PIDS_SMAP_PSS_ANON, // ul_int smaps_rollup: Pss_Anon + PIDS_SMAP_PSS_FILE, // ul_int smaps_rollup: Pss_File + PIDS_SMAP_PSS_SHMEM, // ul_int smaps_rollup: Pss_Shmem + PIDS_SMAP_REFERENCED, // ul_int smaps_rollup: Referenced + PIDS_SMAP_RSS, // ul_int smaps_rollup: Rss + PIDS_SMAP_SHR_CLEAN, // ul_int smaps_rollup: Shared_Clean + PIDS_SMAP_SHR_DIRTY, // ul_int smaps_rollup: Shared_Dirty + PIDS_SMAP_SWAP, // ul_int smaps_rollup: Swap + PIDS_SMAP_SWAP_PSS, // ul_int smaps_rollup: SwapPss PIDS_STATE, // s_ch stat: state or status: State PIDS_SUPGIDS, // str status: Groups PIDS_SUPGROUPS, // str derived from SUPGIDS, see getgrgid(3) diff --git a/proc/readproc.c b/proc/readproc.c index 7d6e722f..4975981d 100644 --- a/proc/readproc.c +++ b/proc/readproc.c @@ -648,6 +648,72 @@ static void io2proc(const char* s, proc_t *restrict P) { &P->syscw, &P->read_bytes, &P->write_bytes, &P->cancelled_write_bytes); } + // Assuming permissions have allowed the read of smaps_rollup, this + // guy will extract some %lu data. Considering the number of items, + // we are between small enough to use a sscanf and large enough for + // a search.h approach. Thus we roll (get it?) our own custom code. +static void smaps2proc (const char* s, proc_t *restrict P) { + #define enMAX (int)((sizeof(smaptab) / sizeof(smaptab[0]))) + // 1st proc_t data field + #define fZERO tid + // a smaptab entry generator + #define mkENT(F) { #F ":", -1, (int)((void*)&q->smap_ ## F - (void*)&q->fZERO) } + // make a target field + #define mkOBJ(e) ( (unsigned long *)((void *)&P->fZERO + smaptab[e].offs) ) + static const proc_t *q; + static struct { + const char *item; + int slen; + int offs; + } smaptab[] = { + /* Size smaps only, not rollup */ + /* KernelPageSize " */ + /* MMUPageSize " */ + mkENT(Rss), + mkENT(Pss), + mkENT(Pss_Anon), /* rollup only, not smaps */ + mkENT(Pss_File), /* " */ + mkENT(Pss_Shmem), /* " */ + mkENT(Shared_Clean), + mkENT(Shared_Dirty), + mkENT(Private_Clean), + mkENT(Private_Dirty), + mkENT(Referenced), + mkENT(Anonymous), + mkENT(LazyFree), + mkENT(AnonHugePages), + mkENT(ShmemPmdMapped), + mkENT(FilePmdMapped), + mkENT(Shared_Hugetlb), + mkENT(Private_Hugetlb), + mkENT(Swap), + mkENT(SwapPss), + mkENT(Locked) + /* THPeligible smaps only, not rollup */ + /* ProtectionKey " */ + /* VmFlags " */ + }; + char *head, *tail; + int i; + + if (smaptab[0].slen < 0) { + for (i = 0; i < enMAX; i++) + smaptab[i].slen = (int)strlen(smaptab[i].item); + } + for (i = 0; i < enMAX; i++) { + if (!(head = strstr(s, smaptab[i].item))) + continue; + head += smaptab[i].slen; + *mkOBJ(i) = strtoul(head, &tail, 10); + // saves some overhead BUT makes us dependent on current order + s = tail; + } + #undef enMAX + #undef fZERO + #undef mkENT + #undef mkOBJ +} + static int file2str(const char *directory, const char *what, struct utlbuf_s *ub) { #define buffGRW 1024 char path[PROCPATHLEN]; @@ -1054,6 +1120,11 @@ static proc_t* simple_readproc(PROCTAB *restrict const PT, proc_t *restrict cons io2proc(ub.buf, p); } + if (flags & PROC_FILLSMAPS) { // read /proc/#/smaps_rollup + if (file2str(path, "smaps_rollup", &ub) != -1) + smaps2proc(ub.buf, p); + } + if (flags & PROC_FILLMEM) { // read /proc/#/statm if (file2str(path, "statm", &ub) != -1) statm2proc(ub.buf, p); @@ -1169,10 +1240,16 @@ static proc_t* simple_readtask(PROCTAB *restrict const PT, proc_t *restrict cons io2proc(ub.buf, t); } + if (flags & PROC_FILLSMAPS) { // read /proc/#/task/#/smaps_rollup + if (file2str(path, "smaps_rollup", &ub) != -1) + smaps2proc(ub.buf, t); + } + if (flags & PROC_FILLMEM) { // read /proc/#/task/#/statm if (file2str(path, "statm", &ub) != -1) statm2proc(ub.buf, t); } + if (flags & PROC_FILLSTATUS) { // read /proc/#/task/#/status if (file2str(path, "status", &ub) != -1) { rc += status2proc(ub.buf, t, 0); diff --git a/proc/readproc.h b/proc/readproc.h index 992eb53e..21ca926d 100644 --- a/proc/readproc.h +++ b/proc/readproc.h @@ -104,7 +104,27 @@ typedef struct proc_t { 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 + cancelled_write_bytes, // io number of bytes truncating pagecache + smap_Rss, // smaps_rollup mapping currently resident in RAM + smap_Pss, // " Rss divided by total processes sharing it + smap_Pss_Anon, // " proportional share of 'anonymous' memory + smap_Pss_File, // " proportional share of 'file' memory + smap_Pss_Shmem, // " proportional share of 'shmem' memory + smap_Shared_Clean, // " unmodified shared memory + smap_Shared_Dirty, // " altered shared memory + smap_Private_Clean, // " unmodified private memory + smap_Private_Dirty, // " altered private memory + smap_Referenced, // " memory marked as referenced/accessed + smap_Anonymous, // " memory not belonging to any file + smap_LazyFree, // " memory marked by madvise(MADV_FREE) + smap_AnonHugePages, // " memory backed by transparent huge pages + smap_ShmemPmdMapped, // " shmem/tmpfs memory backed by huge pages + smap_FilePmdMapped, // " file memory backed by huge pages + smap_Shared_Hugetlb, // " hugetlbfs backed memory *not* counted in Rss/Pss + smap_Private_Hugetlb, // " hugetlbfs backed memory *not* counted in Rss/Pss + smap_Swap, // " swapped would-be-anonymous memory (includes swapped out shmem) + smap_SwapPss, // " the proportional share of 'Swap' (excludes swapped out shmem) + smap_Locked; // " memory amount locked to RAM char *environ, // (special) environment as string (/proc/#/environ) *cmdline, // (special) command line as string (/proc/#/cmdline) @@ -217,6 +237,7 @@ typedef struct PROCTAB { #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 +#define PROC_FILLSMAPS 0x02000000 // fill in proc_t smaps_rollup stuff // consider only processes with one of the passed: #define PROC_PID 0x1000 // process id numbers ( 0 terminated) @@ -233,10 +254,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 0x02000000 -#define PROC_SPARE_2 0x04000000 -#define PROC_SPARE_3 0x08000000 -#define PROC_SPARE_4 0x10000000 +#define PROC_SPARE_1 0x04000000 +#define PROC_SPARE_2 0x08000000 +#define PROC_SPARE_3 0x10000000 +#define PROC_SPARE_4 0x20000000 // Function definitions // Initialize a PROCTAB structure holding needed call-to-call persistent data