[procps] cgroup support for new top

  • From: Jan Görig <jgorig@xxxxxxxxxx>
  • To: procps@xxxxxxxxxxxxx
  • Date: Thu, 07 Apr 2011 11:46:09 +0200

Hi,
I've written cgroup support for Jim's new top. It wasn't straightforward
because top counts only with one resizeable string column (cmdline).

Attached patch includes support for more resizeable columns and cgroup
displaying. It probably needs some tuning because it parses cgroups
array many times while sorting.

I will change procps cgroup interface to avoid this issue if Jim accepts
this patch.

Jim, could you review this patch, please? Thanks.

    Jan
diff --git a/top.c b/top.c
index d275019..84ca410 100644
--- a/top.c
+++ b/top.c
@@ -186,6 +186,44 @@ static int   *PHash_sav = HHash_one,   // alternating 
'old/new' hash tables
              *PHash_new = HHash_two;
 #endif
 
+
+/* creates string from cgroup array */
+void parse_cgroup(char *output, size_t output_size, const proc_t *p, int 
max_len)
+{
+   char *endp = output;
+
+   output[0] = 0;
+
+   if(p->cgroup) {
+      char **pcgroup = p->cgroup;
+
+      while(*pcgroup != NULL) {
+         //Skip root cgroups
+         if(!**pcgroup || (*pcgroup)[strlen(*pcgroup)-1] == '/') {
+           pcgroup++;
+           continue;
+         }
+
+         //Skip initial cgroup number
+         char *ccgroup = strchr(*pcgroup, ':');
+         if(ccgroup == NULL)
+            ccgroup = *pcgroup;
+         else
+            ccgroup++;
+
+         if(endp != output)
+            endp += escape_str(endp, ";", output_size, &max_len);
+
+         endp += escape_str(endp, ccgroup, output_size, &max_len);
+
+         pcgroup++;
+      }
+  }
+
+  if(endp == output)
+    strcpy(output, "-");
+}
+
 /*######  Sort callbacks  ################################################*/
 
         /*
@@ -206,6 +244,17 @@ static int SCB_NAME(CMD) (const proc_t **P, const proc_t 
**Q) {
    // this part also handles the compare if both are kernel threads
    return Frame_srtflg * STRSORTCMP((*Q)->cmd, (*P)->cmd);
 }
+
+static int SCB_NAME(CGR) (const proc_t **P, const proc_t **Q) {
+   char p[ROWBUFSIZ];
+   char q[ROWBUFSIZ];
+
+   parse_cgroup(p, sizeof(p), *P, sizeof(p));
+   parse_cgroup(q, sizeof(q), *Q, sizeof(q));
+
+   return Frame_srtflg * STRSORTCMP(q, p);
+}
+
 SCB_NUM1(COD, trs)
 SCB_NUMx(CPN, processor)
 SCB_NUM1(CPU, pcpu)
@@ -1158,6 +1207,7 @@ static inline int user_matched (WIN_t *q, const proc_t 
*p) {
 #define L_statm    PROC_FILLMEM
 #define L_status   PROC_FILLSTATUS
 #define L_CMDLINE  PROC_FILLARG
+#define L_CGROUP   PROC_FILLCGROUP
 #define L_EUSER    PROC_FILLUSR
 #define L_OUSER    PROC_FILLSTATUS | PROC_FILLUSR
 #define L_EGROUP   PROC_FILLSTATUS | PROC_FILLGRP
@@ -1224,10 +1274,11 @@ static FLD_t Fieldstab[] = {
    { "WCHAN     ",  "%-9.9s ",   -1,     -1,  SF(WCH),  L_stat,    "Sleeping 
in Function" },
    // next entry's special: the 0's will be replaced with '.'!
 #ifdef CASEUP_HEXES
-   { "Flags    ",   "%08lX ",    -1,     -1,  SF(FLG),  L_stat,    "Task Flags 
<sched.h>" }
+   { "Flags    ",   "%08lX ",    -1,     -1,  SF(FLG),  L_stat,    "Task Flags 
<sched.h>" },
 #else
-   { "Flags    ",   "%08lx ",    -1,     -1,  SF(FLG),  L_stat,    "Task Flags 
<sched.h>" }
+   { "Flags    ",   "%08lx ",    -1,     -1,  SF(FLG),  L_stat,    "Task Flags 
<sched.h>" },
 #endif
+   { "CGROUP  ",   "%-*.*s ",    -1,     -1,  SF(CGR),  L_EITHER,  "Control 
Group"        }
  #undef SF
 };
 
@@ -1317,6 +1368,7 @@ static void calibrate_fields (void) {
    int x, hdrmax = 0;
 #endif
    int i, needpsdb = 0;
+   int strcount, divadder = 0;
 
    // block SIGWINCH signals while we do our thing...
    sigemptyset(&newss);
@@ -1360,7 +1412,21 @@ static void calibrate_fields (void) {
             heading via maxcmdln - it may be a fib if P_CMD wasn't encountered,
             but that's ok because it won't be displayed anyway */
          w->maxpflgs = i;
