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)
#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
{ 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) },
#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
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)
&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];
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);
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);
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)
#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)
#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