]> granicus.if.org Git - procps-ng/commitdiff
slabtop: adapted to exploit new alloc & sort interface
authorJim Warner <james.warner@comcast.net>
Sat, 11 Jul 2015 05:00:00 +0000 (00:00 -0500)
committerCraig Small <csmall@enc.com.au>
Tue, 14 Jul 2015 12:36:48 +0000 (22:36 +1000)
In addition to the new interface several other changes
were made. In fact, there are so many I must apologize
in advance to Craig, et al. for the hatchet I wielded.

Among the changes was my attempt to shrink the body of
that main() function. It's amazing how some folks must
always cram as code much as possible into  ol' main().

Personally, unless it's a throwaway quick & dirty pgm,
all main function bodies should not exceed one screen.

Signed-off-by: Jim Warner <james.warner@comcast.net>
slabtop.c

index 8879c620e08eab796702fcfc442cefbfa113f544..f197d44720b8b3c31744b0ec891c9df8f68293cc 100644 (file)
--- a/slabtop.c
+++ b/slabtop.c
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
+#include <ctype.h>
+#include <errno.h>
+#include <getopt.h>
 #include <locale.h>
-#include <stdlib.h>
+#include <ncurses.h>
+#include <signal.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
-#include <errno.h>
-#include <signal.h>
-#include <ncurses.h>
 #include <termios.h>
-#include <getopt.h>
-#include <ctype.h>
-#include <sys/ioctl.h>
 
+#include <sys/ioctl.h>
 #include <sys/select.h>
 #include <sys/time.h>
 #include <sys/types.h>
 #include "strutils.h"
 #include <proc/slab.h>
 
-#define DEFAULT_SORT_ITEM PROCPS_SLABNODE_OBJS
+#define DEFAULT_SORT  PROCPS_SLABNODE_OBJS
+#define CHAINS_ALLOC  150
+
+static unsigned short Cols, Rows;
+static struct termios Saved_tty;
+static long Delay = 3;
+static int Run_once = 0;
+
+static struct procps_slabinfo *Slab_info;
+
+enum slabnode_item Sort_item = DEFAULT_SORT;
+
+enum slabnode_item Node_items[] = {
+    PROCPS_SLABNODE_OBJS,     PROCPS_SLABNODE_AOBJS, PROCPS_SLABNODE_USE,
+    PROCPS_SLABNODE_OBJ_SIZE, PROCPS_SLABNODE_SLABS, PROCPS_SLABNODE_OBJS_PER_SLAB,
+    PROCPS_SLABNODE_SIZE,     PROCPS_SLABNODE_NAME,
+    /* last 2 are sortable but are not displayable,
+       thus they need not be represented in the Relative_enums */
+    PROCPS_SLABNODE_PAGES_PER_SLAB,
+    PROCPS_SLABNODE_ASLABS };
+
+enum Relative_enums {
+    my_OBJS,  my_AOBJS, my_USE,  my_OSIZE,
+    my_SLABS, my_OPS,   my_SIZE, my_NAME };
+
+#define MAX_ITEMS (int)(sizeof(Node_items) / sizeof(Node_items[0]))
+
+#define PRINT_line(fmt, ...) if (Run_once) printf(fmt, __VA_ARGS__); else printw(fmt, __VA_ARGS__)
 
-static unsigned short cols, rows;
-static struct termios saved_tty;
-static long delay = 3;
-static int run_once = 0;
 
-#define print_line(fmt, ...) if (run_once) printf(fmt, __VA_ARGS__); else printw(fmt, __VA_ARGS__)
 /*
- * term_size - set the globals 'cols' and 'rows' to the current terminal size
+ * term_resize - set the globals 'Cols' and 'Rows' to the current terminal size
  */
-static void term_size(int unusused __attribute__ ((__unused__)))
+static void term_resize (int unusused __attribute__ ((__unused__)))
 {
     struct winsize ws;
 
     if ((ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != -1) && ws.ws_row > 10) {
-        cols = ws.ws_col;
-        rows = ws.ws_row;
+        Cols = ws.ws_col;
+        Rows = ws.ws_row;
     } else {
-        cols = 80;
-        rows = 24;
+        Cols = 80;
+        Rows = 24;
     }
 }
 