-         w->maxcmdln = Screen_cols - (strlen(w->columnhdr) - 
strlen(Fieldstab[P_CMD].head)) - 1;
+         w->maxcmdln = Screen_cols - strlen(w->columnhdr);
+
+         /* count string format columns */
+         strcount = 0;
+         for (i = 0; i < w->maxpflgs; i++) {
+            if(w->procflgs[i] == P_CMD || w->procflgs[i] == P_CGR) {
+               strcount++;
+               w->maxcmdln += strlen(Fieldstab[w->procflgs[i]].head);
+            }
+         }
+
+         strcount = strcount ? strcount : 1;
+         divadder = w->maxcmdln % strcount;
+         w->maxcmdln = w->maxcmdln/strcount - 1;
+
 
          /* establish the field where all remaining fields would still
             fit within screen width, including a leading window number */
@@ -1373,7 +1439,7 @@ static void calibrate_fields (void) {
             if (Screen_cols < ((int)(s - w->columnhdr) + (int)strlen(h))) 
break;
             s = scat(s, h);
          }
-         w->endpflg = i ? i + 1 : i;
+         w->endpflg = w->maxpflgs ? w->maxpflgs + 1 : w->maxpflgs;
 
          /* finally, we can build the true run-time columns header, format the
             command column heading, if P_CMD is really being displayed, and
@@ -1389,10 +1455,19 @@ static void calibrate_fields (void) {
             if (P_CMD == f) {
                if (CHKw(w, Show_CMDLIN)) Frames_libflags |= L_CMDLINE;
                s = scat(s, fmtmk(Fieldstab[P_CMD].fmts, w->maxcmdln, 
w->maxcmdln, h));
+            } else if (P_CGR == f) {
+               Frames_libflags |= L_CGROUP;
+               s = scat(s, fmtmk(Fieldstab[P_CGR].fmts, w->maxcmdln, 
w->maxcmdln, h));
             } else
                s = scat(s, h);
             Frames_libflags |= Fieldstab[w->procflgs[i]].lflg;
          }
+
+         /* compensate maxcmdln division */
+         if(divadder) {
+            s = scat(s, fmtmk("%*s", divadder, ""));
+            divadder = 0;
+         }
 #ifdef EQUCOLHDRYES
          // prepare to even out column header lengths...
          if (hdrmax < (x = strlen(w->columnhdr))) hdrmax = x;
@@ -3108,6 +3183,12 @@ static void task_show (const WIN_t *q, const proc_t *p) {
             makeCOL(q->maxcmdln, q->maxcmdln, tmp);
          }
             break;
+         case P_CGR:
+         {  char tmp[ROWBUFSIZ];
+            parse_cgroup(tmp, sizeof(tmp), p, q->maxcmdln);
+            makeCOL(q->maxcmdln, q->maxcmdln, tmp);
+         }
+            break;
          case P_COD:
             makeCOL(scale_num(pages2K(p->trs), w, s));
             break;
diff --git a/top.h b/top.h
index e3fb307..0a1e006 100644
--- a/top.h
+++ b/top.h
@@ -126,7 +126,7 @@ enum pflag {
    P_CPN, P_CPU, P_TME, P_TM2,
    P_MEM, P_VRT, P_SWP, P_RES, P_COD, P_DAT, P_SHR,
    P_FL1, P_FL2, P_DRT,
-   P_STA, P_CMD, P_WCH, P_FLG,
+   P_STA, P_CMD, P_WCH, P_FLG, P_CGR,
    // not really pflags, used with tbl indexing & col highlighting
    P_MAXPFLGS, X_XON, X_XOF
 };

Other related posts: