2 * slabtop.c - utility to display kernel slab information.
4 * Chris Rivera <cmrivera@ufl.edu>
5 * Robert Love <rml@tech9.net>
7 * Copyright (C) 2003 Chris Rivera
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
35 #include <sys/ioctl.h>
37 #include <sys/select.h>
39 #include <sys/types.h>
43 #include "fileutils.h"
46 #include "proc/slab.h"
47 #include "proc/version.h"
49 #define DEF_SORT_FUNC sort_nr_objs
52 static unsigned short cols, rows;
53 static struct termios saved_tty;
54 static long delay = 3;
55 static int (*sort_func)(const struct slab_info *, const struct slab_info *);
57 static struct slab_info *merge_objs(struct slab_info *a, struct slab_info *b)
59 struct slab_info sorted_list;
60 struct slab_info *curr = &sorted_list;
62 while ((a != NULL) && (b != NULL)) {
63 if (sort_func(a, b)) {
74 curr->next = (a == NULL) ? b : a;
75 return sorted_list.next;
79 * slabsort - merge sort the slab_info linked list based on sort_func
81 static struct slab_info *slabsort(struct slab_info *list)
83 struct slab_info *a, *b;
85 if ((list == NULL) || (list->next == NULL))
91 while ((b != NULL) && (b->next != NULL)) {
99 return merge_objs(slabsort(a), slabsort(b));
103 * Sort Routines. Each of these should be associated with a command-line
104 * search option. The functions should fit the prototype:
106 * int sort_foo(const struct slab_info *a, const struct slab_info *b)
108 * They return one if the first parameter is larger than the second
109 * Otherwise, they return zero.
112 static int sort_name(const struct slab_info *a, const struct slab_info *b)
114 return (strcmp(a->name, b->name) < 0) ? 1 : 0;
117 static int sort_nr_objs(const struct slab_info *a, const struct slab_info *b)
119 return (a->nr_objs > b->nr_objs);
122 static int sort_nr_active_objs(const struct slab_info *a,
123 const struct slab_info *b)
125 return (a->nr_active_objs > b->nr_active_objs);
128 static int sort_obj_size(const struct slab_info *a, const struct slab_info *b)
130 return (a->obj_size > b->obj_size);
133 static int sort_objs_per_slab(const struct slab_info *a,
134 const struct slab_info *b)
136 return (a->objs_per_slab > b->objs_per_slab);
139 static int sort_pages_per_slab(const struct slab_info *a,
140 const struct slab_info *b)
142 return (a->pages_per_slab > b->pages_per_slab);
145 static int sort_nr_slabs(const struct slab_info *a, const struct slab_info *b)
147 return (a->nr_slabs > b->nr_slabs);
150 static int sort_nr_active_slabs(const struct slab_info *a,
151 const struct slab_info *b)
153 return (a->nr_active_slabs > b->nr_active_slabs);
157 static int sort_use(const struct slab_info *a, const struct slab_info *b)
159 return (a->use > b->use);
162 static int sort_cache_size(const struct slab_info *a, const struct slab_info *b)
164 return (a->cache_size > b->cache_size);
168 * term_size - set the globals 'cols' and 'rows' to the current terminal size
170 static void term_size(int unusused __attribute__ ((__unused__)))
174 if ((ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != -1) && ws.ws_row > 10) {
185 static void sigint_handler(int unused __attribute__ ((__unused__)))
190 static void __attribute__((__noreturn__)) usage(FILE *out)
192 fputs(USAGE_HEADER, out);
193 fprintf(out, _(" %s [options]\n"), program_invocation_short_name);
194 fputs(USAGE_OPTIONS, out);
195 fputs(_(" -d, --delay <secs> delay updates\n"), out);
196 fputs(_(" -o, --once only display once, then exit\n"), out);
197 fputs(_(" -s, --sort <char> specify sort criteria by character (see below)\n"), out);
198 fputs(USAGE_SEPARATOR, out);
199 fputs(USAGE_HELP, out);
200 fputs(USAGE_VERSION, out);
202 fputs(_("\nThe following are valid sort criteria:\n"), out);
203 fputs(_(" a: sort by number of active objects\n"), out);
204 fputs(_(" b: sort by objects per slab\n"), out);
205 fputs(_(" c: sort by cache size\n"), out);
206 fputs(_(" l: sort by number of slabs\n"), out);
207 fputs(_(" v: sort by number of active slabs\n"), out);
208 fputs(_(" n: sort by name\n"), out);
209 fputs(_(" o: sort by number of objects (the default)\n"), out);
210 fputs(_(" p: sort by pages per slab\n"), out);
211 fputs(_(" s: sort by object size\n"), out);
212 fputs(_(" u: sort by cache utilization\n"), out);
213 fprintf(out, USAGE_MAN_TAIL("slabtop(1)"));
215 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
219 * set_sort_func - return the slab_sort_func that matches the given key.
220 * On unrecognizable key, DEF_SORT_FUNC is returned.
222 static void * set_sort_func(char key)
226 return (void *) sort_name;
228 return (void *) sort_nr_objs;
230 return (void *) sort_nr_active_objs;
232 return (void *) sort_obj_size;
234 return (void *) sort_objs_per_slab;
236 return (void *) sort_pages_per_slab;
238 return (void *) sort_nr_slabs;
240 return (void *) sort_nr_active_slabs;
242 return (void *) sort_cache_size;
244 return (void *) sort_use;
246 return (void *) DEF_SORT_FUNC;
250 static void parse_input(char c)
255 sort_func = sort_nr_active_objs;
258 sort_func = sort_objs_per_slab;
261 sort_func = sort_cache_size;
264 sort_func = sort_nr_slabs;
267 sort_func = sort_nr_active_slabs;
270 sort_func = sort_name;
273 sort_func = sort_nr_objs;
276 sort_func = sort_pages_per_slab;
279 sort_func = sort_obj_size;
282 sort_func = sort_use;
290 #define print_line(fmt, ...) if (run_once) printf(fmt, __VA_ARGS__); else printw(fmt, __VA_ARGS__)
291 int main(int argc, char *argv[])
294 unsigned short old_rows;
295 struct slab_info *slab_list = NULL;
296 int retval = EXIT_SUCCESS;
298 static const struct option longopts[] = {
299 { "delay", required_argument, NULL, 'd' },
300 { "sort", required_argument, NULL, 's' },
301 { "once", no_argument, NULL, 'o' },
302 { "help", no_argument, NULL, 'h' },
303 { "version", no_argument, NULL, 'V' },
307 #ifdef HAVE_PROGRAM_INVOCATION_NAME
308 program_invocation_name = program_invocation_short_name;
310 setlocale (LC_ALL, "");
311 bindtextdomain(PACKAGE, LOCALEDIR);
313 atexit(close_stdout);
315 sort_func = DEF_SORT_FUNC;
317 while ((o = getopt_long(argc, argv, "d:s:ohV", longopts, NULL)) != -1) {
321 delay = strtol_or_err(optarg, _("illegal delay"));
324 _("delay must be positive integer"));
327 sort_func = (int (*)(const struct slab_info*,
328 const struct slab_info *)) set_sort_func(optarg[0]);
335 printf(PROCPS_NG_VERSION);
344 is_tty = isatty(STDIN_FILENO);
345 if (is_tty && tcgetattr(STDIN_FILENO, &saved_tty) == -1)
346 xwarn(_("terminal setting retrieval"));
352 resizeterm(rows, cols);
353 signal(SIGWINCH, term_size);
355 signal(SIGINT, sigint_handler);
358 struct slab_info *curr;
359 struct slab_stat stats;
364 memset(&stats, 0, sizeof(struct slab_stat));
366 if (get_slabinfo(&slab_list, &stats)) {
368 retval = EXIT_FAILURE;
372 if (!run_once && old_rows != rows) {
373 resizeterm(rows, cols);
378 print_line(" %-35s: %d / %d (%.1f%%)\n"
379 " %-35s: %d / %d (%.1f%%)\n"
380 " %-35s: %d / %d (%.1f%%)\n"
381 " %-35s: %.2fK / %.2fK (%.1f%%)\n"
382 " %-35s: %.2fK / %.2fK / %.2fK\n\n",
383 /* Translation Hint: Next five strings must not
384 * exceed 35 length in characters. */
385 /* xgettext:no-c-format */
386 _("Active / Total Objects (% used)"),
387 stats.nr_active_objs, stats.nr_objs,
388 100.0 * stats.nr_active_objs / stats.nr_objs,
389 /* xgettext:no-c-format */
390 _("Active / Total Slabs (% used)"),
391 stats.nr_active_slabs, stats.nr_slabs,
392 100.0 * stats.nr_active_slabs / stats.nr_slabs,
393 /* xgettext:no-c-format */
394 _("Active / Total Caches (% used)"),
395 stats.nr_active_caches, stats.nr_caches,
396 100.0 * stats.nr_active_caches / stats.nr_caches,
397 /* xgettext:no-c-format */
398 _("Active / Total Size (% used)"),
399 stats.active_size / 1024.0, stats.total_size / 1024.0,
400 100.0 * stats.active_size / stats.total_size,
401 _("Minimum / Average / Maximum Object"),
402 stats.min_obj_size / 1024.0, stats.avg_obj_size / 1024.0,
403 stats.max_obj_size / 1024.0);
405 slab_list = slabsort(slab_list);
408 /* Translation Hint: Please keep alignment of the
409 * following intact. */
410 print_line("%-78s\n", _(" OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME"));
414 for (i = 0; i < rows - 8 && curr; i++) {
415 print_line("%6u %6u %3u%% %7.2fK %6u %8u %9uK %-23s\n",
416 curr->nr_objs, curr->nr_active_objs, curr->use,
417 curr->obj_size / 1024.0, curr->nr_slabs,
418 curr->objs_per_slab, (unsigned)(curr->cache_size / 1024),
423 put_slabinfo(slab_list);
427 FD_SET(STDIN_FILENO, &readfds);
430 if (select(STDOUT_FILENO, &readfds, NULL, NULL, &tv) > 0) {
431 if (read(STDIN_FILENO, &c, 1) != 1)
439 tcsetattr(STDIN_FILENO, TCSAFLUSH, &saved_tty);
441 free_slabinfo(slab_list);