From 59f5a37a247184b3009af963706ca68198067185 Mon Sep 17 00:00:00 2001 From: Jim Warner Date: Fri, 22 May 2020 00:00:00 -0500 Subject: [PATCH] top: add '4' toggle for 2 abreast cpu display, program In the back of my mind, I've always wanted to enable a two abreast cpu display. Folks with massively parallel machines must surely have been frustrated with the '1' toggle when Off (individual cpus in the Summary Area). So, I'll use that recently raised issue shown below as a justification for finally implementing this feature. Reference(s): https://gitlab.com/procps-ng/procps/-/issues/172 Signed-off-by: Jim Warner --- top/top.c | 86 +++++++++++++++++++++++++++++++++++++++------------ top/top.h | 5 ++- top/top_nls.c | 9 +++--- top/top_nls.h | 4 +-- 4 files changed, 78 insertions(+), 26 deletions(-) diff --git a/top/top.c b/top/top.c index 0badd9fe..61b95b04 100644 --- a/top/top.c +++ b/top/top.c @@ -204,6 +204,11 @@ static const char Osel_window_fmts[] = "window #%d, osel_tot=%d\n"; static const char Osel_filterO_fmt[] = "\ttype=%d,\t" OSEL_FILTER "%s\n"; static const char Osel_filterI_fmt[] = "\ttype=%d,\t" OSEL_FILTER "%*s\n"; + /* Support for 2 abreast Cpu display (if terminal is wide enough) */ +static char Double_sp[] = " "; +#define DOUBLE_space (sizeof(Double_sp) - 1) +#define DOUBLE_limit (160 + DOUBLE_space) + /* Support for the new library API -- acquired (if necessary) at program startup and referenced throughout our lifetime. */ /* @@ -1767,6 +1772,11 @@ static void adj_geometry (void) { if (Graph_len >= 0) Graph_len = GRAPH_actual; else if (Screen_cols > 80) Graph_len = Screen_cols - GRAPH_prefix - GRAPH_suffix; else Graph_len = 80 - GRAPH_prefix - GRAPH_suffix; + if (Screen_cols < DOUBLE_limit) Curwin->double_up = 0; + if (Curwin->double_up) { + Graph_len = (Screen_cols - DOUBLE_space - (2 * (GRAPH_prefix + + GRAPH_suffix))) / 2; + if (Graph_len > GRAPH_actual) Graph_len = GRAPH_actual; + } Graph_adj = (float)Graph_len / 100.0; fflush(stdout); @@ -4801,6 +4811,7 @@ static void keys_summary (int ch) { else TOGw(w, View_CPUSUM); OFFw(w, View_CPUNOD); SETw(w, View_STATES); + w->double_up = 0; break; case '2': if (!Numa_node_tot) @@ -4810,6 +4821,7 @@ static void keys_summary (int ch) { if (!CHKw(w, View_CPUNOD)) SETw(w, View_CPUSUM); SETw(w, View_STATES); Numa_node_sel = -1; + w->double_up = 0; } break; case '3': @@ -4822,11 +4834,27 @@ static void keys_summary (int ch) { Numa_node_sel = num; SETw(w, View_CPUNOD | View_STATES); OFFw(w, View_CPUSUM); + w->double_up = 0; } else show_msg(N_txt(NUMA_nodebad_txt)); } } break; + case '4': + w->double_up = !w->double_up; + if (w->double_up && Screen_cols < DOUBLE_limit) { + show_msg(N_txt(XTRA_size2up_txt)); + w->double_up = 0; + break; + } +#ifdef TOG4_NOFORCE + if (CHKw(w, (View_CPUSUM | View_CPUNOD))) + w->double_up = 0; +#else + if (w->double_up) + OFFw(w, (View_CPUSUM | View_CPUNOD)); +#endif + break; case 'C': VIZTOGw(w, View_SCROLL); break; @@ -5241,7 +5269,7 @@ static void do_key (int ch) { , 'I', 'k', 'r', 's', 'X', 'Y', 'Z', '0' , kbd_ENTER, kbd_SPACE, '\0' } }, { keys_summary, - { '1', '2', '3', 'C', 'l', 'm', 't', '\0' } }, + { '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' @@ -5301,6 +5329,31 @@ all_done: } // end: do_key + /* + * 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 char row[ROWMINSIZ]; + static int tog; + char *p; + + p = scat(row, str); + if (nobuf || !Curwin->double_up) + goto flush_it; + if (!tog) { + scat(p, Double_sp); + tog = 1; + return 0; + } +flush_it: + scat(p, "\n"); + show_special(0, row); + row[0] = '\0'; + tog = 0; + return 1; +} // end: sum_cpu + + /* * State display *Helper* function to calc and display the state * percentages for a single cpu. In this way, we can support @@ -5309,11 +5362,12 @@ all_done: * 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 void summary_hlp (struct stat_stack *this, const char *pfx) { +static int summary_hlp (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; float scale; + int n; idl_frme = rSv(stat_IL); tot_frme = rSv(stat_SUM_TOT); @@ -5344,15 +5398,16 @@ static void summary_hlp (struct stat_stack *this, const char *pfx) { 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); - show_special(0, fmtmk("%%%s ~3%#5.1f~2/%-#5.1f~3 %3.0f[~1%-*s]~1\n" - , pfx, pct_user, pct_syst, pct_user + pct_syst, Graph_len +4, dual)); + n = sum_cpu(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 { - show_special(0, fmtmk(Cpu_States_fmts, pfx + n = sum_cpu(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 - , (float)rSv(stat_SI) * scale, (float)rSv(stat_ST) * scale)); + , (float)rSv(stat_SI) * scale, (float)rSv(stat_ST) * scale), nobuf); } + return n; #undef rSv } // end: summary_hlp @@ -5395,16 +5450,14 @@ static void summary_show (void) { if (Numa_node_sel < 0) { numa_oops: // display the 1st /proc/stat line, then the nodes (if room) - summary_hlp(Stat_reap->summary, N_txt(WORD_allcpus_txt)); - Msg_row += 1; + Msg_row += summary_hlp(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)); - summary_hlp(nod_ptr, tmp); - Msg_row += 1; + Msg_row += summary_hlp(nod_ptr, tmp, 1); } } else { // display the node summary, then the associated cpus (if room) @@ -5412,14 +5465,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); - summary_hlp(Stat_reap->nodes->stacks[Numa_node_sel], tmp); - Msg_row += 1; + Msg_row += summary_hlp(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)); - summary_hlp(Stat_reap->cpus->stacks[i], tmp); - Msg_row += 1; + Msg_row += summary_hlp(Stat_reap->cpus->stacks[i], tmp, 1); } } } @@ -5428,15 +5479,12 @@ numa_oops: numa_nope: if (CHKw(w, View_CPUSUM)) { // display just the 1st /proc/stat line - summary_hlp(Stat_reap->summary, N_txt(WORD_allcpus_txt)); - Msg_row += 1; - + Msg_row += summary_hlp(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)); - summary_hlp(Stat_reap->cpus->stacks[i], tmp); - Msg_row += 1; + Msg_row += summary_hlp(Stat_reap->cpus->stacks[i], tmp, (i+1 >= Cpu_cnt)); if (!isROOM(anyFLG, 1)) break; } } diff --git a/top/top.h b/top/top.h index 3245376b..48628503 100644 --- a/top/top.h +++ b/top/top.h @@ -46,6 +46,7 @@ //#define SCROLLVAR_NO /* disable intra-column horizontal scroll */ //#define STRINGCASENO /* case insenstive compare/locate versions */ //#define TERMIOS_ONLY /* just limp along with native input only */ +//#define TOG4_NOFORCE /* no force 2 abreast mode with '4' toggle */ //#define TREE_NORESET /* sort keys do NOT force forest view OFF */ //#define TREE_SCANALL /* rescan array w/ forest view, avoid sort */ //#define TREE_VALTMRK /* use an indented '+' with collapsed pids */ @@ -354,6 +355,7 @@ typedef struct WIN_t { int osel_tot; // total of other selection criteria char *findstr; // window's current/active search string int findlen; // above's strlen, without call overhead + int double_up; // show individual cpus 2 abreast 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,7 +670,8 @@ typedef struct WIN_t { //atic void keys_xtra (int ch); /*------ Main Screen routines ------------------------------------------*/ //atic void do_key (int ch); -//atic void summary_hlp (struct stat_stack *this, const char *pfx); +//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 d5d56357..29856b73 100644 --- a/top/top_nls.c +++ b/top/top_nls.c @@ -506,6 +506,7 @@ static void build_norm_nlstab (void) { Norm_nlstab[LIB_errorpid_fmt] = _("library failed pids statistics, at %d: %s"); 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"); } @@ -555,8 +556,8 @@ static void build_uniq_nlstab (void) { "Window ~1%s~6: ~1Cumulative mode ~3%s~2. ~1System~6: ~1Delay ~3%.1f secs~2; ~1Secure mode ~3%s~2.\n" "\n" " Z~5,~1B~5,E,e Global: '~1Z~2' colors; '~1B~2' bold; '~1E~2'/'~1e~2' summary/task memory scale\n" - " l,t,m Toggle Summary: '~1l~2' load avg; '~1t~2' task/cpu stats; '~1m~2' memory info\n" - " 0,1,2,3,I Toggle: '~10~2' zeros; '~11~2/~12~2/~13~2' cpus or numa node views; '~1I~2' Irix mode\n" + " l,t,m,I Toggle: '~1l~2' load avg; '~1t~2' task/cpu; '~1m~2' memory; '~1I~2' Irix mode\n" + " 0,1,2,3,4 Toggle: '~10~2' zeros; '~11~2/~12~2/~13~2' cpu/numa views; '~14~2' cpus two abreast\n" " f,F,X Fields: '~1f~2'/'~1F~2' add/remove/order/sort; '~1X~2' increase fixed-width\n" "\n" " L,&,<,> . Locate: '~1L~2'/'~1&~2' find/again; Move sort column: '~1<~2'/'~1>~2' left/right\n" @@ -663,13 +664,13 @@ static void build_uniq_nlstab (void) { . us = user, sy = system, ni = nice, id = idle, wa = wait, . hi hardware interrupt, si = software interrupt */ 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\n"); + " %#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" - "%#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\n"); + "%#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 */ Uniq_nlstab[MEMORY_lines_fmt] = _("" diff --git a/top/top_nls.h b/top/top_nls.h index 12ac7773..51cbe193 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_vforest_fmt, XTRA_warncfg_txt, - XTRA_winsize_txt, + XTRA_badflds_fmt, XTRA_fixwide_fmt, 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,