]> granicus.if.org Git - procps-ng/commitdiff
top: add '4' toggle for 2 abreast cpu display, program
authorJim Warner <james.warner@comcast.net>
Wed, 13 May 2020 05:00:00 +0000 (00:00 -0500)
committerCraig Small <csmall@dropbear.xyz>
Thu, 28 May 2020 09:37:58 +0000 (19:37 +1000)
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 <james.warner@comcast.net>
top/top.c
top/top.h
top/top_nls.c
top/top_nls.h

index a99820a2715d69141628e7bb4adf7e8712cf8600..ff701861247ba11893fa9a78ec301a9e3b0dc208 100644 (file)
--- a/top/top.c
+++ b/top/top.c
@@ -233,6 +233,11 @@ static const char Osel_window_fmts[] = "window #%d, osel_tot=%d\n";
 #define OSEL_FILTER   "filter="
 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)
 \f
 /*######  Sort callbacks  ################################################*/
 
@@ -1940,6 +1945,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);
@@ -5219,6 +5229,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)
@@ -5228,6 +5239,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':
@@ -5240,11 +5252,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;
@@ -5659,7 +5687,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'
@@ -5719,6 +5747,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
@@ -5727,7 +5780,7 @@ 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 (CPU_t *cpu, const char *pfx) {
+static int summary_hlp (CPU_t *cpu, const char *pfx, int nobuf) {
    /* we'll trim to zero if we get negative time ticks,
       which has happened with some SMP kernels (pre-2.4?)
       and when cpus are dynamically added or removed */
@@ -5735,6 +5788,7 @@ static void summary_hlp (CPU_t *cpu, const char *pfx) {
    //    user    syst    nice    idle    wait    hirg    sirq    steal
    SIC_t u_frme, s_frme, n_frme, i_frme, w_frme, x_frme, y_frme, z_frme, tot_frme, tz;
    float scale;
+   int n;
 
    u_frme = TRIMz(cpu->cur.u - cpu->sav.u);
    s_frme = TRIMz(cpu->cur.s - cpu->sav.s);
@@ -5776,15 +5830,16 @@ static void summary_hlp (CPU_t *cpu, 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)u_frme * scale, (float)s_frme * scale
          , (float)n_frme * scale, (float)i_frme * scale
          , (float)w_frme * scale, (float)x_frme * scale
-         , (float)y_frme * scale, (float)z_frme * scale));
+         , (float)y_frme * scale, (float)z_frme * scale), nobuf);
    }
+   return n;
  #undef TRIMz
 } // end: summary_hlp
 
