Updated with Tizen:Base source codes
[external/procps.git] / slabtop.c
1 /* 
2  * slabtop.c - utility to display kernel slab information.
3  *
4  * Chris Rivera <cmrivera@ufl.edu>
5  * Robert Love <rml@tech9.net>
6  *
7  * This program is licensed under the GNU Library General Public License, v2
8  *
9  * Copyright (C) 2003 Chris Rivera
10  */
11
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include <errno.h>
16 #include <signal.h>
17 #include <ncurses.h>
18 #include <termios.h>
19 #include <getopt.h>
20 #include <ctype.h>
21 #include <sys/ioctl.h>
22
23 #include <sys/select.h>
24 #include <sys/time.h>
25 #include <sys/types.h>
26 #include <unistd.h>
27
28 #include "proc/slab.h"
29 #include "proc/version.h"
30
31 #define DEF_SORT_FUNC           sort_nr_objs
32 #define SLAB_STAT_ZERO          { nr_objs: 0 }
33
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 *);
38
39 static struct slab_info *merge_objs(struct slab_info *a, struct slab_info *b)
40 {
41         struct slab_info sorted_list;
42         struct slab_info *curr = &sorted_list;
43
44         while ((a != NULL) && (b != NULL)) {
45                 if (sort_func(a, b)) {
46                         curr->next = a;
47                         curr = a;
48                         a = a->next;
49                 } else {
50                         curr->next = b;
51                         curr = b;
52                         b = b->next;
53                 }
54         }
55
56         curr->next = (a == NULL) ? b : a;
57         return sorted_list.next;
58 }
59
60 /* 
61  * slabsort - merge sort the slab_info linked list based on sort_func
62  */
63 static struct slab_info *slabsort(struct slab_info *list)
64 {
65         struct slab_info *a, *b;
66
67         if ((list == NULL) || (list->next == NULL))
68                 return list;
69
70         a = list;
71         b = list->next;
72
73         while ((b != NULL) && (b->next != NULL)) {
74                 list = list->next;
75                 b = b->next->next;
76         }
77         
78         b = list->next;
79         list->next = NULL;
80
81         return merge_objs(slabsort(a), slabsort(b));
82 }
83
84 /*
85  * Sort Routines.  Each of these should be associated with a command-line
86  * search option.  The functions should fit the prototype:
87  *
88  *      int sort_foo(const struct slab_info *a, const struct slab_info *b)
89  *
90  * They return one if the first parameter is larger than the second
91  * Otherwise, they return zero.
92  */
93
94 static int sort_name(const struct slab_info *a, const struct slab_info *b)
95 {
96         return (strcmp(a->name, b->name) < 0) ? 1 : 0;
97 }
98
99 static int sort_nr_objs(const struct slab_info *a, const struct slab_info *b)
100 {
101         return (a->nr_objs > b->nr_objs);
102 }
103
104 static int sort_nr_active_objs(const struct slab_info *a,
105                                 const struct slab_info *b)
106 {
107         return (a->nr_active_objs > b->nr_active_objs);
108 }
109
110 static int sort_obj_size(const struct slab_info *a, const struct slab_info *b)
111 {
112         return (a->obj_size > b->obj_size);
113 }
114
115 static int sort_objs_per_slab(const struct slab_info *a,
116                                 const struct slab_info *b)
117 {
118         return (a->objs_per_slab > b->objs_per_slab);
119 }
120
121 static int sort_pages_per_slab(const struct slab_info *a,
122                 const struct slab_info *b)
123 {
124         return (a->pages_per_slab > b->pages_per_slab);
125 }
126
127 static int sort_nr_slabs(const struct slab_info *a, const struct slab_info *b)
128 {
129         return (a->nr_slabs > b->nr_slabs);
130 }
131
132 static int sort_nr_active_slabs(const struct slab_info *a,
133                         const struct slab_info *b)
134 {
135         return (a->nr_active_slabs > b->nr_active_slabs);
136 }
137
138
139 static int sort_use(const struct slab_info *a, const struct slab_info *b)
140 {
141         return (a->use > b->use);
142 }
143
144 static int sort_cache_size(const struct slab_info *a, const struct slab_info *b)
145 {
146         return (a->cache_size > b->cache_size);
147 }
148
149 /*
150  * term_size - set the globals 'cols' and 'rows' to the current terminal size
151  */
152 static void term_size(int unused)
153 {
154         struct winsize ws;
155         (void) unused;
156
157         if ((ioctl(1, TIOCGWINSZ, &ws) != -1) && ws.ws_row > 10) {
158                 cols = ws.ws_col;
159                 rows = ws.ws_row;
160         } else {
161                 cols = 80;
162                 rows = 24;
163         }
164 }
165
166 static void sigint_handler(int unused)
167 {
168         (void) unused;
169
170         delay = 0;
171 }
172
173 static void usage(const char *cmd)
174 {
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");
197 }
198
199 /*
200  * set_sort_func - return the slab_sort_func that matches the given key.
201  * On unrecognizable key, DEF_SORT_FUNC is returned.
202  */
203 static void * set_sort_func(char key)
204 {
205         switch (key) {
206         case 'n':
207                 return sort_name;
208         case 'o':
209                 return sort_nr_objs;
210         case 'a':
211                 return sort_nr_active_objs;
212         case 's':
213                 return sort_obj_size;
214         case 'b':
215                 return sort_objs_per_slab;
216         case 'p':
217                 return sort_pages_per_slab;
218         case 'l':
219                 return sort_nr_slabs;
220         case 'v':
221                 return sort_nr_active_slabs;
222         case 'c':
223                 return sort_cache_size;
224         case 'u':
225                 return sort_use;
226         default:
227                 return DEF_SORT_FUNC;
228         }
229 }
230
231 static void parse_input(char c)
232 {
233         c = toupper(c);
234         switch(c) {
235         case 'A':
236                 sort_func = sort_nr_active_objs;
237                 break;
238         case 'B':
239                 sort_func = sort_objs_per_slab;
240                 break;
241         case 'C':
242                 sort_func = sort_cache_size;
243                 break;
244         case 'L':
245                 sort_func = sort_nr_slabs;
246                 break;
247         case 'V':
248                 sort_func = sort_nr_active_slabs;
249                 break;
250         case 'N':
251                 sort_func = sort_name;
252                 break;
253         case 'O':
254                 sort_func = sort_nr_objs;
255                 break;
256         case 'P':
257                 sort_func = sort_pages_per_slab;
258                 break;
259         case 'S':
260                 sort_func = sort_obj_size;
261                 break;
262         case 'U':
263                 sort_func = sort_use;
264                 break;
265         case 'Q':
266                 delay = 0;
267                 break;
268         }
269 }
270
271 int main(int argc, char *argv[])
272 {
273         int o;
274         unsigned short old_rows;
275         struct slab_info *slab_list = NULL;
276
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' },
283                 {  NULL,        0, NULL, 0 }
284         };
285
286         sort_func = DEF_SORT_FUNC;
287
288         while ((o = getopt_long(argc, argv, "d:s:ohV", longopts, NULL)) != -1) {
289                 int ret = 1;
290
291                 switch (o) {
292                 case 'd':
293                         errno = 0;
294                         delay = strtol(optarg, NULL, 10);
295                         if (errno) {
296                                 perror("strtoul");
297                                 return 1;
298                         }
299                         if (delay < 0) {
300                                 fprintf(stderr, "error: can't have a "\
301                                         "negative delay\n");
302                                 exit(1);
303                         }
304                         break;
305                 case 's':
306                         sort_func = set_sort_func(optarg[0]);
307                         break;
308                 case 'o':
309                         delay = 0;
310                         break;
311                 case 'V':
312                         display_version();
313                         return 0;
314                 case 'h':
315                         ret = 0;
316                 default:
317                         usage(argv[0]);
318                         return ret;
319                 }
320         }
321
322         if (tcgetattr(0, &saved_tty) == -1)
323                 perror("tcgetattr");
324
325         initscr();
326         term_size(0);
327         old_rows = rows;
328         resizeterm(rows, cols);
329         signal(SIGWINCH, term_size);
330         signal(SIGINT, sigint_handler);
331
332         do {
333                 struct slab_info *curr;
334                 struct slab_stat stats = SLAB_STAT_ZERO;
335                 struct timeval tv;
336                 fd_set readfds;
337                 char c;
338                 int i;
339
340                 if (get_slabinfo(&slab_list, &stats))
341                         break;
342
343                 if (old_rows != rows) {
344                         resizeterm(rows, cols);
345                         old_rows = rows;
346                 }
347
348                 move(0,0);
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
359                 );
360
361                 slab_list = slabsort(slab_list);
362
363                 attron(A_REVERSE);
364                 printw( "%6s %6s %4s %8s %6s %8s %10s %-23s\n",
365                         "OBJS", "ACTIVE", "USE", "OBJ SIZE", "SLABS",
366                         "OBJ/SLAB", "CACHE SIZE", "NAME");
367                 attroff(A_REVERSE);
368
369                 curr = slab_list;
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),
375                                 curr->name);
376                         curr = curr->next;
377                 }
378
379                 refresh();
380                 put_slabinfo(slab_list);
381
382                 FD_ZERO(&readfds);
383                 FD_SET(0, &readfds);
384                 tv.tv_sec = delay;
385                 tv.tv_usec = 0;
386                 if (select(1, &readfds, NULL, NULL, &tv) > 0) {
387                         if (read(0, &c, 1) != 1)
388                                 break;
389                         parse_input(c);
390                 }
391         } while (delay);
392
393         tcsetattr(0, TCSAFLUSH, &saved_tty);
394         free_slabinfo(slab_list);
395         endwin();
396         return 0;
397 }