summaryrefslogtreecommitdiff
path: root/top
diff options
context:
space:
mode:
authorJim Warner <james.warner@comcast.net>2020-05-23 08:51:43 -0500
committerCraig Small <csmall@dropbear.xyz>2020-05-28 19:49:40 +1000
commit94d6db6b40bda4a49785855745e86607019df359 (patch)
tree623c036a129ea8b9989c97abf9bb781cb76a5ca6 /top
parent6e5f2c8de695b9330eed88da0a6eb51f57798871 (diff)
downloadprocps-ng-94d6db6b40bda4a49785855745e86607019df359.tar.gz
top: add '!' toggle for combined cpus display, program
When implementing that earlier '4' toggle, in response to the issue referenced below, I got to thinking about those environments with massively parallel processors. Such environments may not benefit from the '4' toggle. So, I decided to implement a feature that could enable use of those '1' and/or '4' toggles no matter how many active processors top may have ultimately encountered. With the new '!' toggle, adjacent cpus can be combined to any degree, represented as a single cpu group/line. Reference(s): https://gitlab.com/procps-ng/procps/-/issues/172 Signed-off-by: Jim Warner <james.warner@comcast.net>
Diffstat (limited to 'top')
-rw-r--r--top/top.c233
-rw-r--r--top/top.h7
-rw-r--r--top/top_nls.c20
-rw-r--r--top/top_nls.h4
4 files changed, 163 insertions, 101 deletions
diff --git a/top/top.c b/top/top.c
index 61b95b0..f59af63 100644
--- a/top/top.c
+++ b/top/top.c
@@ -3991,6 +3991,7 @@ static void win_reset (WIN_t *q) {
// NOHISEL_xxx is redundant (already turned off by osel_clear)
OFFw(q, NOHIFND_xxx | NOHISEL_xxx);
#endif
+ q->combine_cpus = 0;
} // end: win_reset
@@ -4806,6 +4807,15 @@ static void keys_summary (int ch) {
WIN_t *w = Curwin; // avoid gcc bloat with a local copy
switch (ch) {
+ case '!':
+ if (CHKw(w, View_CPUSUM) || CHKw(w, View_CPUNOD))
+ show_msg(N_txt(XTRA_modebad_txt));
+ else {
+ if (!w->combine_cpus) w->combine_cpus = 1;
+ else w->combine_cpus *= 2;
+ if (w->combine_cpus >= Cpu_cnt) w->combine_cpus = 0;
+ }
+ break;
case '1':
if (CHKw(w, View_CPUNOD)) OFFw(w, View_CPUSUM);
else TOGw(w, View_CPUSUM);
@@ -5255,84 +5265,12 @@ static void keys_xtra (int ch) {
// show_msg(fmtmk("%s sort compatibility key honored", xmsg));
} // end: keys_xtra
-/*###### Main Screen routines ##########################################*/
-
- /*
- * Process keyboard input during the main loop */
-static void do_key (int ch) {
- static struct {
- void (*func)(int ch);
- char keys[SMLBUFSIZ];
- } key_tab[] = {
- { keys_global,
- { '?', 'B', 'd', 'E', 'e', 'F', 'f', 'g', 'H', 'h'
- , 'I', 'k', 'r', 's', 'X', 'Y', 'Z', '0'
- , kbd_ENTER, kbd_SPACE, '\0' } },
- { keys_summary,
- { '1', '2', '3', '4', 'C', 'l', 'm', 't', '\0' } },
- { keys_task,
- { '#', '<', '>', 'b', 'c', 'i', 'J', 'j', 'n', 'O', 'o'
- , 'R', 'S', 'U', 'u', 'V', 'v', 'x', 'y', 'z'
- , kbd_CtrlO, '\0' } },
- { keys_window,
- { '+', '-', '=', '_', '&', 'A', 'a', 'G', 'L', 'w'
- , kbd_UP, kbd_DOWN, kbd_LEFT, kbd_RIGHT, kbd_PGUP, kbd_PGDN
- , kbd_HOME, kbd_END, '\0' } },
- { keys_xtra,
- { 'M', 'N', 'P', 'T', '\0'} }
- };
- int i;
-
- switch (ch) {
- case 0: // ignored (always)
- case kbd_ESC: // ignored (sometimes)
- goto all_done;
- case 'q': // no return from this guy
- bye_bye(NULL);
- case 'W': // no need for rebuilds
- write_rcfile();
- goto all_done;
- default: // and now, the real work...
- for (i = 0; i < MAXTBL(key_tab); ++i)
- if (strchr(key_tab[i].keys, ch)) {
- key_tab[i].func(ch);
- Frames_signal = BREAK_kbd;
- goto all_done;
- }
- };
- /* The Frames_signal above will force a rebuild of column headers.
- It's NOT simply lazy programming. Below are some keys that may
- require new column headers and/or new library item enumerators:
- 'A' - likely
- 'c' - likely when !Mode_altscr, maybe when Mode_altscr
- 'F' - likely
- 'f' - likely
- 'g' - likely
- 'H' - likely
- 'I' - likely
- 'J' - always
- 'j' - always
- 'Z' - likely, if 'Curwin' changed when !Mode_altscr
- '-' - likely (restricted to Mode_altscr)
- '_' - likely (restricted to Mode_altscr)
- '=' - maybe, but only when Mode_altscr
- '+' - likely (restricted to Mode_altscr)
- PLUS, likely for FOUR of the EIGHT cursor motion keys (scrolled)
- ( At this point we have a human being involved and so have all the time )
- ( in the world. We can afford a few extra cpu cycles every now & then! )
- */
-
- show_msg(N_txt(UNKNOWN_cmds_txt));
-all_done:
- sysinfo_refresh(1); // let's be more responsive to hot-pluggin'
- putp((Cursor_state = Cap_curs_hide));
-} // end: do_key
-
+/*###### Cpu Display Secondary support (summary_show helpers) ##########*/
/*
* Cpu *Helper* function to combine and or show the state
* percentages for 1 cpu or 2 adjacent cpus (one single line). */
-static inline int sum_cpu (const char *str, int nobuf) {
+static inline int cpu_prt (const char *str, int nobuf) {
static char row[ROWMINSIZ];
static int tog;
char *p;
@@ -5351,7 +5289,7 @@ flush_it:
row[0] = '\0';
tog = 0;
return 1;
-} // end: sum_cpu
+} // end: cpu_prt
/*
@@ -5362,7 +5300,7 @@ flush_it:
* 2) modest smp boxes with room for each cpu's percentages
* 3) massive smp guys leaving little or no room for process
* display and thus requiring the cpu summary toggle */
-static int summary_hlp (struct stat_stack *this, const char *pfx, int nobuf) {
+static int cpu_tics (struct stat_stack *this, const char *pfx, int nobuf) {
// a tailored 'results stack value' extractor macro
#define rSv(E) TIC_VAL(E, this)
SIC_t idl_frme, tot_frme;
@@ -5398,10 +5336,10 @@ static int summary_hlp (struct stat_stack *this, const char *pfx, int nobuf) {
snprintf(syst, sizeof(syst), gtab[ix].syst, (int)((pct_syst * Graph_adj) + .4), gtab[ix].type);
#endif
snprintf(dual, sizeof(dual), "%s%s", user, syst);
- n = sum_cpu(fmtmk("%%%s ~3%#5.1f~2/%-#5.1f~3 %3.0f[~1%-*s]~1"
+ n = cpu_prt(fmtmk("%s ~3%#5.1f~2/%-#5.1f~3 %3.0f[~1%-*s]~1"
, pfx, pct_user, pct_syst, pct_user + pct_syst, Graph_len +4, dual), nobuf);
} else {
- n = sum_cpu(fmtmk(Cpu_States_fmts, pfx
+ n = cpu_prt(fmtmk(Cpu_States_fmts, pfx
, (float)rSv(stat_US) * scale, (float)rSv(stat_SY) * scale
, (float)rSv(stat_NI) * scale, (float)idl_frme * scale
, (float)rSv(stat_IO) * scale, (float)rSv(stat_IR) * scale
@@ -5409,7 +5347,119 @@ static int summary_hlp (struct stat_stack *this, const char *pfx, int nobuf) {
}
return n;
#undef rSv
-} // end: summary_hlp
+} // end: cpu_tics
+
+
+ /*
+ * Cpu *Helper* function to combine adjacent cpu stats
+ * in an effort to reduce total number of processors shown */
+static int cpu_unify (struct stat_stack *this, int nobuf) {
+ // a tailored 'results stack value' extractor macro
+ #define rSv(E,T) STAT_VAL(E, T, this, Stat_ctx)
+ static struct stat_result stack[MAXTBL(Stat_items)];
+ static struct stat_stack accum = { &stack[0] };
+ static int ix, beg;
+ char pfx[16];
+ int n;
+
+ // entries for stat_ID & stat_NU are unused
+ stack[stat_US].result.sl_int += rSv(stat_US, sl_int);
+ stack[stat_SY].result.sl_int += rSv(stat_SY, sl_int);
+ stack[stat_NI].result.sl_int += rSv(stat_NI, sl_int);
+ stack[stat_IL].result.sl_int += rSv(stat_IL, sl_int);
+ stack[stat_IO].result.sl_int += rSv(stat_IO, sl_int);
+ stack[stat_IR].result.sl_int += rSv(stat_IR, sl_int);
+ stack[stat_SI].result.sl_int += rSv(stat_SI, sl_int);
+ stack[stat_ST].result.sl_int += rSv(stat_ST, sl_int);
+ stack[stat_SUM_USR].result.sl_int += rSv(stat_SUM_USR, sl_int);
+ stack[stat_SUM_SYS].result.sl_int += rSv(stat_SUM_SYS, sl_int);
+ stack[stat_SUM_TOT].result.sl_int += rSv(stat_SUM_TOT, sl_int);
+
+ if (!ix) beg = rSv(stat_ID, s_int);
+ if (nobuf || ix >= Curwin->combine_cpus) {
+ snprintf(pfx, sizeof(pfx), "%-7.7s:", fmtmk("%d-%d", beg, rSv(stat_ID, s_int)));
+ n = cpu_tics(&accum, pfx, nobuf);
+ memset(&stack, 0, sizeof(stack));
+ ix = beg = 0;
+ return n;
+ }
+ ++ix;
+ return 0;
+ #undef rSv
+} // end: cpu_unify
+
+/*###### Main Screen routines ##########################################*/
+
+ /*
+ * Process keyboard input during the main loop */
+static void do_key (int ch) {
+ static struct {
+ void (*func)(int ch);
+ char keys[SMLBUFSIZ];
+ } key_tab[] = {
+ { keys_global,
+ { '?', 'B', 'd', 'E', 'e', 'F', 'f', 'g', 'H', 'h'
+ , 'I', 'k', 'r', 's', 'X', 'Y', 'Z', '0'
+ , kbd_ENTER, kbd_SPACE, '\0' } },
+ { keys_summary,
+ { '!', '1', '2', '3', '4', 'C', 'l', 'm', 't', '\0' } },
+ { keys_task,
+ { '#', '<', '>', 'b', 'c', 'i', 'J', 'j', 'n', 'O', 'o'
+ , 'R', 'S', 'U', 'u', 'V', 'v', 'x', 'y', 'z'
+ , kbd_CtrlO, '\0' } },
+ { keys_window,
+ { '+', '-', '=', '_', '&', 'A', 'a', 'G', 'L', 'w'
+ , kbd_UP, kbd_DOWN, kbd_LEFT, kbd_RIGHT, kbd_PGUP, kbd_PGDN
+ , kbd_HOME, kbd_END, '\0' } },
+ { keys_xtra,
+ { 'M', 'N', 'P', 'T', '\0'} }
+ };
+ int i;
+
+ switch (ch) {
+ case 0: // ignored (always)
+ case kbd_ESC: // ignored (sometimes)
+ goto all_done;
+ case 'q': // no return from this guy
+ bye_bye(NULL);
+ case 'W': // no need for rebuilds
+ write_rcfile();
+ goto all_done;
+ default: // and now, the real work...
+ for (i = 0; i < MAXTBL(key_tab); ++i)
+ if (strchr(key_tab[i].keys, ch)) {
+ key_tab[i].func(ch);
+ Frames_signal = BREAK_kbd;
+ goto all_done;
+ }
+ };
+ /* The Frames_signal above will force a rebuild of column headers.
+ It's NOT simply lazy programming. Below are some keys that may
+ require new column headers and/or new library item enumerators:
+ 'A' - likely
+ 'c' - likely when !Mode_altscr, maybe when Mode_altscr
+ 'F' - likely
+ 'f' - likely
+ 'g' - likely
+ 'H' - likely
+ 'I' - likely
+ 'J' - always
+ 'j' - always
+ 'Z' - likely, if 'Curwin' changed when !Mode_altscr
+ '-' - likely (restricted to Mode_altscr)
+ '_' - likely (restricted to Mode_altscr)
+ '=' - maybe, but only when Mode_altscr
+ '+' - likely (restricted to Mode_altscr)
+ PLUS, likely for FOUR of the EIGHT cursor motion keys (scrolled)
+ ( At this point we have a human being involved and so have all the time )
+ ( in the world. We can afford a few extra cpu cycles every now & then! )
+ */
+
+ show_msg(N_txt(UNKNOWN_cmds_txt));
+all_done:
+ sysinfo_refresh(1); // let's be more responsive to hot-pluggin'
+ putp((Cursor_state = Cap_curs_hide));
+} // end: do_key
/*
@@ -5450,14 +5500,14 @@ static void summary_show (void) {
if (Numa_node_sel < 0) {
numa_oops:
// display the 1st /proc/stat line, then the nodes (if room)
- Msg_row += summary_hlp(Stat_reap->summary, N_txt(WORD_allcpus_txt), 1);
+ Msg_row += cpu_tics(Stat_reap->summary, N_txt(WORD_allcpus_txt), 1);
// display each cpu node's states
for (i = 0; i < Numa_node_tot; i++) {
struct stat_stack *nod_ptr = Stat_reap->nodes->stacks[i];
if (NOD_VAL(stat_ID, i) == STAT_NODE_INVALID) continue;
if (!isROOM(anyFLG, 1)) break;
snprintf(tmp, sizeof(tmp), N_fmt(NUMA_nodenam_fmt), NOD_VAL(stat_ID, i));
- Msg_row += summary_hlp(nod_ptr, tmp, 1);
+ Msg_row += cpu_tics(nod_ptr, tmp, 1);
}
} else {
// display the node summary, then the associated cpus (if room)
@@ -5465,12 +5515,12 @@ numa_oops:
if (Numa_node_sel == NOD_VAL(stat_ID, i)) break;
if (i == Numa_node_tot) goto numa_oops;
snprintf(tmp, sizeof(tmp), N_fmt(NUMA_nodenam_fmt), Numa_node_sel);
- Msg_row += summary_hlp(Stat_reap->nodes->stacks[Numa_node_sel], tmp, 1);
+ Msg_row += cpu_tics(Stat_reap->nodes->stacks[Numa_node_sel], tmp, 1);
for (i = 0; i < Cpu_cnt; i++) {
if (Numa_node_sel == CPU_VAL(stat_NU, i)) {
if (!isROOM(anyFLG, 1)) break;
snprintf(tmp, sizeof(tmp), N_fmt(WORD_eachcpu_fmt), CPU_VAL(stat_ID, i));
- Msg_row += summary_hlp(Stat_reap->cpus->stacks[i], tmp, 1);
+ Msg_row += cpu_tics(Stat_reap->cpus->stacks[i], tmp, 1);
}
}
}
@@ -5479,13 +5529,20 @@ numa_oops:
numa_nope:
if (CHKw(w, View_CPUSUM)) {
// display just the 1st /proc/stat line
- Msg_row += summary_hlp(Stat_reap->summary, N_txt(WORD_allcpus_txt), 1);
+ Msg_row += cpu_tics(Stat_reap->summary, N_txt(WORD_allcpus_txt), 1);
} else {
// display each cpu's states separately, screen height permitting...
- for (i = 0; i < Cpu_cnt; i++) {
- snprintf(tmp, sizeof(tmp), N_fmt(WORD_eachcpu_fmt), CPU_VAL(stat_ID, i));
- Msg_row += summary_hlp(Stat_reap->cpus->stacks[i], tmp, (i+1 >= Cpu_cnt));
- if (!isROOM(anyFLG, 1)) break;
+ if (w->combine_cpus) {
+ for (i = 0; i < Cpu_cnt; i++) {
+ Msg_row += cpu_unify(Stat_reap->cpus->stacks[i], (i+1 >= Cpu_cnt));
+ if (!isROOM(anyFLG, 1)) break;
+ }
+ } else {
+ for (i = 0; i < Cpu_cnt; i++) {
+ snprintf(tmp, sizeof(tmp), N_fmt(WORD_eachcpu_fmt), CPU_VAL(stat_ID, i));
+ Msg_row += cpu_tics(Stat_reap->cpus->stacks[i], tmp, (i+1 >= Cpu_cnt));
+ if (!isROOM(anyFLG, 1)) break;
+ }
}
}
} // end: View_STATES
diff --git a/top/top.h b/top/top.h
index 4862850..f0ce564 100644
--- a/top/top.h
+++ b/top/top.h
@@ -356,6 +356,7 @@ typedef struct WIN_t {
char *findstr; // window's current/active search string
int findlen; // above's strlen, without call overhead
int double_up; // show individual cpus 2 abreast
+ int combine_cpus; // keep combining adjacent cpus
struct pids_stack **ppt; // this window's stacks ptr array
struct WIN_t *next, // next window in window stack
*prev; // prior window in window stack
@@ -668,10 +669,12 @@ typedef struct WIN_t {
//atic void keys_task (int ch);
//atic void keys_window (int ch);
//atic void keys_xtra (int ch);
+/*------ Cpu Display Secondary Support (summary_show helpers) ----------*/
+//atic inline int cpu_prt (const char *str, int nobuf);
+//atic int cpu_tics (struct stat_stack *this, const char *pfx, int nobuf);
+//atic int cpu_unify (struct stat_stack *this, int nobuf);
/*------ Main Screen routines ------------------------------------------*/
//atic void do_key (int ch);
-//atic inline int sum_cpu (const char *str, int nobuf);
-//atic int summary_hlp (struct stat_stack *this, const char *pfx, int nobuf);
//atic void summary_show (void);
//atic const char *task_show (const WIN_t *q, struct pids_stack *p);
//atic void window_hlp (void);
diff --git a/top/top_nls.c b/top/top_nls.c
index 29856b7..c69385d 100644
--- a/top/top_nls.c
+++ b/top/top_nls.c
@@ -416,11 +416,11 @@ static void build_norm_nlstab (void) {
Norm_nlstab[WORD_process_txt] = _("Tasks");
/* Translation Hint: The following "word" is meant to represent either a single
. cpu or all of the processors in a multi-processor computer
- . (should be exactly 6 characters, not counting the colon)*/
- Norm_nlstab[WORD_allcpus_txt] = _("Cpu(s):");
+ . (should be exactly 6 characters, excluding leading % & colon) */
+ Norm_nlstab[WORD_allcpus_txt] = _("%Cpu(s):");
/* Translation Hint: The following "word" is meant to represent a single processor
- . (should be exactly 3 characters) */
- Norm_nlstab[WORD_eachcpu_fmt] = _("Cpu%-3d:");
+ . (should be exactly 3 characters, excluding leading %%, fmt chars & colon) */
+ Norm_nlstab[WORD_eachcpu_fmt] = _("%%Cpu%-3d:");
/* Translation Hint: The following word "another" must have 1 trailing space */
Norm_nlstab[WORD_another_txt] = _("another ");
Norm_nlstab[FIND_no_next_txt] = _("Locate next inactive, use \"L\"");
@@ -490,8 +490,9 @@ static void build_norm_nlstab (void) {
Norm_nlstab[WORD_exclude_txt] = _("exclude");
Norm_nlstab[OSEL_statlin_fmt] = _("<Enter> to resume, filters: %s");
Norm_nlstab[WORD_noneone_txt] = _("none");
-/* Translation Hint: The following word 'Node' should be exactly 4 characters */
- Norm_nlstab[NUMA_nodenam_fmt] = _("Node%-2d:");
+/* Translation Hint: The following word 'Node' should be exactly
+ 4 characters, excluding leading %%, fmt chars & colon) */
+ Norm_nlstab[NUMA_nodenam_fmt] = _("%%Node%-2d:");
Norm_nlstab[NUMA_nodeget_fmt] = _("expand which node (0-%d)");
Norm_nlstab[NUMA_nodebad_txt] = _("invalid node");
Norm_nlstab[NUMA_nodenot_txt] = _("sorry, NUMA extensions unavailable");
@@ -507,6 +508,7 @@ static void build_norm_nlstab (void) {
Norm_nlstab[BAD_memscale_fmt] = _("bad memory scaling arg '%c'");
Norm_nlstab[XTRA_vforest_fmt] = _("PID to collapse/expand [default pid = %d]");
Norm_nlstab[XTRA_size2up_txt] = _("terminal is not wide enough");
+ Norm_nlstab[XTRA_modebad_txt] = _("wrong mode, command inactive");
}
@@ -570,7 +572,7 @@ static void build_uniq_nlstab (void) {
" V,v . Toggle: '~1V~2' forest view; '~1v~2' hide/show forest view children\n"
"\n"
"%s"
- " W,Y Write configuration file '~1W~2'; Inspect other output '~1Y~2'\n"
+ " W,Y,! Write config file '~1W~2'; Inspect other output '~1Y~2'; Combine Cpus '~1!~2'\n"
" q Quit\n"
" ( commands shown with '.' require a ~1visible~2 task display ~1window~2 ) \n"
"Press '~1h~2' or '~1?~2' for help with ~1Windows~2,\n"
@@ -663,13 +665,13 @@ static void build_uniq_nlstab (void) {
/* Translation Hint: Only the following abbreviations need be translated
. us = user, sy = system, ni = nice, id = idle, wa = wait,
. hi hardware interrupt, si = software interrupt */
- Uniq_nlstab[STATE_lin2x6_fmt] = _("%%%s~3"
+ Uniq_nlstab[STATE_lin2x6_fmt] = _("%s~3"
" %#5.1f ~2us,~3 %#5.1f ~2sy,~3 %#5.1f ~2ni,~3 %#5.1f ~2id,~3 %#5.1f ~2wa,~3 %#5.1f ~2hi,~3 %#5.1f ~2si~3");
/* Translation Hint: Only the following abbreviations need be translated
. us = user, sy = system, ni = nice, id = idle, wa = wait,
. hi hardware interrupt, si = software interrupt, st = steal time */
- Uniq_nlstab[STATE_lin2x7_fmt] = _("%%%s~3"
+ Uniq_nlstab[STATE_lin2x7_fmt] = _("%s~3"
"%#5.1f ~2us,~3%#5.1f ~2sy,~3%#5.1f ~2ni,~3%#5.1f ~2id,~3%#5.1f ~2wa,~3%#5.1f ~2hi,~3%#5.1f ~2si,~3%#5.1f ~2st~3");
/* Translation Hint: this must be translated as 2 lines with words above & below aligned */
diff --git a/top/top_nls.h b/top/top_nls.h
index 51cbe19..e728b76 100644
--- a/top/top_nls.h
+++ b/top/top_nls.h
@@ -82,8 +82,8 @@ enum norm_nls {
WORD_abv_mem_txt, WORD_abv_swp_txt, WORD_allcpus_txt, WORD_another_txt,
WORD_eachcpu_fmt, WORD_exclude_txt, WORD_include_txt, WORD_noneone_txt,
WORD_process_txt, WORD_threads_txt, WRITE_rcfile_fmt, WRONG_switch_fmt,
- XTRA_badflds_fmt, XTRA_fixwide_fmt, XTRA_size2up_txt, XTRA_vforest_fmt,
- XTRA_warncfg_txt, XTRA_winsize_txt,
+ XTRA_badflds_fmt, XTRA_fixwide_fmt, XTRA_modebad_txt, XTRA_size2up_txt,
+ XTRA_vforest_fmt, XTRA_warncfg_txt, XTRA_winsize_txt,
#ifndef INSP_OFFDEMO
YINSP_demo01_txt, YINSP_demo02_txt, YINSP_demo03_txt, YINSP_deqfmt_txt,
YINSP_deqtyp_txt, YINSP_dstory_txt,