]> granicus.if.org Git - procps-ng/commitdiff
library: added important new functionality, <pids> api
authorJim Warner <james.warner@comcast.net>
Fri, 25 Feb 2022 06:00:00 +0000 (00:00 -0600)
committerCraig Small <csmall@dropbear.xyz>
Sun, 27 Feb 2022 10:27:02 +0000 (21:27 +1100)
This commit introduces some new capabilities available
in libproc-2 under the <PIDS> 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 <james.warner@comcast.net>
proc/pids.c
proc/pids.h

index fee4109a6a33d2183c9de7050da0d7a9badbdbbc..2914bf00b319062b8efe9d3bf49a0f5f22c15b30 100644 (file)
@@ -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);
index 4331c5ec91e5b1bdf44320f7f133458510666ac5..f2713c8cb03eb037e6c1d4af6dc6bbd908dc9121 100644 (file)
@@ -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;
 };