]> granicus.if.org Git - procps-ng/commitdiff
top: provide the means to adjust scaled process memory
authorJim Warner <james.warner@comcast.net>
Fri, 14 Dec 2012 06:00:00 +0000 (00:00 -0600)
committerCraig Small <csmall@enc.com.au>
Sat, 22 Dec 2012 06:07:41 +0000 (17:07 +1100)
This commit is an unrequested outgrowth of the earlier
change dealing with summary area memory field scaling.
That user selectable scaling provision is now extended
to include 6 (at present) task oriented memory fields.

The new companion 'e' (lower case) interactive command
has been added and, like the 'E' command, it can cycle
each of the currently displayed memory columns between
KiB through TiB. There are, however, some differences.

Where '+' indicates summary area truncation at a given
radix, task memory fields are automatically scaled for
their column. Thus, not all rows use the same scaling.

And, while summary area field widths were not changed,
the task memory columns were widened in order to offer
more meaningful data when the radix was increased. The
precision is automatically increased in step with each
radix: MiB displays 2 decimal places, GiB 3 and TiB 4.

To compliment that additional precision, both the %CPU
and %MEM fields were widened by 1 column and now offer
precision up to 3 decimal places. But, unique to %CPU,
widening could already have occurred due to the number
of processors in some massively parallel boxes. At any
rate, total extra width for both memory and percentage
fields could amount to twenty (precious) columns more.

So for both the memory and % fields the original width
(along with loss of precision) can be restored via new
compiler conditionals which this commit also provides.

p.s. and it will be rcfile preserved for any restarts!

(now that we know a '.' + 2 spaces is squeezed to one)
(everything's perfectly justified, but it's just luck)

Reference(s):
http://www.freelists.org/post/procps/top-regression-reports

Signed-off-by: Jim Warner <james.warner@comcast.net>
top/top.1
top/top.c
top/top.h
top/top_nls.c

