From 7647e96b0a35d473fa9bc644ea6107487b3b0527 Mon Sep 17 00:00:00 2001 From: Jim Warner Date: Fri, 25 Feb 2022 00:00:00 -0600 Subject: [PATCH] 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 --- top/top.c | 51 ++++++++++++++++++++++++++++++++++++--------------- top/top.h | 3 ++- top/top_nls.c | 6 ++++++ 3 files changed, 44 insertions(+), 16 deletions(-) diff --git a/top/top.c b/top/top.c index df3019d0..f30ce57f 100644 --- a/top/top.c +++ b/top/top.c @@ -1597,18 +1597,27 @@ end_justifies: /* * 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]; buf[0] = '\0'; if (Rc.zero_suppress && 0 >= num) 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 if (width >= snprintf(buf, sizeof(buf), "%#.3f", num)) goto end_justifies; if (width >= snprintf(buf, sizeof(buf), "%#.2f", num)) goto end_justifies; + (void)xtra; #endif +carry_on: if (width >= snprintf(buf, sizeof(buf), "%#.1f", num)) goto end_justifies; 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 { 5, -1, A_right, PIDS_IO_WRITE_OPS }, // ul_int EU_IWO { 5, -1, A_right, PIDS_AUTOGRP_ID }, // s_int EU_AGI - { 4, -1, A_right, PIDS_AUTOGRP_NICE } // s_int EU_AGN -#define eu_LAST EU_AGN + { 4, -1, A_right, PIDS_AUTOGRP_NICE }, // s_int 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 . . . . . . . #define eu_CMDLINE eu_LAST +1 #define eu_TICS_ALL_C eu_LAST +2 -#define eu_TIME_START eu_LAST +3 -#define eu_ID_FUID eu_LAST +4 -#define eu_TREE_HID eu_LAST +5 -#define eu_TREE_LVL eu_LAST +6 -#define eu_TREE_ADD eu_LAST +7 +#define eu_ID_FUID eu_LAST +3 +#define eu_TREE_HID eu_LAST +4 +#define eu_TREE_LVL eu_LAST +5 +#define eu_TREE_ADD eu_LAST +6 , { -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_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_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 } // 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_right }; @@ -1956,9 +1965,9 @@ static void build_headers (void) { if (!CHKw(w, Show_IDLEPS)) ckITEM(EU_CPU); // with forest view mode, we'll need pid, tgid, ppid & start_time... #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 - 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 // 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); } @@ -4549,7 +4558,7 @@ static void forest_begin (WIN_t *q) { #ifndef TREE_SCANALL 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))); #endif 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; #endif if (u > Cpu_pmax) u = Cpu_pmax; - cp = scale_pcnt(u, W, Jn); + cp = scale_pcnt(u, W, Jn, 0); } 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 */ case EU_GID: // PIDS_ID_EGID 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); 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; /* ul_int, make_str with special handling */ 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); } 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) */ case EU_LXC: // PIDS_LXCNAME case EU_TTY: // PIDS_TTY_NAME diff --git a/top/top.h b/top/top.h index 3e67e493..f008f550 100644 --- a/top/top.h +++ b/top/top.h @@ -202,6 +202,7 @@ enum pflag { EU_RSS, EU_PSS, EU_PZA, EU_PZF, EU_PZS, EU_USS, EU_IRB, EU_IRO, EU_IWB, EU_IWO, EU_AGI, EU_AGN, + EU_TM3, EU_CUU, #ifdef USE_X_COLHDR // not really pflags, used with tbl indexing 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 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_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); /*------ Fields Management support -------------------------------------*/ /*atic struct Fieldstab[] = { ... } */ diff --git a/top/top_nls.c b/top/top_nls.c index 38e1867d..64c9cc5f 100644 --- a/top/top_nls.c +++ b/top/top_nls.c @@ -350,6 +350,12 @@ static void build_two_nlstabs (void) { /* Translation Hint: maximum 'AGNI' = 4 */ Head_nlstab[EU_AGN] = _("AGNI"); 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"); }