@@ -5826,8 +5881,7 @@ static void summary_show (void) {
       if (CHKw(w, View_CPUNOD)) {
          if (Numa_node_sel < 0) {
             // display the 1st /proc/stat line, then the nodes (if room)
-            summary_hlp(&Cpu_tics[smp_num_cpus], N_txt(WORD_allcpus_txt));
-            Msg_row += 1;
+            Msg_row += summary_hlp(&Cpu_tics[smp_num_cpus], N_txt(WORD_allcpus_txt), 1);
             // display each cpu node's states
             for (i = 0; i < Numa_node_tot; i++) {
                CPU_t *nod_ptr = &Cpu_tics[1 + smp_num_cpus + i];
@@ -5836,8 +5890,7 @@ static void summary_show (void) {
                if (nod_ptr->id) {
 #endif
                snprintf(tmp, sizeof(tmp), N_fmt(NUMA_nodenam_fmt), i);
-               summary_hlp(nod_ptr, tmp);
-               Msg_row += 1;
+               Msg_row += summary_hlp(nod_ptr, tmp, 1);
 #ifndef OFF_NUMASKIP
                }
 #endif
@@ -5845,14 +5898,12 @@ static void summary_show (void) {
          } else {
             // display the node summary, then the associated cpus (if room)
             snprintf(tmp, sizeof(tmp), N_fmt(NUMA_nodenam_fmt), Numa_node_sel);
-            summary_hlp(&Cpu_tics[1 + smp_num_cpus + Numa_node_sel], tmp);
-            Msg_row += 1;
+            Msg_row += summary_hlp(&Cpu_tics[1 + smp_num_cpus + Numa_node_sel], tmp, 1);
             for (i = 0; i < Cpu_faux_tot; i++) {
                if (Numa_node_sel == Cpu_tics[i].node) {
                   if (!isROOM(anyFLG, 1)) break;
                   snprintf(tmp, sizeof(tmp), N_fmt(WORD_eachcpu_fmt), Cpu_tics[i].id);
-                  summary_hlp(&Cpu_tics[i], tmp);
-                  Msg_row += 1;
+                  Msg_row += summary_hlp(&Cpu_tics[i], tmp, 1);
                }
             }
          }
@@ -5860,15 +5911,12 @@ static void summary_show (void) {
 numa_nope:
       if (CHKw(w, View_CPUSUM)) {
          // display just the 1st /proc/stat line
-         summary_hlp(&Cpu_tics[smp_num_cpus], N_txt(WORD_allcpus_txt));
-         Msg_row += 1;
-
+         Msg_row += summary_hlp(&Cpu_tics[smp_num_cpus], N_txt(WORD_allcpus_txt), 1);
       } else {
          // display each cpu's states separately, screen height permitting...
          for (i = 0; i < Cpu_faux_tot; i++) {
             snprintf(tmp, sizeof(tmp), N_fmt(WORD_eachcpu_fmt), Cpu_tics[i].id);
-            summary_hlp(&Cpu_tics[i], tmp);
-            Msg_row += 1;
+            Msg_row += summary_hlp(&Cpu_tics[i], tmp, (i+1 >= Cpu_faux_tot));
             if (!isROOM(anyFLG, 1)) break;
          }
       }
index 35fc7745b2d754a78769befc834910c9ad539ce8..1f36957d0a7c71aa6f62609823a169782f259a8b 100644 (file)
--- a/top/top.h
+++ b/top/top.h
@@ -54,6 +54,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 */
@@ -435,6 +436,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
    proc_t **ppt;                       // this window's proc_t ptr array
    struct WIN_t *next,                 // next window in window stack
                 *prev;                 // prior window in window stack
@@ -804,7 +806,8 @@ typedef struct WIN_t {
 //atic void          keys_xtra (int ch);
 /*------  Main Screen routines  ------------------------------------------*/
 //atic void          do_key (int ch);
-//atic void          summary_hlp (CPU_t *cpu, const char *pfx);
+//atic inline int    sum_cpu (const char *str, int nobuf);
+//atic int           summary_hlp (CPU_t *cpu, const char *pfx, int nobuf);
 //atic void          summary_show (void);
 //atic const char   *task_show (const WIN_t *q, const int idx);
 //atic void          window_hlp (void);
index 2be00a9ed3c9f0cc96592699fceadeef1836c958..32f9a569f0873b64829ea52ef1a1a7b25c82b3dc 100644 (file)
@@ -500,6 +500,7 @@ static void build_norm_nlstab (void) {
    Norm_nlstab[WORD_abv_swp_txt] = _("Swap");
    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");
 }
 
 
@@ -549,8 +550,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"
@@ -654,22 +655,22 @@ static void build_uniq_nlstab (void) {
       " %3u ~2total,~3 %3u ~2running,~3 %3u ~2sleeping,~3 %3u ~2stopped,~3 %3u ~2zombie~3\n");
 
    Uniq_nlstab[STATE_lin2x4_fmt] = _("%%%s~3"
-      " %#5.1f  ~2user,~3 %#5.1f  ~2system,~3 %#5.1f  ~2nice,~3 %#5.1f  ~2idle~3\n");
+      " %#5.1f  ~2user,~3 %#5.1f  ~2system,~3 %#5.1f  ~2nice,~3 %#5.1f  ~2idle~3");
 
    Uniq_nlstab[STATE_lin2x5_fmt] = _("%%%s~3"
-      " %#5.1f  ~2user,~3 %#5.1f  ~2system,~3 %#5.1f  ~2nice,~3 %#5.1f  ~2idle,~3 %#5.1f  ~2IO-wait~3\n");
+      " %#5.1f  ~2user,~3 %#5.1f  ~2system,~3 %#5.1f  ~2nice,~3 %#5.1f  ~2idle,~3 %#5.1f  ~2IO-wait~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 */
    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] = _(""
index 9148c12b7d9caf63e34875a683f189f721746720..cf5207de25f40f5304f6a6402f29307396cbec50 100644 (file)
@@ -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,