index 0ba5bed4cbe54fbe44613048e826da72b350c753..e6ab28cd8e1e9a4e2a2b17ce0cfccd84e20869d3 100644 (file)
--- a/top/top.1
+++ b/top/top.1
@@ -446,6 +446,10 @@ are sorted high-to-low or low-to-high.
 For additional information on sort provisions
 \*(Xt 4c. TASK AREA Commands, SORTING.
 
+The fields related to \*(MP or \*(MV reference '(KiB)' as the default,
+unsuffixed display mode.
+Such fields can, however, be scaled differently via the 'e' \*(CI.
+
 .TP 4
  1.\fB %CPU \*(Em \*(PU Usage \fR
 The task's share of the elapsed \*(PU time since the last screen update,
@@ -938,6 +942,17 @@ If you see a '+' between a displayed number and the following label, it
 means that \*(We was forced to truncate some portion of that number.
 By raising the scaling factor, such truncation can usually be avoided.
 
+.TP 7
+\ \ \'\fBe\fR\' :\fIExtend-Memory-Scale\fR in Task Windows
+With this command you can cycle through the available \*(TW memory scaling
+which ranges from KiB (kibibytes or 1,024 bytes) through TiB (tebibytes or
+1,099,511,627,776 bytes).
+
+While \*(We will try to honor the selected target range, additional
+scaling might still be necessary in order to accommodate current values.
+If you wish to see a more homogeneous result in the memory columns,
+raising the scaling range will usually accomplish that goal.
+
 .TP 7
 \ \ \'\fBg\fR\' :\fIChoose-Another-Window/Field-Group \fR
 You will be prompted to enter a number between 1 and 4 designating the
index 655bf0c290ff2c86a621c86db2084c4ddee8b27f..204a678307c4ce2b9117372f70915a5f280fdbef 100644 (file)
--- a/top/top.c
+++ b/top/top.c
@@ -198,6 +198,13 @@ static int Autox_array [P_MAXPFLGS],
 #define AUTOX_NO      P_MAXPFLGS
 #define AUTOX_COL(f)  if (P_MAXPFLGS > f) Autox_array[f] = Autox_found = 1
 #define AUTOX_MODE   (0 > Rc.fixed_widest)
+
+        /* Support for scale_mem and scale_num (to avoid duplication. */
+#ifdef CASEUP_SUFIX
+   static char Scaled_sfxtab[] =  { 'K', 'M', 'G', 'T', 0 };
+#else
+   static char Scaled_sfxtab[] =  { 'k', 'm', 'g', 't', 0 };
+#endif
 \f
 /*######  Sort callbacks  ################################################*/
 
@@ -1252,12 +1259,78 @@ static inline const char *make_str (const char *str, int width, int justr, int c
 } // end: make_str
 
 
+        /*
+         * Do some scaling then justify stuff.
+         * We'll interpret 'num' as a kibibytes quantity and try to
+         * format it to reach 'target' while also fitting 'width'. */
+static const char *scale_mem (int target, unsigned long num, int width, int justr) {
+#ifndef NOBOOST_MEMS
+   static const char *fmttab[] =  { "%.0f", "%#.2f%c", "%#.3f%c", "%#.4f%c", NULL };
+#else
+   static const char *fmttab[] =  { "%.0f", "%.0f%c", "%.0f%c", "%.0f%c", NULL };
+#endif
+   static char buf[SMLBUFSIZ];
+   float scaled_num;
+   char *psfx;
+   int i;
+
+   buf[0] = '\0';
+   if (Rc.zero_suppress && 0 >= num)
+      goto end_justifies;
+
+   scaled_num = num;
+   for (i = 0, psfx = Scaled_sfxtab; 0 < *psfx; psfx++, i++) {
+      if (i >= target
+      && (width >= snprintf(buf, sizeof(buf), fmttab[i], scaled_num, *psfx)))
+         goto end_justifies;
+      scaled_num /= 1024.0;
+   }
+
+   // well shoot, this outta' fit...
+   snprintf(buf, sizeof(buf), "?");
+end_justifies:
+   return justify_pad(buf, width, justr);
+} // end: scale_mem
+
+
+        /*
+         * Do some scaling then justify stuff. */
+static const char *scale_num (unsigned long num, int width, int justr) {
+   static char buf[SMLBUFSIZ];
+   float scaled_num;
+   char *psfx;
+
+   buf[0] = '\0';
+   if (Rc.zero_suppress && 0 >= num)
+      goto end_justifies;
+   if (width >= snprintf(buf, sizeof(buf), "%lu", num))
+      goto end_justifies;
+
+   scaled_num = num;
+   for (psfx = Scaled_sfxtab; 0 < *psfx; psfx++) {
+      scaled_num /= 1024.0;
+      if (width >= snprintf(buf, sizeof(buf), "%.1f%c", scaled_num, *psfx))
+         goto end_justifies;
+      if (width >= snprintf(buf, sizeof(buf), "%.0f%c", scaled_num, *psfx))
+         goto end_justifies;
+   }
+
+   // well shoot, this outta' fit...
+   snprintf(buf, sizeof(buf), "?");
+end_justifies:
+   return justify_pad(buf, width, justr);
+} // end: scale_num
+
+
         /*
          * Make and then justify a percentage, with decreasing precision. */
-static inline const char *scale_pcnt (float num, int width, int justr) {
+static const char *scale_pcnt (float num, int width, int justr) {
    static char buf[SMLBUFSIZ];
 
-#ifdef PERCENTBOOST
+   buf[0] = '\0';
+   if (Rc.zero_suppress && 0 >= num)
+      goto end_justifies;
+#ifndef NOBOOST_PCNT
    if (width >= snprintf(buf, sizeof(buf), "%#.3f", num))
       goto end_justifies;
    if (width >= snprintf(buf, sizeof(buf), "%#.2f", num))
@@ -1293,7 +1366,10 @@ static const char *scale_tics (TIC_t tics, int width, int justr) {
    unsigned cc;         // centiseconds
    unsigned nn;         // multi-purpose whatever
 
+   buf[0] = '\0';
    nt  = (tics * 100ull) / Hertz;               // up to 68 weeks of cpu time
+   if (Rc.zero_suppress && 0 >= nt)
+      goto end_justifies;
    cc  = nt % 100;                              // centiseconds past second
    nt /= 100;                                   // total seconds
    nn  = nt % 60;                               // seconds past the minute
@@ -1324,49 +1400,6 @@ end_justifies:
  #undef DD
  #undef WW
 } // end: scale_tics
-
-
-        /*
-         * Do some scaling then justify stuff.
-         * We'll interpret 'num' as one of the following types and
-         * try to format it to fit 'width'.
-         *    SK_no (0) it's a byte count
-         *    SK_Kb (1) it's kilobytes
-         *    SK_Mb (2) it's megabytes
-         *    SK_Gb (3) it's gigabytes
-         *    SK_Tb (4) it's terabytes  */
-static const char *scale_unum (unsigned long num, int type, int width, int justr) {
-      // kilobytes, megabytes, gigabytes, terabytes, duh!
-   static double scale[] = { 1024.0, 1024.0*1024, 1024.0*1024*1024, 1024.0*1024*1024*1024, 0 };
-      // kilo, mega, giga, tera, none
-#ifdef CASEUP_SUFIX
-   static char nextup[] =  { 'K', 'M', 'G', 'T', 0 };
-#else
-   static char nextup[] =  { 'k', 'm', 'g', 't', 0 };
-#endif
-   static char buf[SMLBUFSIZ];
-   double *dp;
-   char *up;
-
-   // try an unscaled version first...
-   if (width >= snprintf(buf, sizeof(buf), "%lu", num))
-      goto end_justifies;
-
-   // now try successively higher types until it fits
-   for (up = nextup + type, dp = scale; 0 < *dp; ++dp, ++up) {
-      // the most accurate version
-      if (width >= snprintf(buf, sizeof(buf), "%.1f%c", num / *dp, *up))
-         goto end_justifies;
-      // the integer version
-      if (width >= snprintf(buf, sizeof(buf), "%lu%c", (unsigned long)(num / *dp), *up))
-         goto end_justifies;
-   }
-
-   // well shoot, this outta' fit...
-   snprintf(buf, sizeof(buf), "?");
-end_justifies:
-   return justify_pad(buf, width, justr);
-} // end: scale_unum
 \f
 /*######  Fields Management support  #####################################*/
 
@@ -1431,20 +1464,29 @@ static FLD_t Fieldstab[] = {
    {     0,     -1,  A_right,  SF(CPU),  L_stat    },
    {     6,     -1,  A_right,  SF(TME),  L_stat    },
    {     9,     -1,  A_right,  SF(TME),  L_stat    }, // P_TM2 slot
-#ifdef PERCENTBOOST
+#ifndef NOBOOST_PCNT
    {     5,     -1,  A_right,  SF(RES),  L_statm   }, // P_MEM slot
 #else
    {     4,     -1,  A_right,  SF(RES),  L_statm   }, // P_MEM slot
 #endif
+#ifndef NOBOOST_MEMS
+   {     8,  SK_Kb,  A_right,  SF(VRT),  L_statm   },
+   {     7,  SK_Kb,  A_right,  SF(SWP),  L_status  },
+   {     7,  SK_Kb,  A_right,  SF(RES),  L_statm   },
+   {     7,  SK_Kb,  A_right,  SF(COD),  L_statm   },
+   {     7,  SK_Kb,  A_right,  SF(DAT),  L_statm   },
+   {     7,  SK_Kb,  A_right,  SF(SHR),  L_statm   },
+#else
    {     5,  SK_Kb,  A_right,  SF(VRT),  L_statm   },
    {     4,  SK_Kb,  A_right,  SF(SWP),  L_status  },
    {     4,  SK_Kb,  A_right,  SF(RES),  L_statm   },
    {     4,  SK_Kb,  A_right,  SF(COD),  L_statm   },
    {     4,  SK_Kb,  A_right,  SF(DAT),  L_statm   },
    {     4,  SK_Kb,  A_right,  SF(SHR),  L_statm   },
-   {     4,  SK_no,  A_right,  SF(FL1),  L_stat    },
-   {     4,  SK_no,  A_right,  SF(FL2),  L_stat    },
-   {     4,  SK_no,  A_right,  SF(DRT),  L_statm   },
+#endif
+   {     4,     -1,  A_right,  SF(FL1),  L_stat    },
+   {     4,     -1,  A_right,  SF(FL2),  L_stat    },
+   {     4,     -1,  A_right,  SF(DRT),  L_statm   },
    {     1,     -1,  A_right,  SF(STA),  L_EITHER  },
    {    -1,     -1,  A_left,   SF(CMD),  L_EITHER  },
    {    10,     -1,  A_left,   SF(WCH),  L_stat    },
@@ -1460,8 +1502,8 @@ static FLD_t Fieldstab[] = {
 #undef L_oom
 #endif
    {    -1,     -1,  A_left,   SF(ENV),  L_ENVIRON },
-   {     3,  SK_no,  A_right,  SF(FV1),  L_stat    },
-   {     3,  SK_no,  A_right,  SF(FV2),  L_stat    }
+   {     3,     -1,  A_right,  SF(FV1),  L_stat    },
+   {     3,     -1,  A_right,  SF(FV2),  L_stat    }
  #undef SF
  #undef A_left
  #undef A_right
@@ -1947,7 +1989,7 @@ static void zap_fieldstab (void) {
       Fieldstab[P_CPN].width = digits;
    }
 
-#ifdef PERCENTBOOST
+#ifndef NOBOOST_PCNT
    Cpu_pmax = 99.9;
    Fieldstab[P_CPU].width = 5;
    if (Rc.mode_irixps && smp_num_cpus > 1 && !Thread_mode) {
@@ -1986,6 +2028,12 @@ static void zap_fieldstab (void) {
          = Rc.fixed_widest ? 10 + Rc.fixed_widest : 10;
    }
 
+   /* plus user selectable scaling */
+   Fieldstab[P_VRT].scale = Fieldstab[P_SWP].scale
+      = Fieldstab[P_RES].scale = Fieldstab[P_COD].scale
+      = Fieldstab[P_DAT].scale = Fieldstab[P_SHR].scale
+      = Rc.task_mscale;
+
    // lastly, ensure we've got proper column headers...
    calibrate_fields();
 } // end: zap_fieldstab
@@ -3065,7 +3113,8 @@ static void configs_read (void) {
       } // end: for (GROUPSMAX)
 
       // any new addition(s) last, for older rcfiles compatibility...
-      fscanf(fp, "Fixed_widest=%d, Summ_mscale=%d\n", &Rc.fixed_widest, &Rc.summ_mscale);
+      fscanf(fp, "Fixed_widest=%d, Summ_mscale=%d, Task_mscale=%d\n"
+         , &Rc.fixed_widest, &Rc.summ_mscale, &Rc.task_mscale);
 
 try_inspect_entries:
 
@@ -3653,7 +3702,8 @@ static void file_writerc (void) {
    }
 
    // any new addition(s) last, for older rcfiles compatibility...
-   fprintf(fp, "Fixed_widest=%d, Summ_mscale=%d\n", Rc.fixed_widest, Rc.summ_mscale);
+   fprintf(fp, "Fixed_widest=%d, Summ_mscale=%d, Task_mscale=%d\n"
+      , Rc.fixed_widest, Rc.summ_mscale, Rc.task_mscale);
 
    if (Inspect.raw)
       fputs(Inspect.raw, fp);
@@ -3770,8 +3820,10 @@ static void keys_global (int ch) {
          }
          break;
       case 'E':
-         // current summary_show limits: 0 == kilo through 3 == tera
-         if (++Rc.summ_mscale > 3) Rc.summ_mscale = 0;
+         if (++Rc.summ_mscale >= SK_SENTINEL) Rc.summ_mscale = SK_Kb;
+         break;
+      case 'e':
+         if (++Rc.task_mscale >= SK_SENTINEL) Rc.task_mscale = SK_Kb;
          break;
       case 'F':
       case 'f':
@@ -4311,7 +4363,8 @@ static void do_key (int ch) {
       char keys[SMLBUFSIZ];
    } key_tab[] = {
       { keys_global,
-         { '?', 'B', 'd', 'E', 'F', 'f', 'g', 'H', 'h', 'I', 'k', 'r', 's', 'X', 'Y', 'Z'
+         { '?', 'B', 'd', 'E', 'e', 'F', 'f', 'g', 'H', 'h'
+         , 'I', 'k', 'r', 's', 'X', 'Y', 'Z'
          , kbd_ENTER, kbd_SPACE, '\0' } },
       { keys_summary,
          { '1', 'C', 'l', 'm', 't', '\0' } },
@@ -4562,7 +4615,7 @@ static const char *task_show (const WIN_t *q, const proc_t *p) {
             makeVAR(forest_display(q, p));
             break;
          case P_COD:
-            cp = scale_unum(pages2K(p->trs), S, W, Jn);
+            cp = scale_mem(S, pages2K(p->trs), W, Jn);
             break;
          case P_CPN:
             cp = make_num(p->processor, W, Jn, AUTOX_NO);
@@ -4574,10 +4627,10 @@ static const char *task_show (const WIN_t *q, const proc_t *p) {
          }
             break;
          case P_DAT:
-            cp = scale_unum(pages2K(p->drs), S, W, Jn);
+            cp = scale_mem(S, pages2K(p->drs), W, Jn);
             break;
          case P_DRT:
-            cp = scale_unum(p->dt, S, W, Jn);
+            cp = scale_num(p->dt, W, Jn);
             break;
          case P_ENV:
             makeVAR(p->environ[0]);
@@ -4586,16 +4639,16 @@ static const char *task_show (const WIN_t *q, const proc_t *p) {
             cp = make_str(hex_make(p->flags, 1), W, Js, AUTOX_NO);
             break;
          case P_FL1:
-            cp = scale_unum(p->maj_flt, S, W, Jn);
+            cp = scale_num(p->maj_flt, W, Jn);
             break;
          case P_FL2:
-            cp = scale_unum(p->min_flt, S, W, Jn);
+            cp = scale_num(p->min_flt, W, Jn);
             break;
          case P_FV1:
-            cp = scale_unum(p->maj_delta, S, W, Jn);
+            cp = scale_num(p->maj_delta, W, Jn);
             break;
          case P_FV2:
-            cp = scale_unum(p->min_delta, S, W, Jn);
+            cp = scale_num(p->min_delta, W, Jn);
             break;
          case P_GID:
             cp = make_num(p->egid, W, Jn, P_GID);
@@ -4633,7 +4686,7 @@ static const char *task_show (const WIN_t *q, const proc_t *p) {
                cp = make_num(p->priority, W, Jn, AUTOX_NO);
             break;
          case P_RES:
-            cp = scale_unum(pages2K(p->resident), S, W, Jn);
+            cp = scale_mem(S, pages2K(p->resident), W, Jn);
             break;
          case P_SGD:
             makeVAR(p->supgid);
@@ -4642,7 +4695,7 @@ static const char *task_show (const WIN_t *q, const proc_t *p) {
             makeVAR(p->supgrp);
             break;
          case P_SHR:
-            cp = scale_unum(pages2K(p->share), S, W, Jn);
+            cp = scale_mem(S, pages2K(p->share), W, Jn);
             break;
          case P_SID:
             cp = make_num(p->session, W, Jn, AUTOX_NO);
@@ -4651,7 +4704,7 @@ static const char *task_show (const WIN_t *q, const proc_t *p) {
             cp = make_chr(p->state, W, Js);
             break;
          case P_SWP:
-            cp = scale_unum(p->vm_swap, S, W, Jn);
+            cp = scale_mem(S, p->vm_swap, W, Jn);
             break;
          case P_TGD:
             cp = make_num(p->tgid, W, Jn, AUTOX_NO);
@@ -4694,7 +4747,7 @@ static const char *task_show (const WIN_t *q, const proc_t *p) {
             cp = make_str(p->suser, W, Js, P_USN);
             break;
          case P_VRT:
-            cp = scale_unum(pages2K(p->size), S, W, Jn);
+            cp = scale_mem(S, pages2K(p->size), W, Jn);
             break;
          case P_WCH:
          {  const char *u;
index be5bdfc6edfe4c227c6614c4e8cf5b890da7a479..4eb58ad42319a2a95e19b5428f3dba3daaf3333d 100644 (file)
--- a/top/top.h
+++ b/top/top.h
 //#define INSP_OFFDEMO            /* disable demo screens, issue msg instead */
 //#define INSP_SAVEBUF            /* preserve 'Insp_buf' contents in a file  */
 //#define INSP_SLIDE_1            /* when scrolling left/right don't move 8  */
+//#define NOBOOST_MEMS            /* disable extra precision for mem fields  */
+//#define NOBOOST_PCNT            /* disable extra precision for % fields    */
 //#define OFF_HST_HASH            /* use BOTH qsort+bsrch vs. hashing scheme */
 //#define OFF_STDIOLBF            /* disable our own stdout _IOFBF override  */
-//#define PERCENTBOOST            /* enable extended precision for % fields  */
 //#define PRETEND2_5_X            /* pretend we're linux 2.5.x (for IO-wait) */
 //#define PRETEND4CPUS            /* pretend we're smp with 4 ticsers (sic)  */
 //#define PRETENDNOCAP            /* use a terminal without essential caps   */
@@ -191,10 +192,9 @@ enum pflag {
 #endif
 };
 
-        /* The scaling 'type' used with scale_unum() -- this is how
-           the passed number is interpreted should scaling be necessary */
-enum scale_unum {
-   SK_no, SK_Kb, SK_Mb, SK_Gb, SK_Tb
+        /* The scaling 'target' used with memory fields */
+enum scale_enum {
+   SK_Kb, SK_Mb, SK_Gb, SK_Tb, SK_SENTINEL
 };
 
         /* This typedef just ensures consistent 'process flags' handling */
@@ -211,7 +211,7 @@ typedef int (*QFP_t)(const void *, const void *);
            in a variety of display roles. */
 typedef struct FLD_t {
    int           width;         // field width, if applicable
-   const int     scale;         // scale_unum type, if applicable
+   int           scale;         // scaled target, if applicable
    const int     align;         // the default column alignment flag
    const QFP_t   sort;          // sort function
    const int     lflg;          // PROC_FILLxxx flag(s) needed by this field
@@ -337,6 +337,8 @@ typedef struct RCF_t {
    RCW_t  win [GROUPSMAX];      // a 'WIN_t.rc' for each window
    int    fixed_widest;         // 'X' - wider non-scalable col addition
    int    summ_mscale;          // 'E' - scaling of summary memory values
+   int    task_mscale;          // 'e' - scaling of process memory values
+   int    zero_suppress;        // '0' - suppress scaled zeros toggle
 } RCF_t;
 
         /* This structure stores configurable information for each window.
@@ -635,9 +637,10 @@ typedef struct WIN_t {
 //atic inline const char *make_chr (const char ch, int width, int justr);
 //atic inline const char *make_num (long num, int width, int justr, int col);
 //atic inline const char *make_str (const char *str, int width, int justr, int col);
-//atic inline const char *scale_pcnt (float num, int width, int justr);
+//atic const char   *scale_mem (int target, unsigned long num, int width, int justr);
+//atic const char   *scale_num (unsigned long num, int width, int justr);
+//atic const char   *scale_pcnt (float num, int width, int justr);
 //atic const char   *scale_tics (TIC_t tics, int width, int justr);
-//atic const char   *scale_unum (unsigned long num, int type, int width, int justr);
 /*------  Fields Management support  -------------------------------------*/
 /*atic FLD_t         Fieldstab[] = { ... }                                */
 //atic void          adj_geometry (void);
index fa08928b4fba30290a74b73f89af32e9ab594a89..66dfeeb246b42a35d282158319c39841944cbd2c 100644 (file)
@@ -458,7 +458,7 @@ static void build_uniq_nlstab (void) {
       "Help for Interactive Commands~2 - %s\n"
       "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     Global: '~1Z~2' color mappings; '~1B~2' bold; '~1E~2' summary mem scale\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 Summaries: '~1l~2' load avg; '~1t~2' task/cpu stats; '~1m~2' mem info\n"
       "  1,I       Toggle SMP view: '~11~2' single/separate states; '~1I~2' Irix/Solaris mode\n"
       "  f,F,X     Fields: '~1f~2'/'~1F~2' add/remove/order/sort; '~1X~2' increase fixed-width\n"