2 * slabtop.c - utility to display kernel slab information.
4 * Chris Rivera <cmrivera@ufl.edu>
5 * Robert Love <rml@tech9.net>
7 * This program is licensed under the GNU Library General Public License, v2
9 * Copyright (C) 2003 Chris Rivera
21 #include <sys/ioctl.h>
23 #include <sys/select.h>
25 #include <sys/types.h>
28 #include "proc/slab.h"
29 #include "proc/version.h"
31 #define DEF_SORT_FUNC sort_nr_objs
32 #define SLAB_STAT_ZERO { nr_objs: 0 }
34 static unsigned short cols, rows;
35 static struct termios saved_tty;
36 static long delay = 3;
37 static int (*sort_func)(const struct slab_info *, const struct slab_info *);
39 static struct slab_info *merge_objs(struct slab_info *a, struct slab_info *b)
41 struct slab_info sorted_list;
42 struct slab_info *curr = &sorted_list;
44 while ((a != NULL) && (b != NULL)) {
45 if (sort_func(a, b)) {
56 curr->next = (a == NULL) ? b : a;
57 return sorted_list.next;
61 * slabsort - merge sort the slab_info linked list based on sort_func
63 static struct slab_info *slabsort(struct slab_info *list)
65 struct slab_info *a, *b;
67 if ((list == NULL) || (list->next == NULL))
73 while ((b != NULL) && (b->next != NULL)) {
81 return merge_objs(slabsort(a), slabsort(b));
85 * Sort Routines. Each of these should be associated with a command-line
86 * search option. The functions should fit the prototype:
88 * int sort_foo(const struct slab_info *a, const struct slab_info *b)
90 * They return one if the first parameter is larger than the second
91 * Otherwise, they return zero.
94 static int sort_name(const struct slab_info *a, const struct slab_info *b)
96 return (strcmp(a->name, b->name) < 0) ? 1 : 0;
99 static int sort_nr_objs(const struct slab_info *a, const struct slab_info *b)
101 return (a->nr_objs > b->nr_objs);
104 static int sort_nr_active_objs(const struct slab_info *a,
105 const struct slab_info *b)
107 return (a->nr_active_objs > b->nr_active_objs);
110 static int sort_obj_size(const struct slab_info *a, const struct slab_info *b)
112 return (a->obj_size > b->obj_size);
115 static int sort_objs_per_slab(const struct slab_info *a,
116 const struct slab_info *b)
118 return (a->objs_per_slab > b->objs_per_slab);
121 static int sort_pages_per_slab(const struct slab_info *a,
122 const struct slab_info *b)
124 return (a->pages_per_slab > b->pages_per_slab);
127 static int sort_nr_slabs(const struct slab_info *a, const struct slab_info *b)
129 return (a->nr_slabs > b->nr_slabs);
132 static int sort_nr_active_slabs(const struct slab_info *a,
133 const struct slab_info *b)
135 return (a->nr_active_slabs > b->nr_active_slabs);
139 static int sort_use(const struct slab_info *a, const struct slab_info *b)
141 return (a->use > b->use);
144 static int sort_cache_size(const struct slab_info *a, const struct slab_info *b)
146 return (a->cache_size > b->cache_size);
150 * term_size - set the globals 'cols' and 'rows' to the current terminal size
152 static void term_size(int unused)
157 if ((ioctl(1, TIOCGWINSZ, &ws) != -1) && ws.ws_row > 10) {
166 static void sigint_handler(int unused)
173 static void usage(const char *cmd)
175 fprintf(stderr, "usage: %s [options]\n\n", cmd);
176 fprintf(stderr, "options:\n");
177 fprintf(stderr, " --delay=n, -d n "
178 "delay n seconds between updates\n");
179 fprintf(stderr, " --once, -o "
180 "only display once, then exit\n");
181 fprintf(stderr, " --sort=S, -s S "
182 "specify sort criteria S (see below)\n");
183 fprintf(stderr, " --version, -V "
184 "display version information and exit\n");
185 fprintf(stderr, " --help display this help and exit\n\n");
186 fprintf(stderr, "The following are valid sort criteria:\n");
187 fprintf(stderr, " a: sort by number of active objects\n");
188 fprintf(stderr, " b: sort by objects per slab\n");
189 fprintf(stderr, " c: sort by cache size\n");
190 fprintf(stderr, " l: sort by number of slabs\n");
191 fprintf(stderr, " v: sort by number of active slabs\n");
192 fprintf(stderr, " n: sort by name\n");
193 fprintf(stderr, " o: sort by number of objects\n");
194 fprintf(stderr, " p: sort by pages per slab\n");
195 fprintf(stderr, " s: sort by object size\n");
196 fprintf(stderr, " u: sort by cache utilization\n");
200 * set_sort_func - return the slab_sort_func that matches the given key.
201 * On unrecognizable key, DEF_SORT_FUNC is returned.
203 static void * set_sort_func(char key)
211 return sort_nr_active_objs;
213 return sort_obj_size;
215 return sort_objs_per_slab;
217 return sort_pages_per_slab;
219 return sort_nr_slabs;
221 return sort_nr_active_slabs;
223 return sort_cache_size;
227 return DEF_SORT_FUNC;
231 static void parse_input(char c)
236 sort_func = sort_nr_active_objs;
239 sort_func = sort_objs_per_slab;
242 sort_func = sort_cache_size;
245 sort_func = sort_nr_slabs;
248 sort_func = sort_nr_active_slabs;
251 sort_func = sort_name;
254 sort_func = sort_nr_objs;
257 sort_func = sort_pages_per_slab;
260 sort_func = sort_obj_size;
263 sort_func = sort_use;
271 int main(int argc, char *argv[])
274 unsigned short old_rows;
275 struct slab_info *slab_list = NULL;
277 struct option longopts[] = {
278 { "delay", 1, NULL, 'd' },
279 { "sort", 1, NULL, 's' },
280 { "once", 0, NULL, 'o' },
281 { "help", 0, NULL, 'h' },
282 { "version", 0, NULL, 'V' },
286 sort_func = DEF_SORT_FUNC;
288 while ((o = getopt_long(argc, argv, "d:s:ohV", longopts, NULL)) != -1) {
294 delay = strtol(optarg, NULL, 10);
300 fprintf(stderr, "error: can't have a "\
306 sort_func = set_sort_func(optarg[0]);
322 if (tcgetattr(0, &saved_tty) == -1)
328 resizeterm(rows, cols);
329 signal(SIGWINCH, term_size);
330 signal(SIGINT, sigint_handler);
333 struct slab_info *curr;
334 struct slab_stat stats = SLAB_STAT_ZERO;
340 if (get_slabinfo(&slab_list, &stats))
343 if (old_rows != rows) {
344 resizeterm(rows, cols);
349 printw( " Active / Total Objects (%% used) : %d / %d (%.1f%%)\n"
350 " Active / Total Slabs (%% used) : %d / %d (%.1f%%)\n"
351 " Active / Total Caches (%% used) : %d / %d (%.1f%%)\n"
352 " Active / Total Size (%% used) : %.2fK / %.2fK (%.1f%%)\n"
353 " Minimum / Average / Maximum Object : %.2fK / %.2fK / %.2fK\n\n",
354 stats.nr_active_objs, stats.nr_objs, 100.0 * stats.nr_active_objs / stats.nr_objs,
355 stats.nr_active_slabs, stats.nr_slabs, 100.0 * stats.nr_active_slabs / stats.nr_slabs,
356 stats.nr_active_caches, stats.nr_caches, 100.0 * stats.nr_active_caches / stats.nr_caches,
357 stats.active_size / 1024.0, stats.total_size / 1024.0, 100.0 * stats.active_size / stats.total_size,
358 stats.min_obj_size / 1024.0, stats.avg_obj_size / 1024.0, stats.max_obj_size / 1024.0
361 slab_list = slabsort(slab_list);
364 printw( "%6s %6s %4s %8s %6s %8s %10s %-23s\n",
365 "OBJS", "ACTIVE", "USE", "OBJ SIZE", "SLABS",
366 "OBJ/SLAB", "CACHE SIZE", "NAME");
370 for (i = 0; i < rows - 8 && curr->next; i++) {
371 printw("%6u %6u %3u%% %7.2fK %6u %8u %9uK %-23s\n",
372 curr->nr_objs, curr->nr_active_objs, curr->use,
373 curr->obj_size / 1024.0, curr->nr_slabs,
374 curr->objs_per_slab, (unsigned)(curr->cache_size / 1024),
380 put_slabinfo(slab_list);
386 if (select(1, &readfds, NULL, NULL, &tv) > 0) {
387 if (read(0, &c, 1) != 1)
393 tcsetattr(0, TCSAFLUSH, &saved_tty);
394 free_slabinfo(slab_list);