-static void sigint_handler(int unused __attribute__ ((__unused__)))
+static void sigint_handler (int unused __attribute__ ((__unused__)))
 {
-    delay = 0;
+    Delay = 0;
 }
 
-static void __attribute__((__noreturn__)) usage(FILE *out)
+static void __attribute__((__noreturn__)) usage (FILE *out)
 {
     fputs(USAGE_HEADER, out);
     fprintf(out, _(" %s [options]\n"), program_invocation_short_name);
@@ -90,10 +112,10 @@ static void __attribute__((__noreturn__)) usage(FILE *out)
     fputs(_(" b: sort by objects per slab\n"), out);
     fputs(_(" c: sort by cache size\n"), out);
     fputs(_(" l: sort by number of slabs\n"), out);
-    fputs(_(" v: sort by number of active slabs\n"), out);
+    fputs(_(" v: sort by (non display) number of active slabs\n"), out);
     fputs(_(" n: sort by name\n"), out);
     fputs(_(" o: sort by number of objects (the default)\n"), out);
-    fputs(_(" p: sort by pages per slab\n"), out);
+    fputs(_(" p: sort by (non display) pages per slab\n"), out);
     fputs(_(" s: sort by object size\n"), out);
     fputs(_(" u: sort by cache utilization\n"), out);
     fprintf(out, USAGE_MAN_TAIL("slabtop(1)"));
@@ -103,11 +125,10 @@ static void __attribute__((__noreturn__)) usage(FILE *out)
 
 /*
  * set_sort_func - return the slab_sort_func that matches the given key.
- * On unrecognizable key, DEF_SORT_FUNC is returned.
+ * On unrecognizable key, DEFAULT_SORT is returned.
  */
-static enum procps_slabinfo_nodeitem get_sort_item(
-        const char key,
-        enum procps_slabinfo_nodeitem old_sort)
+static enum slabnode_item set_sort_item (
+        const char key)
 {
     switch (tolower(key)) {
     case 'n':
@@ -117,7 +138,7 @@ static enum procps_slabinfo_nodeitem get_sort_item(
     case 'a':
         return PROCPS_SLABNODE_AOBJS;
     case 's':
-        return PROCPS_SLABNODE_SIZE;
+        return PROCPS_SLABNODE_OBJ_SIZE;
     case 'b':
         return PROCPS_SLABNODE_OBJS_PER_SLAB;
     case 'p':
@@ -131,111 +152,136 @@ static enum procps_slabinfo_nodeitem get_sort_item(
     case 'u':
         return PROCPS_SLABNODE_USE;
     default:
-        return old_sort;
+        return DEFAULT_SORT;
     }
 }
 
-#if 0
-    case 'Q':
-        delay = 0;
-        break;
+static void parse_opts (int argc, char **argv)
+{
+    static const struct option longopts[] = {
+        { "delay",   required_argument, NULL, 'd' },
+        { "sort",    required_argument, NULL, 's' },
+        { "once",    no_argument,       NULL, 'o' },
+        { "help",    no_argument,       NULL, 'h' },
+        { "version", no_argument,       NULL, 'V' },
+        {  NULL,     0,                 NULL,  0  }};
+    int o;
+
+    while ((o = getopt_long(argc, argv, "d:s:ohV", longopts, NULL)) != -1) {
+        switch (o) {
+        case 'd':
+            errno = 0;
+            Delay = strtol_or_err(optarg, _("illegal delay"));
+            if (Delay < 1)
+                xerrx(EXIT_FAILURE, _("delay must be positive integer"));
+            break;
+        case 's':
+            Sort_item = set_sort_item(optarg[0]);
+            break;
+        case 'o':
+            Run_once=1;
+            Delay = 0;
+            break;
+        case 'V':
+            printf(PROCPS_NG_VERSION);
+            exit(EXIT_SUCCESS);
+        case 'h':
+            usage(stdout);
+        default:
+            usage(stderr);
+        }
     }
 }
-#endif
 
-static void print_stats(struct procps_slabinfo *info)
+static void print_summary (void)
 {
-#define STAT_VAL(e) stats[e].result
-    enum stat_enums {
+ #define STAT_VAL(e) (int)stats[e].result
+    enum slabs_enums {
         stat_AOBJS,   stat_OBJS,   stat_ASLABS, stat_SLABS,
         stat_ACACHES, stat_CACHES, stat_ACTIVE, stat_TOTAL,
         stat_MIN,     stat_AVG,    stat_MAX,
     };
-    static struct procps_slabinfo_result stats[] = {
-        { PROCPS_SLABINFO_AOBJS,        0, &stats[1] },
-        { PROCPS_SLABINFO_OBJS,         0, &stats[2] },
-        { PROCPS_SLABINFO_ASLABS,       0, &stats[3] },
-        { PROCPS_SLABINFO_SLABS,        0, &stats[4] },
-        { PROCPS_SLABINFO_ACACHES,      0, &stats[5] },
-        { PROCPS_SLABINFO_CACHES,       0, &stats[6] },
-        { PROCPS_SLABINFO_SIZE_ACTIVE,  0, &stats[7] },
-        { PROCPS_SLABINFO_SIZE_TOTAL,   0, &stats[8] },
-        { PROCPS_SLABINFO_SIZE_MIN,     0, &stats[9] },
-        { PROCPS_SLABINFO_SIZE_AVG,     0, &stats[10] },
-        { PROCPS_SLABINFO_SIZE_MAX,     0, NULL },
+    static struct slabs_result stats[] = {
+        { PROCPS_SLABS_AOBJS,        0, &stats[1] },
+        { PROCPS_SLABS_OBJS,         0, &stats[2] },
+        { PROCPS_SLABS_ASLABS,       0, &stats[3] },
+        { PROCPS_SLABS_SLABS,        0, &stats[4] },
+        { PROCPS_SLABS_ACACHES,      0, &stats[5] },
+        { PROCPS_SLABS_CACHES,       0, &stats[6] },
+        { PROCPS_SLABS_SIZE_ACTIVE,  0, &stats[7] },
+        { PROCPS_SLABS_SIZE_TOTAL,   0, &stats[8] },
+        { PROCPS_SLABS_SIZE_MIN,     0, &stats[9] },
+        { PROCPS_SLABS_SIZE_AVG,     0, &stats[10] },
+        { PROCPS_SLABS_SIZE_MAX,     0, NULL },
     };
 
-    if (procps_slabinfo_stat_getchain(info, stats) < 0)
-        xerrx(EXIT_FAILURE,
-              _("Error getting slabinfo results"));
-
-    print_line(" %-35s: %d / %d (%.1f%%)\n"
-               " %-35s: %d / %d (%.1f%%)\n"
-               " %-35s: %d / %d (%.1f%%)\n"
-               " %-35s: %.2fK / %.2fK (%.1f%%)\n"
-               " %-35s: %.2fK / %.2fK / %.2fK\n\n",
-               /* Translation Hint: Next five strings must not
-                * exceed 35 length in characters.  */
-               /* xgettext:no-c-format */
-               _("Active / Total Objects (% used)"),
-               STAT_VAL(stat_AOBJS), STAT_VAL(stat_OBJS),
-               100.0 * STAT_VAL(stat_AOBJS) / STAT_VAL(stat_OBJS),
-                   /* xgettext:no-c-format */
-               _("Active / Total Slabs (% used)"),
-               STAT_VAL(stat_ASLABS), STAT_VAL(stat_SLABS),
-               100.0 * STAT_VAL(stat_ASLABS) / STAT_VAL(stat_SLABS),
-                   /* xgettext:no-c-format */
-               _("Active / Total Caches (% used)"),
-               STAT_VAL(stat_ACACHES), STAT_VAL(stat_CACHES),
-               100.0 * STAT_VAL(stat_ACACHES) / STAT_VAL(stat_CACHES),
-                   /* xgettext:no-c-format */
-               _("Active / Total Size (% used)"),
-               STAT_VAL(stat_ACTIVE) / 1024.0 , STAT_VAL(stat_TOTAL) / 1024.0,
-               100.0 * STAT_VAL(stat_ACTIVE) / STAT_VAL(stat_TOTAL),
-               _("Minimum / Average / Maximum Object"),
-               STAT_VAL(stat_MIN) / 1024.0, STAT_VAL(stat_AVG) / 1024.0,
-               STAT_VAL(stat_MAX) / 1024.0);
-#undef STAT_VAL
+    if (procps_slabs_getchain(Slab_info, stats) < 0) \
+        xerrx(EXIT_FAILURE, _("Error getting slab summary results"));
+
+    PRINT_line(" %-35s: %d / %d (%.1f%%)\n"
+               , /* Translation Hint: Next five strings must not
+                  * exceed a length of 35 characters.  */
+                 /* xgettext:no-c-format */
+                 _("Active / Total Objects (% used)")
+               , STAT_VAL(stat_AOBJS)
+               , STAT_VAL(stat_OBJS)
+               , 100.0 * STAT_VAL(stat_AOBJS) / STAT_VAL(stat_OBJS));
+    PRINT_line(" %-35s: %d / %d (%.1f%%)\n"
+               , /* xgettext:no-c-format */
+                 _("Active / Total Slabs (% used)")
+               , STAT_VAL(stat_ASLABS)
+               , STAT_VAL(stat_SLABS)
+               , 100.0 * STAT_VAL(stat_ASLABS) / STAT_VAL(stat_SLABS));
+    PRINT_line(" %-35s: %d / %d (%.1f%%)\n"
+               , /* xgettext:no-c-format */
+                 _("Active / Total Caches (% used)")
+               , STAT_VAL(stat_ACACHES)
+               , STAT_VAL(stat_CACHES)
+               , 100.0 * STAT_VAL(stat_ACACHES) / STAT_VAL(stat_CACHES));
+    PRINT_line(" %-35s: %.2fK / %.2fK (%.1f%%)\n"
+               , /* xgettext:no-c-format */
+                 _("Active / Total Size (% used)")
+               , STAT_VAL(stat_ACTIVE) / 1024.0
+               , STAT_VAL(stat_TOTAL) / 1024.0
+               , 100.0 * STAT_VAL(stat_ACTIVE) / STAT_VAL(stat_TOTAL));
+    PRINT_line(" %-35s: %.2fK / %.2fK / %.2fK\n\n"
+               , _("Minimum / Average / Maximum Object")
+               , STAT_VAL(stat_MIN) / 1024.0
+               , STAT_VAL(stat_AVG) / 1024.0
+               , STAT_VAL(stat_MAX) / 1024.0);
+ #undef STAT_VAL
 }
 
-static void cleanup(const int is_tty, struct procps_slabinfo **slab_info)
+static void print_headings (void)
 {
-    if (is_tty)
-        tcsetattr(STDIN_FILENO, TCSAFLUSH, &saved_tty);
-    if (!run_once)
-        endwin();
-    procps_slabinfo_unref(slab_info);
+    /* Translation Hint: Please keep alignment of the
+     * following intact. */
+    PRINT_line("%-78s\n", _("  OBJS ACTIVE  USE OBJ SIZE  SLABS OBJ/SLAB CACHE SIZE NAME"));
 }
 
-int main(int argc, char *argv[])
+static void print_details (struct slabnode_chain *chain)
 {
-    int is_tty, o;
-    int nr_slabs;
-    unsigned short old_rows;
-    int retval = EXIT_SUCCESS;
-    struct procps_slabinfo *slab_info;
-    enum procps_slabinfo_nodeitem sort_item = DEFAULT_SORT_ITEM;
+ #define my_NUM(c,e) (unsigned)c->head[e].result.num
+ #define my_STR(c,e) c->head[e].result.str
+
+    PRINT_line("%6u %6u %3u%% %7.2fK %6u %8u %9uK %-23s\n"
+        , my_NUM(chain, my_OBJS),  my_NUM(chain, my_AOBJS)
+        , my_NUM(chain, my_USE),   my_NUM(chain, my_OSIZE) / 1024.0
+        , my_NUM(chain, my_SLABS), my_NUM(chain, my_OPS)
+        , my_NUM(chain, my_SIZE) / 1024
+        , my_STR(chain, my_NAME));
+
+    return;
+ #undef my_NUM
+ #undef my_STR
+}
 
-    static const struct option longopts[] = {
-        { "delay",    required_argument, NULL, 'd' },
-        { "sort",    required_argument, NULL, 's' },
-        { "once",    no_argument,       NULL, 'o' },
-        { "help",    no_argument,       NULL, 'h' },
-        { "version",    no_argument,       NULL, 'V' },
-        {  NULL, 0, NULL, 0 }
-    };
 
-    struct procps_slabnode_result result[] = {
-        { PROCPS_SLABNODE_OBJS,          0, &result[1] },
-        { PROCPS_SLABNODE_AOBJS,         0, &result[2] },
-        { PROCPS_SLABNODE_USE,           0, &result[3] },
-        { PROCPS_SLABNODE_OBJ_SIZE,      0, &result[4] },
-        { PROCPS_SLABNODE_SLABS,         0, &result[5] },
-        { PROCPS_SLABNODE_OBJS_PER_SLAB, 0, &result[6] },
-        { PROCPS_SLABNODE_SIZE,          0, NULL } };
-    enum result_enums {
-        stat_OBJS, stat_AOBJS, stat_USE, stat_OSIZE, stat_SLABS,
-        stat_OPS, stat_SIZE };
+int main(int argc, char *argv[])
+{
+    int is_tty, nr_slabs, rc = EXIT_SUCCESS;
+    unsigned short old_rows;
+    struct slabnode_chain **v;
 
 #ifdef HAVE_PROGRAM_INVOCATION_NAME
     program_invocation_name = program_invocation_short_name;
@@ -245,121 +291,84 @@ int main(int argc, char *argv[])
     textdomain(PACKAGE);
     atexit(close_stdout);
 
-    while ((o = getopt_long(argc, argv, "d:s:ohV", longopts, NULL)) != -1) {
-        switch (o) {
-        case 'd':
-            errno = 0;
-            delay = strtol_or_err(optarg, _("illegal delay"));
-            if (delay < 1)
-                xerrx(EXIT_FAILURE,
-                    _("delay must be positive integer"));
-            break;
-        case 's':
-            sort_item = get_sort_item(optarg[0], sort_item);
-            break;
-        case 'o':
-            run_once=1;
-            delay = 0;
-            break;
-        case 'V':
-            printf(PROCPS_NG_VERSION);
-            return EXIT_SUCCESS;
-        case 'h':
-            usage(stdout);
-        default:
-            usage(stderr);
-        }
-    }
-
-    if (procps_slabinfo_new(&slab_info) < 0)
-        xerrx(EXIT_FAILURE,
-              _("Unable to create slabinfo structure"));
+    parse_opts(argc, argv);
 
+    if (procps_slabinfo_new(&Slab_info) < 0)
+        xerrx(EXIT_FAILURE, _("Unable to create slabinfo structure"));
 
-    is_tty = isatty(STDIN_FILENO);
-    if (is_tty && tcgetattr(STDIN_FILENO, &saved_tty) == -1)
-        xwarn(_("terminal setting retrieval"));
+    if (!(v = procps_slabnode_chains_alloc(Slab_info, CHAINS_ALLOC, 0, MAX_ITEMS, Node_items)))
+        xerrx(EXIT_FAILURE, _("Unable to allocate slabinfo nodes"));
 
-    old_rows = rows;
-    term_size(0);
-    if (!run_once) {
+    if (!Run_once) {
+        is_tty = isatty(STDIN_FILENO);
+        if (is_tty && tcgetattr(STDIN_FILENO, &Saved_tty) == -1)
+            xwarn(_("terminal setting retrieval"));
+        old_rows = Rows;
+        term_resize(0);
         initscr();
-        resizeterm(rows, cols);
-        signal(SIGWINCH, term_size);
+        resizeterm(Rows, Cols);
+        signal(SIGWINCH, term_resize);
+        signal(SIGINT, sigint_handler);
     }
-    signal(SIGINT, sigint_handler);
 
-#define STAT_VAL(e) result[e].result
     do {
-        char *slab_name;
         struct timeval tv;
         fd_set readfds;
-        char c;
-        int i, myerrno;
+        int i;
 
-        if (procps_slabinfo_read(slab_info) < 0) {
-            xwarn(_("Unable to read slabinfo"));
-            retval = EXIT_FAILURE;
+        // this next guy also performs the procps_slabnode_read() call
+        if ((nr_slabs = procps_slabnode_chains_fill(Slab_info, v, CHAINS_ALLOC)) < 0) {
+            xwarn(_("Unable to get slabinfo node data"));
+            rc = EXIT_FAILURE;
             break;
         }
-
-        if (!run_once && old_rows != rows) {
-            resizeterm(rows, cols);
-            old_rows = rows;
+        if (!(v = procps_slabnode_chains_sort(Slab_info, v, nr_slabs, Sort_item))) {
+            xwarn(_("Unable to sort slab nodes"));
+            rc = EXIT_FAILURE;
+            break;
         }
 
-        move(0, 0);
-        print_stats(slab_info);
-
-        if (procps_slabinfo_sort(slab_info, sort_item) < 0) {
-            xwarn(_("Unable to sort slabnodes"));
-            retval= EXIT_FAILURE;
+        if (Run_once) {
+            print_summary();
+            print_headings();
+            for (i = 0; i < nr_slabs; i++)
+                print_details(v[i]);
             break;
         }
 
+        if (old_rows != Rows) {
+            resizeterm(Rows, Cols);
+            old_rows = Rows;
+        }
+        move(0, 0);
+        print_summary();
         attron(A_REVERSE);
-        /* Translation Hint: Please keep alignment of the
-         * following intact. */
-        print_line("%-78s\n", _("  OBJS ACTIVE  USE OBJ SIZE  SLABS OBJ/SLAB CACHE SIZE NAME"));
+        print_headings();
         attroff(A_REVERSE);
 
-        if ((nr_slabs = procps_slabinfo_node_count(slab_info)) < 0) {
-            xwarn(_("Unable to count slabinfo nodes"));
-            retval = EXIT_FAILURE;
-            break;
-        }
-
-        for (i=0 ; i < rows - 8 && i < nr_slabs; i++) {
-            if (procps_slabinfo_node_getchain(slab_info, result, i) < 0) {
-                xwarn(_("Unable to get slabinfo node data"));
-                retval = EXIT_FAILURE;
+        for (i = 0; i < Rows - 8 && i < nr_slabs; i++)
+            print_details(v[i]);
+
+        refresh();
+        FD_ZERO(&readfds);
+        FD_SET(STDIN_FILENO, &readfds);
+        tv.tv_sec = Delay;
+        tv.tv_usec = 0;
+        if (select(STDOUT_FILENO, &readfds, NULL, NULL, &tv) > 0) {
+            char c;
+            if (read(STDIN_FILENO, &c, 1) != 1
+            || (c == 'Q' || c == 'q'))
                 break;
-            }
-            slab_name= procps_slabinfo_node_getname(slab_info, i);
-            print_line("%6u %6u %3u%% %7.2fK %6u %8u %9uK %-23s\n",
-                       STAT_VAL(stat_OBJS), STAT_VAL(stat_AOBJS),
-                       STAT_VAL(stat_USE),
-                       STAT_VAL(stat_OSIZE) / 1024.0, STAT_VAL(stat_SLABS),
-                       STAT_VAL(stat_OPS),
-                       (unsigned)(STAT_VAL(stat_SIZE) / 1024),
-                       slab_name?slab_name:"(unknown)");
-        }
-        if (!run_once) {
-            refresh();
-            FD_ZERO(&readfds);
-            FD_SET(STDIN_FILENO, &readfds);
-            tv.tv_sec = delay;
-            tv.tv_usec = 0;
-            if (select(STDOUT_FILENO, &readfds, NULL, NULL, &tv) > 0) {
-                if (read(STDIN_FILENO, &c, 1) != 1)
-                    break;
-                if (c == 'Q' || c == 'q')
-                    delay = 0;
-                else
-                    sort_item = get_sort_item(c, sort_item);
-            }
+            Sort_item = set_sort_item(c);
         }
-    } while (delay);
-    cleanup(is_tty, &slab_info);
+    // made zero by sigint_handler()
+    } while (Delay);
 
+    if (!Run_once) {
+        if (is_tty)
+            tcsetattr(STDIN_FILENO, TCSAFLUSH, &Saved_tty);
+        endwin();
+    }
+    procps_slabinfo_unref(&Slab_info);
+    return rc;
 }