top: added fields for 'start time' & 'cpu utilization'

This patch will exploit some new library capabilities.

[ one will raise eyebrows, the other likely will not ]

A new 'STARTED' field was added which shows the time a
process started after system boot. As such the largest
interval represents the most recently started process.

This is the field that will likely be questioned since
it's somewhat counterintuitive. But were we to instead
use TIME_ELAPSED, the value will change with every top
refresh. This will defeat any PUFF macro optimization.

The new '%CUU' field will probably be better received.
It represents the cpu usage over the life of the task.
When a process was showing high %CPU usage, this field
can be used to determine if it's an anomaly or normal.

[ and as with %CPU, %CUU shows a '?' when running in ]
[ a namespace when /proc was mounted with subset=pid ]

Signed-off-by: Jim Warner <james.warner@comcast.net>
This commit is contained in:
Jim Warner 2022-02-25 00:00:00 -06:00 committed by Craig Small
parent c69104b2b8
commit 7647e96b0a
3 changed files with 44 additions and 16 deletions

View File

@ -1597,18 +1597,27 @@ end_justifies:
/* /*
* Make and then justify a percentage, with decreasing precision. */ * Make and then justify a percentage, with decreasing precision. */
static const char *scale_pcnt (float num, int width, int justr) { static const char *scale_pcnt (float num, int width, int justr, int xtra) {
static char buf[SMLBUFSIZ]; static char buf[SMLBUFSIZ];
buf[0] = '\0'; buf[0] = '\0';
if (Rc.zero_suppress && 0 >= num) if (Rc.zero_suppress && 0 >= num)
goto end_justifies; goto end_justifies;
if (xtra) {
if (width >= snprintf(buf, sizeof(buf), "%#.3f", num))
goto end_justifies;
if (width >= snprintf(buf, sizeof(buf), "%#.2f", num))
goto end_justifies;
goto carry_on;
}
#ifdef BOOST_PERCNT #ifdef BOOST_PERCNT
if (width >= snprintf(buf, sizeof(buf), "%#.3f", num)) if (width >= snprintf(buf, sizeof(buf), "%#.3f", num))
goto end_justifies; goto end_justifies;
if (width >= snprintf(buf, sizeof(buf), "%#.2f", num)) if (width >= snprintf(buf, sizeof(buf), "%#.2f", num))
goto end_justifies; goto end_justifies;
(void)xtra;
#endif #endif
carry_on:
if (width >= snprintf(buf, sizeof(buf), "%#.1f", num)) if (width >= snprintf(buf, sizeof(buf), "%#.1f", num))
goto end_justifies; goto end_justifies;
if (width >= snprintf(buf, sizeof(buf), "%*.0f", width, num)) if (width >= snprintf(buf, sizeof(buf), "%*.0f", width, num))
@ -1766,23 +1775,23 @@ static struct {
{ 6, -1, A_right, PIDS_IO_WRITE_BYTES }, // ul_int EU_IWB { 6, -1, A_right, PIDS_IO_WRITE_BYTES }, // ul_int EU_IWB
{ 5, -1, A_right, PIDS_IO_WRITE_OPS }, // ul_int EU_IWO { 5, -1, A_right, PIDS_IO_WRITE_OPS }, // ul_int EU_IWO
{ 5, -1, A_right, PIDS_AUTOGRP_ID }, // s_int EU_AGI { 5, -1, A_right, PIDS_AUTOGRP_ID }, // s_int EU_AGI
{ 4, -1, A_right, PIDS_AUTOGRP_NICE } // s_int EU_AGN { 4, -1, A_right, PIDS_AUTOGRP_NICE }, // s_int EU_AGN
#define eu_LAST EU_AGN { 9, -1, A_right, PIDS_TICS_BEGAN }, // ull_int EU_TM3
{ 6, -1, A_right, PIDS_UTILIZATION } // real EU_CUU
#define eu_LAST EU_CUU
// xtra Fieldstab 'pseudo pflag' entries for the newlib interface . . . . . . . // xtra Fieldstab 'pseudo pflag' entries for the newlib interface . . . . . . .
#define eu_CMDLINE eu_LAST +1 #define eu_CMDLINE eu_LAST +1
#define eu_TICS_ALL_C eu_LAST +2 #define eu_TICS_ALL_C eu_LAST +2
#define eu_TIME_START eu_LAST +3 #define eu_ID_FUID eu_LAST +3
#define eu_ID_FUID eu_LAST +4 #define eu_TREE_HID eu_LAST +4
#define eu_TREE_HID eu_LAST +5 #define eu_TREE_LVL eu_LAST +5
#define eu_TREE_LVL eu_LAST +6 #define eu_TREE_ADD eu_LAST +6
#define eu_TREE_ADD eu_LAST +7
, { -1, -1, -1, PIDS_CMDLINE } // str ( if Show_CMDLIN, eu_CMDLINE ) , { -1, -1, -1, PIDS_CMDLINE } // str ( if Show_CMDLIN, eu_CMDLINE )
, { -1, -1, -1, PIDS_TICS_ALL_C } // ull_int ( if Show_CTIMES, eu_TICS_ALL_C ) , { -1, -1, -1, PIDS_TICS_ALL_C } // ull_int ( if Show_CTIMES, eu_TICS_ALL_C )
, { -1, -1, -1, PIDS_TIME_START } // ull_int ( if Show_FOREST, eu_TIME_START )
, { -1, -1, -1, PIDS_ID_FUID } // u_int ( if a usrseltyp, eu_ID_FUID ) , { -1, -1, -1, PIDS_ID_FUID } // u_int ( if a usrseltyp, eu_ID_FUID )
, { -1, -1, -1, PIDS_extra } // s_ch ( if Show_FOREST, eu_TREE_HID ) , { -1, -1, -1, PIDS_extra } // s_ch ( if Show_FOREST, eu_TREE_HID )
, { -1, -1, -1, PIDS_extra } // s_int ( if Show_FOREST, eu_TREE_LVL ) , { -1, -1, -1, PIDS_extra } // s_int ( if Show_FOREST, eu_TREE_LVL )
, { -1, -1, -1, PIDS_extra } // u_int ( if Show_FOREST, eu_TREE_ADD ) , { -1, -1, -1, PIDS_extra } // s_int ( if Show_FOREST, eu_TREE_ADD )
#undef A_left #undef A_left
#undef A_right #undef A_right
}; };
@ -1956,9 +1965,9 @@ static void build_headers (void) {
if (!CHKw(w, Show_IDLEPS)) ckITEM(EU_CPU); if (!CHKw(w, Show_IDLEPS)) ckITEM(EU_CPU);
// with forest view mode, we'll need pid, tgid, ppid & start_time... // with forest view mode, we'll need pid, tgid, ppid & start_time...
#ifndef TREE_VCPUOFF #ifndef TREE_VCPUOFF
if (CHKw(w, Show_FOREST)) { ckITEM(EU_PPD); ckITEM(EU_TGD); ckITEM(eu_TIME_START); ckITEM(eu_TREE_HID); ckITEM(eu_TREE_LVL); ckITEM(eu_TREE_ADD); } if (CHKw(w, Show_FOREST)) { ckITEM(EU_PPD); ckITEM(EU_TGD); ckITEM(EU_TM3); ckITEM(eu_TREE_HID); ckITEM(eu_TREE_LVL); ckITEM(eu_TREE_ADD); }
#else #else
if (CHKw(w, Show_FOREST)) { ckITEM(EU_PPD); ckITEM(EU_TGD); ckITEM(eu_TIME_START); ckITEM(eu_TREE_HID); ckITEM(eu_TREE_LVL); } if (CHKw(w, Show_FOREST)) { ckITEM(EU_PPD); ckITEM(EU_TGD); ckITEM(EU_TM3); ckITEM(eu_TREE_HID); ckITEM(eu_TREE_LVL); }
#endif #endif
// for 'u/U' filtering we need these too (old top forgot that, oops) // for 'u/U' filtering we need these too (old top forgot that, oops)
if (w->usrseltyp) { ckITEM(EU_UED); ckITEM(EU_URD); ckITEM(EU_USD); ckITEM(eu_ID_FUID); } if (w->usrseltyp) { ckITEM(EU_UED); ckITEM(EU_URD); ckITEM(EU_USD); ckITEM(eu_ID_FUID); }
@ -4549,7 +4558,7 @@ static void forest_begin (WIN_t *q) {
#ifndef TREE_SCANALL #ifndef TREE_SCANALL
if (!(procps_pids_sort(Pids_ctx, Seed_ppt, PIDSmaxt if (!(procps_pids_sort(Pids_ctx, Seed_ppt, PIDSmaxt
, PIDS_TIME_START, PIDS_SORT_ASCEND))) , PIDS_TICS_BEGAN, PIDS_SORT_ASCEND)))
error_exit(fmtmk(N_fmt(LIB_errorpid_fmt), __LINE__, strerror(errno))); error_exit(fmtmk(N_fmt(LIB_errorpid_fmt), __LINE__, strerror(errno)));
#endif #endif
for (i = 0; i < PIDSmaxt; i++) { // avoid hidepid distorts | for (i = 0; i < PIDSmaxt; i++) { // avoid hidepid distorts |
@ -6158,9 +6167,17 @@ static const char *task_show (const WIN_t *q, int idx) {
if (u > 100.0 * n) u = 100.0 * n; if (u > 100.0 * n) u = 100.0 * n;
#endif #endif
if (u > Cpu_pmax) u = Cpu_pmax; if (u > Cpu_pmax) u = Cpu_pmax;
cp = scale_pcnt(u, W, Jn); cp = scale_pcnt(u, W, Jn, 0);
} }
break; break;
/* ull_int, scale_pcnt for 'utilization' */
case EU_CUU: // PIDS_UTILIZATION
if (Restrict_some) {
cp = justify_pad("?", W, Jn);
break;
}
cp = scale_pcnt(rSv(EU_CUU, real), W, Jn, 1);
break;
/* u_int, make_num with auto width */ /* u_int, make_num with auto width */
case EU_GID: // PIDS_ID_EGID case EU_GID: // PIDS_ID_EGID
case EU_UED: // PIDS_ID_EUID case EU_UED: // PIDS_ID_EUID
@ -6213,7 +6230,7 @@ static const char *task_show (const WIN_t *q, int idx) {
cp = justify_pad("?", W, Jn); cp = justify_pad("?", W, Jn);
break; break;
} }
cp = scale_pcnt((float)rSv(EU_MEM, ul_int) * 100 / MEM_VAL(mem_TOT), W, Jn); cp = scale_pcnt((float)rSv(EU_MEM, ul_int) * 100 / MEM_VAL(mem_TOT), W, Jn, 0);
break; break;
/* ul_int, make_str with special handling */ /* ul_int, make_str with special handling */
case EU_FLG: // PIDS_FLAGS case EU_FLG: // PIDS_FLAGS
@ -6228,6 +6245,10 @@ static const char *task_show (const WIN_t *q, int idx) {
cp = scale_tics(t, W, Jn); cp = scale_tics(t, W, Jn);
} }
break; break;
/* ull_int, scale_time */
case EU_TM3: // PIDS_TICS_BEGAN
cp = scale_tics(rSv(EU_TM3, ull_int), W, Jn);
break;
/* str, make_str (all AUTOX yes) */ /* str, make_str (all AUTOX yes) */
case EU_LXC: // PIDS_LXCNAME case EU_LXC: // PIDS_LXCNAME
case EU_TTY: // PIDS_TTY_NAME case EU_TTY: // PIDS_TTY_NAME

View File

@ -202,6 +202,7 @@ enum pflag {
EU_RSS, EU_PSS, EU_PZA, EU_PZF, EU_PZS, EU_USS, EU_RSS, EU_PSS, EU_PZA, EU_PZF, EU_PZS, EU_USS,
EU_IRB, EU_IRO, EU_IWB, EU_IWO, EU_IRB, EU_IRO, EU_IWB, EU_IWO,
EU_AGI, EU_AGN, EU_AGI, EU_AGN,
EU_TM3, EU_CUU,
#ifdef USE_X_COLHDR #ifdef USE_X_COLHDR
// not really pflags, used with tbl indexing // not really pflags, used with tbl indexing
EU_MAXPFLGS EU_MAXPFLGS
@ -622,7 +623,7 @@ typedef struct WIN_t {
//atic inline const char *make_str_utf8 (const char *str, int width, int justr, int col); //atic inline const char *make_str_utf8 (const char *str, int width, int justr, int col);
//atic const char *scale_mem (int target, float num, int width, int justr); //atic const char *scale_mem (int target, float num, int width, int justr);
//atic const char *scale_num (float num, int width, int justr); //atic const char *scale_num (float num, int width, int justr);
//atic const char *scale_pcnt (float num, int width, int justr); //atic const char *scale_pcnt (float num, int width, int justr, int xtra);
//atic const char *scale_tics (TIC_t tics, int width, int justr); //atic const char *scale_tics (TIC_t tics, int width, int justr);
/*------ Fields Management support -------------------------------------*/ /*------ Fields Management support -------------------------------------*/
/*atic struct Fieldstab[] = { ... } */ /*atic struct Fieldstab[] = { ... } */

View File

@ -350,6 +350,12 @@ static void build_two_nlstabs (void) {
/* Translation Hint: maximum 'AGNI' = 4 */ /* Translation Hint: maximum 'AGNI' = 4 */
Head_nlstab[EU_AGN] = _("AGNI"); Head_nlstab[EU_AGN] = _("AGNI");
Desc_nlstab[EU_AGN] = _("Autogroup Nice Value"); Desc_nlstab[EU_AGN] = _("Autogroup Nice Value");
/* Translation Hint: maximum 'STARTED' = 9 */
Head_nlstab[EU_TM3] = _("STARTED");
Desc_nlstab[EU_TM3] = _("Start Time from boot");
/* Translation Hint: maximum '%CUU' = 6 */
Head_nlstab[EU_CUU] = _("%CUU");
Desc_nlstab[EU_CUU] = _("CPU Utilization");
} }