OSDN Git Service

Add missing include headers for compilation on Intel SDK for Google TV.
[android-x86/system-extras.git] / showslab / showslab.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <errno.h>
6 #include <ctype.h>
7 #include <limits.h>
8
9 #define STRINGIFY_ARG(a)        #a
10 #define STRINGIFY(a)            STRINGIFY_ARG(a)
11
12 #define DEF_SORT_FUNC           sort_nr_objs
13 #define SLABINFO_LINE_LEN       512     /* size of longest line */
14 #define SLABINFO_NAME_LEN       32      /* cache name size (will truncate) */
15 #define SLABINFO_FILE           "/proc/slabinfo"
16 #define DEF_NR_ROWS             15      /* default nr of caches to show */
17
18 /* object representing a slab cache (each line of slabinfo) */
19 struct slab_info {
20         char name[SLABINFO_NAME_LEN];   /* name of this cache */
21         struct slab_info *next;
22         unsigned long nr_pages;         /* size of cache in pages */
23         unsigned long nr_objs;          /* number of objects in this cache */
24         unsigned long nr_active_objs;   /* number of active objects */
25         unsigned long obj_size;         /* size of each object */
26         unsigned long objs_per_slab;    /* number of objects per slab */
27         unsigned long nr_slabs;         /* number of slabs in this cache */
28         unsigned long use;              /* percent full: total / active */
29 };
30
31 /* object representing system-wide statistics */
32 struct slab_stat {
33         unsigned long total_size;       /* size of all objects */
34         unsigned long active_size;      /* size of all active objects */
35         unsigned long nr_objs;          /* total number of objects */
36         unsigned long nr_active_objs;   /* total number of active objects */
37         unsigned long nr_slabs;         /* total number of slabs */
38         unsigned long nr_active_slabs;  /* total number of active slabs*/
39         unsigned long nr_caches;        /* number of caches */
40         unsigned long nr_active_caches; /* number of active caches */
41         unsigned long avg_obj_size;     /* average object size */
42         unsigned long min_obj_size;     /* size of smallest object */
43         unsigned long max_obj_size;     /* size of largest object */
44 };
45
46 typedef int (*sort_t)(const struct slab_info *, const struct slab_info *);
47 static sort_t sort_func;
48
49 /*
50  * get_slabinfo - open, read, and parse a slabinfo 2.x file, which has the
51  * following format:
52  *
53  * slabinfo - version: 2.1
54  * <name>  <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab>
55  * : tunables <limit> <batchcount> <sharedfactor>
56  * : slabdata <active_slabs> <num_slabs> <sharedavail>
57  *
58  * Returns the head of the new list of slab_info structures, or NULL on error.
59  */
60 static struct slab_info * get_slabinfo(struct slab_stat *stats)
61 {
62         struct slab_info *head = NULL, *p = NULL, *prev = NULL;
63         FILE *slabfile;
64         char line[SLABINFO_LINE_LEN];
65         unsigned int major, minor;
66
67         slabfile = fopen(SLABINFO_FILE, "r");
68         if (!slabfile) {
69                 perror("fopen");
70                 return NULL;
71         }
72
73         if (!fgets(line, SLABINFO_LINE_LEN, slabfile)) {
74                 fprintf(stderr, "cannot read from " SLABINFO_FILE "\n");
75                 return NULL;
76         }
77
78         if (sscanf(line, "slabinfo - version: %u.%u", &major, &minor) != 2) {
79                 fprintf(stderr, "unable to parse slabinfo version!\n");
80                 return NULL;
81         }
82
83         if (major != 2 || minor > 1) {
84                 fprintf(stderr, "we only support slabinfo 2.0 and 2.1!\n");
85                 return NULL;
86         }
87
88         stats->min_obj_size = INT_MAX;
89
90         while (fgets(line, SLABINFO_LINE_LEN, slabfile)) {
91                 unsigned long nr_active_slabs, pages_per_slab;
92                 int ret;
93
94                 if (line[0] == '#')
95                         continue;
96
97                 p = malloc(sizeof (struct slab_info));
98                 if (!p) {
99                         perror("malloc");
100                         head = NULL;
101                         break;
102                 }
103                 if (stats->nr_caches++ == 0)
104                         head = prev = p;
105
106                 ret = sscanf(line, "%" STRINGIFY(SLABINFO_NAME_LEN) "s"
107                              " %lu %lu %lu %lu %lu : tunables %*d %*d %*d : \
108                              slabdata %lu %lu %*d", p->name, 
109                              &p->nr_active_objs, &p->nr_objs, 
110                              &p->obj_size, &p->objs_per_slab,
111                              &pages_per_slab,
112                              &nr_active_slabs,
113                              &p->nr_slabs);
114
115                 if (ret != 8) {
116                         fprintf(stderr, "unrecognizable data in slabinfo!\n");
117                         head = NULL;
118                         break;
119                 }
120
121                 if (p->obj_size < stats->min_obj_size)
122                         stats->min_obj_size = p->obj_size;
123                 if (p->obj_size > stats->max_obj_size)
124                         stats->max_obj_size = p->obj_size;
125
126                 p->nr_pages = p->nr_slabs * pages_per_slab;
127
128                 if (p->nr_objs) {
129                         p->use = 100 * p->nr_active_objs / p->nr_objs;
130                         stats->nr_active_caches++;
131                 } else
132                         p->use = 0;
133
134                 stats->nr_objs += p->nr_objs;
135                 stats->nr_active_objs += p->nr_active_objs;
136                 stats->total_size += p->nr_objs * p->obj_size;
137                 stats->active_size += p->nr_active_objs * p->obj_size;
138                 stats->nr_slabs += p->nr_slabs;
139                 stats->nr_active_slabs += nr_active_slabs;
140
141                 prev->next = p;
142                 prev = p;
143         }
144
145         if (fclose(slabfile))
146                 perror("fclose");
147
148         if (p)
149                 p->next = NULL;
150         if (stats->nr_objs)
151                 stats->avg_obj_size = stats->total_size / stats->nr_objs;
152
153         return head;
154 }
155
156 /*
157  * free_slablist - deallocate the memory associated with each node in the
158  * provided slab_info linked list
159  */
160 static void free_slablist(struct slab_info *list)
161 {
162         while (list) {
163                 struct slab_info *temp = list->next;
164                 free(list);
165                 list = temp;
166         }
167 }
168
169 static struct slab_info *merge_objs(struct slab_info *a, struct slab_info *b)
170 {
171         struct slab_info list;
172         struct slab_info *p = &list;
173
174         while (a && b) {
175                 if (sort_func(a, b)) {
176                         p->next = a;
177                         p = a;
178                         a = a->next;
179                 } else {
180                         p->next = b;
181                         p = b;
182                         b = b->next;
183                 }
184         }
185
186         p->next = (a == NULL) ? b : a;
187         return list.next;
188 }
189
190 /* 
191  * slabsort - merge sort the slab_info linked list based on sort_func
192  */
193 static struct slab_info *slabsort(struct slab_info *list)
194 {
195         struct slab_info *a, *b;
196
197         if (!list || !list->next)
198                 return list;
199
200         a = list;
201         b = list->next;
202
203         while (b && b->next) {
204                 list = list->next;
205                 b = b->next->next;
206         }
207
208         b = list->next;
209         list->next = NULL;
210
211         return merge_objs(slabsort(a), slabsort(b));
212 }
213
214 /*
215  * Sort Routines.  Each of these should be associated with a command-line
216  * search option.  The functions should fit the prototype:
217  *
218  *      int sort_foo(const struct slab_info *a, const struct slab_info *b)
219  *
220  * They return zero if the first parameter is smaller than the second.
221  * Otherwise, they return nonzero.
222  */
223
224 static int sort_name(const struct slab_info *a, const struct slab_info *b)
225 {
226         return (strcmp(a->name, b->name) < 0 ) ? 1: 0;
227 }
228
229 #define BUILD_SORT_FUNC(VAL) \
230         static int sort_ ## VAL \
231                 (const struct slab_info *a, const struct slab_info *b) { \
232                         return (a-> VAL > b-> VAL); }
233
234 BUILD_SORT_FUNC(nr_objs)
235 BUILD_SORT_FUNC(nr_active_objs)
236 BUILD_SORT_FUNC(obj_size)
237 BUILD_SORT_FUNC(objs_per_slab)
238 BUILD_SORT_FUNC(nr_slabs)
239 BUILD_SORT_FUNC(use)
240 BUILD_SORT_FUNC(nr_pages)
241
242 /*
243  * set_sort_func - return the slab_sort_func that matches the given key.
244  * On unrecognizable key, the call returns NULL.
245  */
246 static void * set_sort_func(char key)
247 {
248         switch (tolower(key)) {
249         case 'a':
250                 return sort_nr_active_objs;
251         case 'c':
252                 return sort_nr_pages;
253         case 'l':
254                 return sort_nr_slabs;   
255         case 'n':
256                 return sort_name;
257         case 'o':
258                 return sort_nr_objs;
259         case 'p':
260                 return sort_objs_per_slab;      
261         case 's':
262                 return sort_obj_size;
263         case 'u':
264                 return sort_use;
265         default:
266                 return NULL;
267         }
268 }
269
270 int main(int argc, char *argv[])
271 {
272         struct slab_info *list, *p;
273         struct slab_stat stats = { .nr_objs = 0 };
274         unsigned int page_size = getpagesize() / 1024, nr_rows = DEF_NR_ROWS, i;
275
276         sort_func = DEF_SORT_FUNC;
277
278         if (argc > 1) {
279                 /* FIXME: Ugh. */
280                 if (argc == 3 && !strcmp(argv[1], "-n")) {
281                         errno = 0;
282                         nr_rows = (unsigned int) strtoul(argv[2], NULL, 0);
283                         if (errno) {
284                                 perror("strtoul");
285                                 exit(EXIT_FAILURE);
286                         }
287                 }
288                 else if (argc == 3 && !strcmp(argv[1], "-s"))
289                         sort_func = set_sort_func(argv[2][0]) ? : DEF_SORT_FUNC;
290                 else {
291                         fprintf(stderr, "usage: %s [options]\n\n", argv[0]);
292                         fprintf(stderr, "options:\n");
293                         fprintf(stderr, "  -s S   specify sort criteria S\n");
294                         fprintf(stderr, "  -h     display this help\n\n");
295                         fprintf(stderr, "Valid sort criteria:\n");
296                         fprintf(stderr, "  a: number of Active objects\n");
297                         fprintf(stderr, "  c: Cache size\n");
298                         fprintf(stderr, "  l: number of sLabs\n");
299                         fprintf(stderr, "  n: Name\n");
300                         fprintf(stderr, "  o: number of Objects\n");
301                         fprintf(stderr, "  p: objects Per slab\n");
302                         fprintf(stderr, "  s: object Size\n");
303                         fprintf(stderr, "  u: cache Utilization\n");
304                         exit(EXIT_FAILURE);
305                 }
306         }
307
308         list = get_slabinfo (&stats);
309         if (!list)
310                 exit(EXIT_FAILURE);
311
312         printf(" Active / Total Objects (%% used) : %lu / %lu (%.1f%%)\n"
313                " Active / Total Slabs (%% used)   : %lu / %lu (%.1f%%)\n"
314                " Active / Total Caches (%% used)  : %lu / %lu (%.1f%%)\n"
315                " Active / Total Size (%% used)    : %.2fK / %.2fK (%.1f%%)\n"
316                " Min / Avg / Max Object Size     : %.2fK / %.2fK / %.2fK\n\n",
317                stats.nr_active_objs,
318                stats.nr_objs,
319                100.0 * stats.nr_active_objs / stats.nr_objs,
320                stats.nr_active_slabs,
321                stats.nr_slabs,
322                100.0 * stats.nr_active_slabs / stats.nr_slabs,
323                stats.nr_active_caches,
324                stats.nr_caches,
325                100.0 * stats.nr_active_caches / stats.nr_caches,
326                stats.active_size / 1024.0,
327                stats.total_size / 1024.0,
328                100.0 * stats.active_size / stats.total_size,
329                stats.min_obj_size / 1024.0,
330                stats.avg_obj_size / 1024.0,
331                stats.max_obj_size / 1024.0);
332
333         printf("%6s %6s %4s %8s %6s %8s %10s %-23s\n",
334                "OBJS", "ACTIVE", "USE", "OBJ SIZE", "SLABS",
335                "OBJ/SLAB", "CACHE SIZE", "NAME");
336
337         p = list = slabsort(list);
338         for (i = 0; i < nr_rows && p; i++) {
339                 printf("%6lu %6lu %3lu%% %7.2fK %6lu %8lu %9luK %-23s\n",
340                        p->nr_objs, p->nr_active_objs, p->use,
341                        p->obj_size / 1024.0, p->nr_slabs,
342                        p->objs_per_slab,
343                        p->nr_pages * page_size,
344                        p->name);
345                 p = p->next;
346         }
347
348         free_slablist(list);
349
350         return 0;
351 }