From c69104b2b835176f9801dfd1a1d893579879a5b6 Mon Sep 17 00:00:00 2001 From: Jim Warner Date: Fri, 25 Feb 2022 00:00:00 -0600 Subject: [PATCH] library: added important new functionality, api This commit introduces some new capabilities available in libproc-2 under the interface. Along the way errors impacting some item values have been corrected. The following summarizes the major changes being made. 1. The PIDS_TIME_START item was represented as seconds since system boot but really held tics since boot. And some programs properly divided it by Hertz to actually yield seconds while others acted as if it already was. So, now we have a new PIDS_TICS_BEGAN field and all of the 'TIME' fields properly reflect seconds. With those 'TIME' fields, the type was changed to 'float/real' so one could convert it back to tics without loss of some centiseconds reflected in the Hertz guy (usually 100). 2. The boot_seconds was established in procps_pids_new meaning it was fixed/unchanging. As a result, one item (PIDS_TIME_ELAPSED) was rendered useless. So now, each of the three retrieval functions establishes a current boot_seconds well before the set functions are called. 3. Added a PIDS_UTILIZATION item that will provide the CPU usage over the life of a process, as a percentage. 4. Added PIDS_TIME_ALL_C for symmetry with the similar item called PIDS_TICS_ALL_C (which reflects raw tics). 5. That 'derived from' notation has been added to some additional header items to reflect their true origins. Signed-off-by: Jim Warner --- proc/pids.c | 50 +++++++++++++++++++++++++++++++++++++------------- proc/pids.h | 20 ++++++++++++-------- 2 files changed, 49 insertions(+), 21 deletions(-) diff --git a/proc/pids.c b/proc/pids.c index fee4109a..2914bf00 100644 --- a/proc/pids.c +++ b/proc/pids.c @@ -90,8 +90,8 @@ struct pids_info { unsigned pgs2k_shift; // to convert some proc vaules unsigned oldflags; // the old library PROC_FILL flagss PROCTAB *fetch_PT; // oldlib interface for 'select' & 'reap' - unsigned long hertz; // for TIME_ALL & TIME_ELAPSED calculations - unsigned long long boot_seconds; // for TIME_ELAPSED calculation + unsigned long hertz; // for the 'TIME' & 'UTILIZATION' calculations + float boot_seconds; // for TIME_ELAPSED & 'UTILIZATION' calculations PROCTAB *get_PT; // oldlib interface for active 'get' struct stacks_extent *get_ext; // for active 'get' (also within 'extents') enum pids_fetch_type get_type; // last known type of 'get' request @@ -271,6 +271,7 @@ STR_set(SUPGROUPS, supgrp) setDECL(TICS_ALL) { (void)I; R->result.ull_int = P->utime + P->stime; } setDECL(TICS_ALL_C) { (void)I; R->result.ull_int = P->utime + P->stime + P->cutime + P->cstime; } REG_set(TICS_ALL_DELTA, u_int, pcpu) +REG_set(TICS_BEGAN, ull_int, start_time) REG_set(TICS_BLKIO, ull_int, blkio_tics) REG_set(TICS_GUEST, ull_int, gtime) setDECL(TICS_GUEST_C) { (void)I; R->result.ull_int = P->gtime + P->cgtime; } @@ -278,12 +279,14 @@ REG_set(TICS_SYSTEM, ull_int, stime) setDECL(TICS_SYSTEM_C) { (void)I; R->result.ull_int = P->stime + P->cstime; } REG_set(TICS_USER, ull_int, utime) setDECL(TICS_USER_C) { (void)I; R->result.ull_int = P->utime + P->cutime; } -setDECL(TIME_ALL) { R->result.ull_int = (P->utime + P->stime) / I->hertz; } -setDECL(TIME_ELAPSED) { unsigned long long t = P->start_time / I->hertz; R->result.ull_int = I->boot_seconds >= t ? (I->boot_seconds - t) : 0; } -REG_set(TIME_START, ull_int, start_time) +setDECL(TIME_ALL) { R->result.real = ((float)P->utime + P->stime) / I->hertz; } +setDECL(TIME_ALL_C) { R->result.real = ((float)P->utime + P->stime + P->cutime + P->cstime) / I->hertz; } +setDECL(TIME_ELAPSED) { float t = (float)P->start_time / I->hertz; R->result.real = I->boot_seconds > t ? I->boot_seconds - t : 0; } +setDECL(TIME_START) { R->result.real = (float)P->start_time / I->hertz; } REG_set(TTY, s_int, tty) setDECL(TTY_NAME) { char buf[64]; freNAME(str)(R); dev_to_tty(buf, sizeof(buf), P->tty, P->tid, ABBREV_DEV); if (!(R->result.str = strdup(buf))) I->seterr = 1; } setDECL(TTY_NUMBER) { char buf[64]; freNAME(str)(R); dev_to_tty(buf, sizeof(buf), P->tty, P->tid, ABBREV_DEV|ABBREV_TTY|ABBREV_PTS); if (!(R->result.str = strdup(buf))) I->seterr = 1; } +setDECL(UTILIZATION) { float t; if (I->boot_seconds > 0) { t = I->boot_seconds - ((float)P->start_time / I->hertz); R->result.real = (float)P->utime + P->stime; R->result.real *= (100.0f / ((float)I->hertz * t)); }} REG_set(VM_DATA, ul_int, vm_data) REG_set(VM_EXE, ul_int, vm_exe) REG_set(VM_LIB, ul_int, vm_lib) @@ -337,6 +340,8 @@ REG_srt(u_int) REG_srt(ul_int) REG_srt(ull_int) +REG_srt(real) + srtDECL(str) { const struct pids_result *a = (*A)->head + P->offset; const struct pids_result *b = (*B)->head + P->offset; @@ -554,6 +559,7 @@ static struct { { RS(TICS_ALL), f_stat, NULL, QS(ull_int), 0, TS(ull_int) }, { RS(TICS_ALL_C), f_stat, NULL, QS(ull_int), 0, TS(ull_int) }, { RS(TICS_ALL_DELTA), f_stat, NULL, QS(u_int), +1, TS(u_int) }, + { RS(TICS_BEGAN), f_stat, NULL, QS(ull_int), 0, TS(ull_int) }, { RS(TICS_BLKIO), f_stat, NULL, QS(ull_int), 0, TS(ull_int) }, { RS(TICS_GUEST), f_stat, NULL, QS(ull_int), 0, TS(ull_int) }, { RS(TICS_GUEST_C), f_stat, NULL, QS(ull_int), 0, TS(ull_int) }, @@ -561,12 +567,14 @@ static struct { { RS(TICS_SYSTEM_C), f_stat, NULL, QS(ull_int), 0, TS(ull_int) }, { RS(TICS_USER), f_stat, NULL, QS(ull_int), 0, TS(ull_int) }, { RS(TICS_USER_C), f_stat, NULL, QS(ull_int), 0, TS(ull_int) }, - { RS(TIME_ALL), f_stat, NULL, QS(ull_int), 0, TS(ull_int) }, - { RS(TIME_ELAPSED), f_stat, NULL, QS(ull_int), 0, TS(ull_int) }, - { RS(TIME_START), f_stat, NULL, QS(ull_int), 0, TS(ull_int) }, + { RS(TIME_ALL), f_stat, NULL, QS(real), 0, TS(real) }, + { RS(TIME_ALL_C), f_stat, NULL, QS(real), 0, TS(real) }, + { RS(TIME_ELAPSED), f_stat, NULL, QS(real), 0, TS(real) }, + { RS(TIME_START), f_stat, NULL, QS(real), 0, TS(real) }, { RS(TTY), f_stat, NULL, QS(s_int), 0, TS(s_int) }, { RS(TTY_NAME), f_stat, FF(str), QS(strvers), 0, TS(str) }, { RS(TTY_NUMBER), f_stat, FF(str), QS(strvers), 0, TS(str) }, + { RS(UTILIZATION), f_stat, NULL, QS(real), 0, TS(real) }, { RS(VM_DATA), f_status, NULL, QS(ul_int), 0, TS(ul_int) }, { RS(VM_EXE), f_status, NULL, QS(ul_int), 0, TS(ul_int) }, { RS(VM_LIB), f_status, NULL, QS(ul_int), 0, TS(ul_int) }, @@ -1198,7 +1206,6 @@ PROCPS_EXPORT int procps_pids_new ( int numitems) { struct pids_info *p; - double uptime_secs; int pgsz; #ifdef ITEMTABLE_DEBUG @@ -1282,10 +1289,6 @@ PROCPS_EXPORT int procps_pids_new ( while (pgsz > 1024) { pgsz >>= 1; p->pgs2k_shift++; } p->hertz = procps_hertz_get(); - // in case 'fatal_proc_unmounted' wasn't called and /proc isn't mounted - if (0 >= procps_uptime(&uptime_secs, NULL)) - p->boot_seconds = uptime_secs; - numa_init(); p->fetch.results.counts = &p->fetch.counts; @@ -1405,6 +1408,7 @@ PROCPS_EXPORT struct pids_stack *procps_pids_get ( struct pids_info *info, enum pids_fetch_type which) { + double up_secs; errno = EINVAL; if (info == NULL) @@ -1432,6 +1436,12 @@ fresh_start: } errno = 0; + /* when in a namespace with proc mounted subset=pid, + we will be restricted to process information only */ + info->boot_seconds = 0; + if (0 >= procps_uptime(&up_secs, NULL)) + info->boot_seconds = up_secs; + if (NULL == info->read_something(info->get_PT, &info->get_proc)) return NULL; if (!pids_assign_results(info, info->get_ext->stacks[0], &info->get_proc)) @@ -1451,6 +1461,7 @@ PROCPS_EXPORT struct pids_fetch *procps_pids_reap ( struct pids_info *info, enum pids_fetch_type which) { + double up_secs; int rc; errno = EINVAL; @@ -1468,6 +1479,12 @@ PROCPS_EXPORT struct pids_fetch *procps_pids_reap ( return NULL; info->read_something = which ? readeither : readproc; + /* when in a namespace with proc mounted subset=pid, + we will be restricted to process information only */ + info->boot_seconds = 0; + if (0 >= procps_uptime(&up_secs, NULL)) + info->boot_seconds = up_secs; + rc = pids_stacks_fetch(info); pids_oldproc_close(&info->fetch_PT); @@ -1541,6 +1558,7 @@ PROCPS_EXPORT struct pids_fetch *procps_pids_select ( int numthese, enum pids_select_type which) { + double up_secs; unsigned ids[FILL_ID_MAX + 1]; int rc; @@ -1566,6 +1584,12 @@ PROCPS_EXPORT struct pids_fetch *procps_pids_select ( return NULL; info->read_something = (which & PIDS_FETCH_THREADS_TOO) ? readeither : readproc; + /* when in a namespace with proc mounted subset=pid, + we will be restricted to process information only */ + info->boot_seconds = 0; + if (0 >= procps_uptime(&up_secs, NULL)) + info->boot_seconds = up_secs; + rc = pids_stacks_fetch(info); pids_oldproc_close(&info->fetch_PT); diff --git a/proc/pids.h b/proc/pids.h index 4331c5ec..f2713c8c 100644 --- a/proc/pids.h +++ b/proc/pids.h @@ -51,7 +51,7 @@ enum pids_item { PIDS_EXIT_SIGNAL, // s_int stat: exit_signal PIDS_FLAGS, // ul_int stat: flags PIDS_FLT_MAJ, // ul_int stat: maj_flt - PIDS_FLT_MAJ_C, // ul_int stat: maj_flt + cmaj_flt + PIDS_FLT_MAJ_C, // ul_int derived from stat: maj_flt + cmaj_flt PIDS_FLT_MAJ_DELTA, // s_int derived from FLT_MAJ PIDS_FLT_MIN, // ul_int stat: min_flt PIDS_FLT_MIN_C, // ul_int stat: min_flt + cmin_flt @@ -154,19 +154,22 @@ enum pids_item { PIDS_TICS_ALL, // ull_int stat: stime + utime PIDS_TICS_ALL_C, // ull_int stat: stime + utime + cstime + cutime PIDS_TICS_ALL_DELTA, // u_int derived from TICS_ALL + PIDS_TICS_BEGAN, // ull_int stat: start_time PIDS_TICS_BLKIO, // ull_int stat: blkio_ticks PIDS_TICS_GUEST, // ull_int stat: gtime - PIDS_TICS_GUEST_C, // ull_int stat: gtime + cgtime + PIDS_TICS_GUEST_C, // ull_int derived from stat: gtime + cgtime PIDS_TICS_SYSTEM, // ull_int stat: stime - PIDS_TICS_SYSTEM_C, // ull_int stat: stime + cstime + PIDS_TICS_SYSTEM_C, // ull_int derived from stat: stime + cstime PIDS_TICS_USER, // ull_int stat: utime - PIDS_TICS_USER_C, // ull_int stat: utime + cutime - PIDS_TIME_ALL, // ull_int derived from (utime + stime) / hertz - PIDS_TIME_ELAPSED, // ull_int derived from /proc/uptime - (starttime / hertz) - PIDS_TIME_START, // ull_int stat: start_time + PIDS_TICS_USER_C, // ull_int derived from stat: utime + cutime + PIDS_TIME_ALL, // real derived from (utime + stime) / hertz + PIDS_TIME_ALL_C, // real derived from (utime + stime + cutime + cstime) / hertz + PIDS_TIME_ELAPSED, // real derived from /proc/uptime - (starttime / hertz) + PIDS_TIME_START, // real derived from stat: start_time / hertz PIDS_TTY, // s_int stat: tty_nr PIDS_TTY_NAME, // str derived from TTY PIDS_TTY_NUMBER, // str derived from TTY as str + PIDS_UTILIZATION, // real derived from TIME_ALL / TIME_ELAPSED, as percentage PIDS_VM_DATA, // ul_int status: VmData PIDS_VM_EXE, // ul_int status: VmExe PIDS_VM_LIB, // ul_int status: VmLib @@ -178,7 +181,7 @@ enum pids_item { PIDS_VM_SIZE, // ul_int status: VmSize PIDS_VM_STACK, // ul_int status: VmStk PIDS_VM_SWAP, // ul_int status: VmSwap - PIDS_VM_USED, // ul_int status: VmRSS + VmSwap + PIDS_VM_USED, // ul_int derived from status: VmRSS + VmSwap PIDS_VSIZE_PGS, // ul_int stat: vsize PIDS_WCHAN_NAME // str wchan }; @@ -211,6 +214,7 @@ struct pids_result { unsigned long long ull_int; char *str; char **strv; + float real; } result; };