Home | History | Annotate | Download | only in showslab
      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 }
    352