• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Slabinfo: Tool to get reports about slabs
3  *
4  * (C) 2007 sgi, Christoph Lameter
5  *
6  * Compile by:
7  *
8  * gcc -o slabinfo slabinfo.c
9  */
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <sys/types.h>
13 #include <dirent.h>
14 #include <strings.h>
15 #include <string.h>
16 #include <unistd.h>
17 #include <stdarg.h>
18 #include <getopt.h>
19 #include <regex.h>
20 #include <errno.h>
21 
22 #define MAX_SLABS 500
23 #define MAX_ALIASES 500
24 #define MAX_NODES 1024
25 
26 struct slabinfo {
27 	char *name;
28 	int alias;
29 	int refs;
30 	int aliases, align, cache_dma, cpu_slabs, destroy_by_rcu;
31 	int hwcache_align, object_size, objs_per_slab;
32 	int sanity_checks, slab_size, store_user, trace;
33 	int order, poison, reclaim_account, red_zone;
34 	unsigned long partial, objects, slabs, objects_partial, objects_total;
35 	unsigned long alloc_fastpath, alloc_slowpath;
36 	unsigned long free_fastpath, free_slowpath;
37 	unsigned long free_frozen, free_add_partial, free_remove_partial;
38 	unsigned long alloc_from_partial, alloc_slab, free_slab, alloc_refill;
39 	unsigned long cpuslab_flush, deactivate_full, deactivate_empty;
40 	unsigned long deactivate_to_head, deactivate_to_tail;
41 	unsigned long deactivate_remote_frees, order_fallback;
42 	int numa[MAX_NODES];
43 	int numa_partial[MAX_NODES];
44 } slabinfo[MAX_SLABS];
45 
46 struct aliasinfo {
47 	char *name;
48 	char *ref;
49 	struct slabinfo *slab;
50 } aliasinfo[MAX_ALIASES];
51 
52 int slabs = 0;
53 int actual_slabs = 0;
54 int aliases = 0;
55 int alias_targets = 0;
56 int highest_node = 0;
57 
58 char buffer[4096];
59 
60 int show_empty = 0;
61 int show_report = 0;
62 int show_alias = 0;
63 int show_slab = 0;
64 int skip_zero = 1;
65 int show_numa = 0;
66 int show_track = 0;
67 int show_first_alias = 0;
68 int validate = 0;
69 int shrink = 0;
70 int show_inverted = 0;
71 int show_single_ref = 0;
72 int show_totals = 0;
73 int sort_size = 0;
74 int sort_active = 0;
75 int set_debug = 0;
76 int show_ops = 0;
77 int show_activity = 0;
78 
79 /* Debug options */
80 int sanity = 0;
81 int redzone = 0;
82 int poison = 0;
83 int tracking = 0;
84 int tracing = 0;
85 
86 int page_size;
87 
88 regex_t pattern;
89 
fatal(const char * x,...)90 void fatal(const char *x, ...)
91 {
92 	va_list ap;
93 
94 	va_start(ap, x);
95 	vfprintf(stderr, x, ap);
96 	va_end(ap);
97 	exit(EXIT_FAILURE);
98 }
99 
usage(void)100 void usage(void)
101 {
102 	printf("slabinfo 5/7/2007. (c) 2007 sgi.\n\n"
103 		"slabinfo [-ahnpvtsz] [-d debugopts] [slab-regexp]\n"
104 		"-a|--aliases           Show aliases\n"
105 		"-A|--activity          Most active slabs first\n"
106 		"-d<options>|--debug=<options> Set/Clear Debug options\n"
107 		"-D|--display-active    Switch line format to activity\n"
108 		"-e|--empty             Show empty slabs\n"
109 		"-f|--first-alias       Show first alias\n"
110 		"-h|--help              Show usage information\n"
111 		"-i|--inverted          Inverted list\n"
112 		"-l|--slabs             Show slabs\n"
113 		"-n|--numa              Show NUMA information\n"
114 		"-o|--ops		Show kmem_cache_ops\n"
115 		"-s|--shrink            Shrink slabs\n"
116 		"-r|--report		Detailed report on single slabs\n"
117 		"-S|--Size              Sort by size\n"
118 		"-t|--tracking          Show alloc/free information\n"
119 		"-T|--Totals            Show summary information\n"
120 		"-v|--validate          Validate slabs\n"
121 		"-z|--zero              Include empty slabs\n"
122 		"-1|--1ref              Single reference\n"
123 		"\nValid debug options (FZPUT may be combined)\n"
124 		"a / A          Switch on all debug options (=FZUP)\n"
125 		"-              Switch off all debug options\n"
126 		"f / F          Sanity Checks (SLAB_DEBUG_FREE)\n"
127 		"z / Z          Redzoning\n"
128 		"p / P          Poisoning\n"
129 		"u / U          Tracking\n"
130 		"t / T          Tracing\n"
131 	);
132 }
133 
read_obj(const char * name)134 unsigned long read_obj(const char *name)
135 {
136 	FILE *f = fopen(name, "r");
137 
138 	if (!f)
139 		buffer[0] = 0;
140 	else {
141 		if (!fgets(buffer, sizeof(buffer), f))
142 			buffer[0] = 0;
143 		fclose(f);
144 		if (buffer[strlen(buffer)] == '\n')
145 			buffer[strlen(buffer)] = 0;
146 	}
147 	return strlen(buffer);
148 }
149 
150 
151 /*
152  * Get the contents of an attribute
153  */
get_obj(const char * name)154 unsigned long get_obj(const char *name)
155 {
156 	if (!read_obj(name))
157 		return 0;
158 
159 	return atol(buffer);
160 }
161 
get_obj_and_str(const char * name,char ** x)162 unsigned long get_obj_and_str(const char *name, char **x)
163 {
164 	unsigned long result = 0;
165 	char *p;
166 
167 	*x = NULL;
168 
169 	if (!read_obj(name)) {
170 		x = NULL;
171 		return 0;
172 	}
173 	result = strtoul(buffer, &p, 10);
174 	while (*p == ' ')
175 		p++;
176 	if (*p)
177 		*x = strdup(p);
178 	return result;
179 }
180 
set_obj(struct slabinfo * s,const char * name,int n)181 void set_obj(struct slabinfo *s, const char *name, int n)
182 {
183 	char x[100];
184 	FILE *f;
185 
186 	snprintf(x, 100, "%s/%s", s->name, name);
187 	f = fopen(x, "w");
188 	if (!f)
189 		fatal("Cannot write to %s\n", x);
190 
191 	fprintf(f, "%d\n", n);
192 	fclose(f);
193 }
194 
read_slab_obj(struct slabinfo * s,const char * name)195 unsigned long read_slab_obj(struct slabinfo *s, const char *name)
196 {
197 	char x[100];
198 	FILE *f;
199 	size_t l;
200 
201 	snprintf(x, 100, "%s/%s", s->name, name);
202 	f = fopen(x, "r");
203 	if (!f) {
204 		buffer[0] = 0;
205 		l = 0;
206 	} else {
207 		l = fread(buffer, 1, sizeof(buffer), f);
208 		buffer[l] = 0;
209 		fclose(f);
210 	}
211 	return l;
212 }
213 
214 
215 /*
216  * Put a size string together
217  */
store_size(char * buffer,unsigned long value)218 int store_size(char *buffer, unsigned long value)
219 {
220 	unsigned long divisor = 1;
221 	char trailer = 0;
222 	int n;
223 
224 	if (value > 1000000000UL) {
225 		divisor = 100000000UL;
226 		trailer = 'G';
227 	} else if (value > 1000000UL) {
228 		divisor = 100000UL;
229 		trailer = 'M';
230 	} else if (value > 1000UL) {
231 		divisor = 100;
232 		trailer = 'K';
233 	}
234 
235 	value /= divisor;
236 	n = sprintf(buffer, "%ld",value);
237 	if (trailer) {
238 		buffer[n] = trailer;
239 		n++;
240 		buffer[n] = 0;
241 	}
242 	if (divisor != 1) {
243 		memmove(buffer + n - 2, buffer + n - 3, 4);
244 		buffer[n-2] = '.';
245 		n++;
246 	}
247 	return n;
248 }
249 
decode_numa_list(int * numa,char * t)250 void decode_numa_list(int *numa, char *t)
251 {
252 	int node;
253 	int nr;
254 
255 	memset(numa, 0, MAX_NODES * sizeof(int));
256 
257 	if (!t)
258 		return;
259 
260 	while (*t == 'N') {
261 		t++;
262 		node = strtoul(t, &t, 10);
263 		if (*t == '=') {
264 			t++;
265 			nr = strtoul(t, &t, 10);
266 			numa[node] = nr;
267 			if (node > highest_node)
268 				highest_node = node;
269 		}
270 		while (*t == ' ')
271 			t++;
272 	}
273 }
274 
slab_validate(struct slabinfo * s)275 void slab_validate(struct slabinfo *s)
276 {
277 	if (strcmp(s->name, "*") == 0)
278 		return;
279 
280 	set_obj(s, "validate", 1);
281 }
282 
slab_shrink(struct slabinfo * s)283 void slab_shrink(struct slabinfo *s)
284 {
285 	if (strcmp(s->name, "*") == 0)
286 		return;
287 
288 	set_obj(s, "shrink", 1);
289 }
290 
291 int line = 0;
292 
first_line(void)293 void first_line(void)
294 {
295 	if (show_activity)
296 		printf("Name                   Objects      Alloc       Free   %%Fast Fallb O\n");
297 	else
298 		printf("Name                   Objects Objsize    Space "
299 			"Slabs/Part/Cpu  O/S O %%Fr %%Ef Flg\n");
300 }
301 
302 /*
303  * Find the shortest alias of a slab
304  */
find_one_alias(struct slabinfo * find)305 struct aliasinfo *find_one_alias(struct slabinfo *find)
306 {
307 	struct aliasinfo *a;
308 	struct aliasinfo *best = NULL;
309 
310 	for(a = aliasinfo;a < aliasinfo + aliases; a++) {
311 		if (a->slab == find &&
312 			(!best || strlen(best->name) < strlen(a->name))) {
313 				best = a;
314 				if (strncmp(a->name,"kmall", 5) == 0)
315 					return best;
316 			}
317 	}
318 	return best;
319 }
320 
slab_size(struct slabinfo * s)321 unsigned long slab_size(struct slabinfo *s)
322 {
323 	return 	s->slabs * (page_size << s->order);
324 }
325 
slab_activity(struct slabinfo * s)326 unsigned long slab_activity(struct slabinfo *s)
327 {
328 	return 	s->alloc_fastpath + s->free_fastpath +
329 		s->alloc_slowpath + s->free_slowpath;
330 }
331 
slab_numa(struct slabinfo * s,int mode)332 void slab_numa(struct slabinfo *s, int mode)
333 {
334 	int node;
335 
336 	if (strcmp(s->name, "*") == 0)
337 		return;
338 
339 	if (!highest_node) {
340 		printf("\n%s: No NUMA information available.\n", s->name);
341 		return;
342 	}
343 
344 	if (skip_zero && !s->slabs)
345 		return;
346 
347 	if (!line) {
348 		printf("\n%-21s:", mode ? "NUMA nodes" : "Slab");
349 		for(node = 0; node <= highest_node; node++)
350 			printf(" %4d", node);
351 		printf("\n----------------------");
352 		for(node = 0; node <= highest_node; node++)
353 			printf("-----");
354 		printf("\n");
355 	}
356 	printf("%-21s ", mode ? "All slabs" : s->name);
357 	for(node = 0; node <= highest_node; node++) {
358 		char b[20];
359 
360 		store_size(b, s->numa[node]);
361 		printf(" %4s", b);
362 	}
363 	printf("\n");
364 	if (mode) {
365 		printf("%-21s ", "Partial slabs");
366 		for(node = 0; node <= highest_node; node++) {
367 			char b[20];
368 
369 			store_size(b, s->numa_partial[node]);
370 			printf(" %4s", b);
371 		}
372 		printf("\n");
373 	}
374 	line++;
375 }
376 
show_tracking(struct slabinfo * s)377 void show_tracking(struct slabinfo *s)
378 {
379 	printf("\n%s: Kernel object allocation\n", s->name);
380 	printf("-----------------------------------------------------------------------\n");
381 	if (read_slab_obj(s, "alloc_calls"))
382 		printf(buffer);
383 	else
384 		printf("No Data\n");
385 
386 	printf("\n%s: Kernel object freeing\n", s->name);
387 	printf("------------------------------------------------------------------------\n");
388 	if (read_slab_obj(s, "free_calls"))
389 		printf(buffer);
390 	else
391 		printf("No Data\n");
392 
393 }
394 
ops(struct slabinfo * s)395 void ops(struct slabinfo *s)
396 {
397 	if (strcmp(s->name, "*") == 0)
398 		return;
399 
400 	if (read_slab_obj(s, "ops")) {
401 		printf("\n%s: kmem_cache operations\n", s->name);
402 		printf("--------------------------------------------\n");
403 		printf(buffer);
404 	} else
405 		printf("\n%s has no kmem_cache operations\n", s->name);
406 }
407 
onoff(int x)408 const char *onoff(int x)
409 {
410 	if (x)
411 		return "On ";
412 	return "Off";
413 }
414 
slab_stats(struct slabinfo * s)415 void slab_stats(struct slabinfo *s)
416 {
417 	unsigned long total_alloc;
418 	unsigned long total_free;
419 	unsigned long total;
420 
421 	if (!s->alloc_slab)
422 		return;
423 
424 	total_alloc = s->alloc_fastpath + s->alloc_slowpath;
425 	total_free = s->free_fastpath + s->free_slowpath;
426 
427 	if (!total_alloc)
428 		return;
429 
430 	printf("\n");
431 	printf("Slab Perf Counter       Alloc     Free %%Al %%Fr\n");
432 	printf("--------------------------------------------------\n");
433 	printf("Fastpath             %8lu %8lu %3lu %3lu\n",
434 		s->alloc_fastpath, s->free_fastpath,
435 		s->alloc_fastpath * 100 / total_alloc,
436 		s->free_fastpath * 100 / total_free);
437 	printf("Slowpath             %8lu %8lu %3lu %3lu\n",
438 		total_alloc - s->alloc_fastpath, s->free_slowpath,
439 		(total_alloc - s->alloc_fastpath) * 100 / total_alloc,
440 		s->free_slowpath * 100 / total_free);
441 	printf("Page Alloc           %8lu %8lu %3lu %3lu\n",
442 		s->alloc_slab, s->free_slab,
443 		s->alloc_slab * 100 / total_alloc,
444 		s->free_slab * 100 / total_free);
445 	printf("Add partial          %8lu %8lu %3lu %3lu\n",
446 		s->deactivate_to_head + s->deactivate_to_tail,
447 		s->free_add_partial,
448 		(s->deactivate_to_head + s->deactivate_to_tail) * 100 / total_alloc,
449 		s->free_add_partial * 100 / total_free);
450 	printf("Remove partial       %8lu %8lu %3lu %3lu\n",
451 		s->alloc_from_partial, s->free_remove_partial,
452 		s->alloc_from_partial * 100 / total_alloc,
453 		s->free_remove_partial * 100 / total_free);
454 
455 	printf("RemoteObj/SlabFrozen %8lu %8lu %3lu %3lu\n",
456 		s->deactivate_remote_frees, s->free_frozen,
457 		s->deactivate_remote_frees * 100 / total_alloc,
458 		s->free_frozen * 100 / total_free);
459 
460 	printf("Total                %8lu %8lu\n\n", total_alloc, total_free);
461 
462 	if (s->cpuslab_flush)
463 		printf("Flushes %8lu\n", s->cpuslab_flush);
464 
465 	if (s->alloc_refill)
466 		printf("Refill %8lu\n", s->alloc_refill);
467 
468 	total = s->deactivate_full + s->deactivate_empty +
469 			s->deactivate_to_head + s->deactivate_to_tail;
470 
471 	if (total)
472 		printf("Deactivate Full=%lu(%lu%%) Empty=%lu(%lu%%) "
473 			"ToHead=%lu(%lu%%) ToTail=%lu(%lu%%)\n",
474 			s->deactivate_full, (s->deactivate_full * 100) / total,
475 			s->deactivate_empty, (s->deactivate_empty * 100) / total,
476 			s->deactivate_to_head, (s->deactivate_to_head * 100) / total,
477 			s->deactivate_to_tail, (s->deactivate_to_tail * 100) / total);
478 }
479 
report(struct slabinfo * s)480 void report(struct slabinfo *s)
481 {
482 	if (strcmp(s->name, "*") == 0)
483 		return;
484 
485 	printf("\nSlabcache: %-20s  Aliases: %2d Order : %2d Objects: %lu\n",
486 		s->name, s->aliases, s->order, s->objects);
487 	if (s->hwcache_align)
488 		printf("** Hardware cacheline aligned\n");
489 	if (s->cache_dma)
490 		printf("** Memory is allocated in a special DMA zone\n");
491 	if (s->destroy_by_rcu)
492 		printf("** Slabs are destroyed via RCU\n");
493 	if (s->reclaim_account)
494 		printf("** Reclaim accounting active\n");
495 
496 	printf("\nSizes (bytes)     Slabs              Debug                Memory\n");
497 	printf("------------------------------------------------------------------------\n");
498 	printf("Object : %7d  Total  : %7ld   Sanity Checks : %s  Total: %7ld\n",
499 			s->object_size, s->slabs, onoff(s->sanity_checks),
500 			s->slabs * (page_size << s->order));
501 	printf("SlabObj: %7d  Full   : %7ld   Redzoning     : %s  Used : %7ld\n",
502 			s->slab_size, s->slabs - s->partial - s->cpu_slabs,
503 			onoff(s->red_zone), s->objects * s->object_size);
504 	printf("SlabSiz: %7d  Partial: %7ld   Poisoning     : %s  Loss : %7ld\n",
505 			page_size << s->order, s->partial, onoff(s->poison),
506 			s->slabs * (page_size << s->order) - s->objects * s->object_size);
507 	printf("Loss   : %7d  CpuSlab: %7d   Tracking      : %s  Lalig: %7ld\n",
508 			s->slab_size - s->object_size, s->cpu_slabs, onoff(s->store_user),
509 			(s->slab_size - s->object_size) * s->objects);
510 	printf("Align  : %7d  Objects: %7d   Tracing       : %s  Lpadd: %7ld\n",
511 			s->align, s->objs_per_slab, onoff(s->trace),
512 			((page_size << s->order) - s->objs_per_slab * s->slab_size) *
513 			s->slabs);
514 
515 	ops(s);
516 	show_tracking(s);
517 	slab_numa(s, 1);
518 	slab_stats(s);
519 }
520 
slabcache(struct slabinfo * s)521 void slabcache(struct slabinfo *s)
522 {
523 	char size_str[20];
524 	char dist_str[40];
525 	char flags[20];
526 	char *p = flags;
527 
528 	if (strcmp(s->name, "*") == 0)
529 		return;
530 
531 	if (actual_slabs == 1) {
532 		report(s);
533 		return;
534 	}
535 
536 	if (skip_zero && !show_empty && !s->slabs)
537 		return;
538 
539 	if (show_empty && s->slabs)
540 		return;
541 
542 	store_size(size_str, slab_size(s));
543 	snprintf(dist_str, 40, "%lu/%lu/%d", s->slabs - s->cpu_slabs,
544 						s->partial, s->cpu_slabs);
545 
546 	if (!line++)
547 		first_line();
548 
549 	if (s->aliases)
550 		*p++ = '*';
551 	if (s->cache_dma)
552 		*p++ = 'd';
553 	if (s->hwcache_align)
554 		*p++ = 'A';
555 	if (s->poison)
556 		*p++ = 'P';
557 	if (s->reclaim_account)
558 		*p++ = 'a';
559 	if (s->red_zone)
560 		*p++ = 'Z';
561 	if (s->sanity_checks)
562 		*p++ = 'F';
563 	if (s->store_user)
564 		*p++ = 'U';
565 	if (s->trace)
566 		*p++ = 'T';
567 
568 	*p = 0;
569 	if (show_activity) {
570 		unsigned long total_alloc;
571 		unsigned long total_free;
572 
573 		total_alloc = s->alloc_fastpath + s->alloc_slowpath;
574 		total_free = s->free_fastpath + s->free_slowpath;
575 
576 		printf("%-21s %8ld %10ld %10ld %3ld %3ld %5ld %1d\n",
577 			s->name, s->objects,
578 			total_alloc, total_free,
579 			total_alloc ? (s->alloc_fastpath * 100 / total_alloc) : 0,
580 			total_free ? (s->free_fastpath * 100 / total_free) : 0,
581 			s->order_fallback, s->order);
582 	}
583 	else
584 		printf("%-21s %8ld %7d %8s %14s %4d %1d %3ld %3ld %s\n",
585 			s->name, s->objects, s->object_size, size_str, dist_str,
586 			s->objs_per_slab, s->order,
587 			s->slabs ? (s->partial * 100) / s->slabs : 100,
588 			s->slabs ? (s->objects * s->object_size * 100) /
589 				(s->slabs * (page_size << s->order)) : 100,
590 			flags);
591 }
592 
593 /*
594  * Analyze debug options. Return false if something is amiss.
595  */
debug_opt_scan(char * opt)596 int debug_opt_scan(char *opt)
597 {
598 	if (!opt || !opt[0] || strcmp(opt, "-") == 0)
599 		return 1;
600 
601 	if (strcasecmp(opt, "a") == 0) {
602 		sanity = 1;
603 		poison = 1;
604 		redzone = 1;
605 		tracking = 1;
606 		return 1;
607 	}
608 
609 	for ( ; *opt; opt++)
610 	 	switch (*opt) {
611 		case 'F' : case 'f':
612 			if (sanity)
613 				return 0;
614 			sanity = 1;
615 			break;
616 		case 'P' : case 'p':
617 			if (poison)
618 				return 0;
619 			poison = 1;
620 			break;
621 
622 		case 'Z' : case 'z':
623 			if (redzone)
624 				return 0;
625 			redzone = 1;
626 			break;
627 
628 		case 'U' : case 'u':
629 			if (tracking)
630 				return 0;
631 			tracking = 1;
632 			break;
633 
634 		case 'T' : case 't':
635 			if (tracing)
636 				return 0;
637 			tracing = 1;
638 			break;
639 		default:
640 			return 0;
641 		}
642 	return 1;
643 }
644 
slab_empty(struct slabinfo * s)645 int slab_empty(struct slabinfo *s)
646 {
647 	if (s->objects > 0)
648 		return 0;
649 
650 	/*
651 	 * We may still have slabs even if there are no objects. Shrinking will
652 	 * remove them.
653 	 */
654 	if (s->slabs != 0)
655 		set_obj(s, "shrink", 1);
656 
657 	return 1;
658 }
659 
slab_debug(struct slabinfo * s)660 void slab_debug(struct slabinfo *s)
661 {
662 	if (strcmp(s->name, "*") == 0)
663 		return;
664 
665 	if (sanity && !s->sanity_checks) {
666 		set_obj(s, "sanity", 1);
667 	}
668 	if (!sanity && s->sanity_checks) {
669 		if (slab_empty(s))
670 			set_obj(s, "sanity", 0);
671 		else
672 			fprintf(stderr, "%s not empty cannot disable sanity checks\n", s->name);
673 	}
674 	if (redzone && !s->red_zone) {
675 		if (slab_empty(s))
676 			set_obj(s, "red_zone", 1);
677 		else
678 			fprintf(stderr, "%s not empty cannot enable redzoning\n", s->name);
679 	}
680 	if (!redzone && s->red_zone) {
681 		if (slab_empty(s))
682 			set_obj(s, "red_zone", 0);
683 		else
684 			fprintf(stderr, "%s not empty cannot disable redzoning\n", s->name);
685 	}
686 	if (poison && !s->poison) {
687 		if (slab_empty(s))
688 			set_obj(s, "poison", 1);
689 		else
690 			fprintf(stderr, "%s not empty cannot enable poisoning\n", s->name);
691 	}
692 	if (!poison && s->poison) {
693 		if (slab_empty(s))
694 			set_obj(s, "poison", 0);
695 		else
696 			fprintf(stderr, "%s not empty cannot disable poisoning\n", s->name);
697 	}
698 	if (tracking && !s->store_user) {
699 		if (slab_empty(s))
700 			set_obj(s, "store_user", 1);
701 		else
702 			fprintf(stderr, "%s not empty cannot enable tracking\n", s->name);
703 	}
704 	if (!tracking && s->store_user) {
705 		if (slab_empty(s))
706 			set_obj(s, "store_user", 0);
707 		else
708 			fprintf(stderr, "%s not empty cannot disable tracking\n", s->name);
709 	}
710 	if (tracing && !s->trace) {
711 		if (slabs == 1)
712 			set_obj(s, "trace", 1);
713 		else
714 			fprintf(stderr, "%s can only enable trace for one slab at a time\n", s->name);
715 	}
716 	if (!tracing && s->trace)
717 		set_obj(s, "trace", 1);
718 }
719 
totals(void)720 void totals(void)
721 {
722 	struct slabinfo *s;
723 
724 	int used_slabs = 0;
725 	char b1[20], b2[20], b3[20], b4[20];
726 	unsigned long long max = 1ULL << 63;
727 
728 	/* Object size */
729 	unsigned long long min_objsize = max, max_objsize = 0, avg_objsize;
730 
731 	/* Number of partial slabs in a slabcache */
732 	unsigned long long min_partial = max, max_partial = 0,
733 				avg_partial, total_partial = 0;
734 
735 	/* Number of slabs in a slab cache */
736 	unsigned long long min_slabs = max, max_slabs = 0,
737 				avg_slabs, total_slabs = 0;
738 
739 	/* Size of the whole slab */
740 	unsigned long long min_size = max, max_size = 0,
741 				avg_size, total_size = 0;
742 
743 	/* Bytes used for object storage in a slab */
744 	unsigned long long min_used = max, max_used = 0,
745 				avg_used, total_used = 0;
746 
747 	/* Waste: Bytes used for alignment and padding */
748 	unsigned long long min_waste = max, max_waste = 0,
749 				avg_waste, total_waste = 0;
750 	/* Number of objects in a slab */
751 	unsigned long long min_objects = max, max_objects = 0,
752 				avg_objects, total_objects = 0;
753 	/* Waste per object */
754 	unsigned long long min_objwaste = max,
755 				max_objwaste = 0, avg_objwaste,
756 				total_objwaste = 0;
757 
758 	/* Memory per object */
759 	unsigned long long min_memobj = max,
760 				max_memobj = 0, avg_memobj,
761 				total_objsize = 0;
762 
763 	/* Percentage of partial slabs per slab */
764 	unsigned long min_ppart = 100, max_ppart = 0,
765 				avg_ppart, total_ppart = 0;
766 
767 	/* Number of objects in partial slabs */
768 	unsigned long min_partobj = max, max_partobj = 0,
769 				avg_partobj, total_partobj = 0;
770 
771 	/* Percentage of partial objects of all objects in a slab */
772 	unsigned long min_ppartobj = 100, max_ppartobj = 0,
773 				avg_ppartobj, total_ppartobj = 0;
774 
775 
776 	for (s = slabinfo; s < slabinfo + slabs; s++) {
777 		unsigned long long size;
778 		unsigned long used;
779 		unsigned long long wasted;
780 		unsigned long long objwaste;
781 		unsigned long percentage_partial_slabs;
782 		unsigned long percentage_partial_objs;
783 
784 		if (!s->slabs || !s->objects)
785 			continue;
786 
787 		used_slabs++;
788 
789 		size = slab_size(s);
790 		used = s->objects * s->object_size;
791 		wasted = size - used;
792 		objwaste = s->slab_size - s->object_size;
793 
794 		percentage_partial_slabs = s->partial * 100 / s->slabs;
795 		if (percentage_partial_slabs > 100)
796 			percentage_partial_slabs = 100;
797 
798 		percentage_partial_objs = s->objects_partial * 100
799 							/ s->objects;
800 
801 		if (percentage_partial_objs > 100)
802 			percentage_partial_objs = 100;
803 
804 		if (s->object_size < min_objsize)
805 			min_objsize = s->object_size;
806 		if (s->partial < min_partial)
807 			min_partial = s->partial;
808 		if (s->slabs < min_slabs)
809 			min_slabs = s->slabs;
810 		if (size < min_size)
811 			min_size = size;
812 		if (wasted < min_waste)
813 			min_waste = wasted;
814 		if (objwaste < min_objwaste)
815 			min_objwaste = objwaste;
816 		if (s->objects < min_objects)
817 			min_objects = s->objects;
818 		if (used < min_used)
819 			min_used = used;
820 		if (s->objects_partial < min_partobj)
821 			min_partobj = s->objects_partial;
822 		if (percentage_partial_slabs < min_ppart)
823 			min_ppart = percentage_partial_slabs;
824 		if (percentage_partial_objs < min_ppartobj)
825 			min_ppartobj = percentage_partial_objs;
826 		if (s->slab_size < min_memobj)
827 			min_memobj = s->slab_size;
828 
829 		if (s->object_size > max_objsize)
830 			max_objsize = s->object_size;
831 		if (s->partial > max_partial)
832 			max_partial = s->partial;
833 		if (s->slabs > max_slabs)
834 			max_slabs = s->slabs;
835 		if (size > max_size)
836 			max_size = size;
837 		if (wasted > max_waste)
838 			max_waste = wasted;
839 		if (objwaste > max_objwaste)
840 			max_objwaste = objwaste;
841 		if (s->objects > max_objects)
842 			max_objects = s->objects;
843 		if (used > max_used)
844 			max_used = used;
845 		if (s->objects_partial > max_partobj)
846 			max_partobj = s->objects_partial;
847 		if (percentage_partial_slabs > max_ppart)
848 			max_ppart = percentage_partial_slabs;
849 		if (percentage_partial_objs > max_ppartobj)
850 			max_ppartobj = percentage_partial_objs;
851 		if (s->slab_size > max_memobj)
852 			max_memobj = s->slab_size;
853 
854 		total_partial += s->partial;
855 		total_slabs += s->slabs;
856 		total_size += size;
857 		total_waste += wasted;
858 
859 		total_objects += s->objects;
860 		total_used += used;
861 		total_partobj += s->objects_partial;
862 		total_ppart += percentage_partial_slabs;
863 		total_ppartobj += percentage_partial_objs;
864 
865 		total_objwaste += s->objects * objwaste;
866 		total_objsize += s->objects * s->slab_size;
867 	}
868 
869 	if (!total_objects) {
870 		printf("No objects\n");
871 		return;
872 	}
873 	if (!used_slabs) {
874 		printf("No slabs\n");
875 		return;
876 	}
877 
878 	/* Per slab averages */
879 	avg_partial = total_partial / used_slabs;
880 	avg_slabs = total_slabs / used_slabs;
881 	avg_size = total_size / used_slabs;
882 	avg_waste = total_waste / used_slabs;
883 
884 	avg_objects = total_objects / used_slabs;
885 	avg_used = total_used / used_slabs;
886 	avg_partobj = total_partobj / used_slabs;
887 	avg_ppart = total_ppart / used_slabs;
888 	avg_ppartobj = total_ppartobj / used_slabs;
889 
890 	/* Per object object sizes */
891 	avg_objsize = total_used / total_objects;
892 	avg_objwaste = total_objwaste / total_objects;
893 	avg_partobj = total_partobj * 100 / total_objects;
894 	avg_memobj = total_objsize / total_objects;
895 
896 	printf("Slabcache Totals\n");
897 	printf("----------------\n");
898 	printf("Slabcaches : %3d      Aliases  : %3d->%-3d Active: %3d\n",
899 			slabs, aliases, alias_targets, used_slabs);
900 
901 	store_size(b1, total_size);store_size(b2, total_waste);
902 	store_size(b3, total_waste * 100 / total_used);
903 	printf("Memory used: %6s   # Loss   : %6s   MRatio:%6s%%\n", b1, b2, b3);
904 
905 	store_size(b1, total_objects);store_size(b2, total_partobj);
906 	store_size(b3, total_partobj * 100 / total_objects);
907 	printf("# Objects  : %6s   # PartObj: %6s   ORatio:%6s%%\n", b1, b2, b3);
908 
909 	printf("\n");
910 	printf("Per Cache    Average         Min         Max       Total\n");
911 	printf("---------------------------------------------------------\n");
912 
913 	store_size(b1, avg_objects);store_size(b2, min_objects);
914 	store_size(b3, max_objects);store_size(b4, total_objects);
915 	printf("#Objects  %10s  %10s  %10s  %10s\n",
916 			b1,	b2,	b3,	b4);
917 
918 	store_size(b1, avg_slabs);store_size(b2, min_slabs);
919 	store_size(b3, max_slabs);store_size(b4, total_slabs);
920 	printf("#Slabs    %10s  %10s  %10s  %10s\n",
921 			b1,	b2,	b3,	b4);
922 
923 	store_size(b1, avg_partial);store_size(b2, min_partial);
924 	store_size(b3, max_partial);store_size(b4, total_partial);
925 	printf("#PartSlab %10s  %10s  %10s  %10s\n",
926 			b1,	b2,	b3,	b4);
927 	store_size(b1, avg_ppart);store_size(b2, min_ppart);
928 	store_size(b3, max_ppart);
929 	store_size(b4, total_partial * 100  / total_slabs);
930 	printf("%%PartSlab%10s%% %10s%% %10s%% %10s%%\n",
931 			b1,	b2,	b3,	b4);
932 
933 	store_size(b1, avg_partobj);store_size(b2, min_partobj);
934 	store_size(b3, max_partobj);
935 	store_size(b4, total_partobj);
936 	printf("PartObjs  %10s  %10s  %10s  %10s\n",
937 			b1,	b2,	b3,	b4);
938 
939 	store_size(b1, avg_ppartobj);store_size(b2, min_ppartobj);
940 	store_size(b3, max_ppartobj);
941 	store_size(b4, total_partobj * 100 / total_objects);
942 	printf("%% PartObj%10s%% %10s%% %10s%% %10s%%\n",
943 			b1,	b2,	b3,	b4);
944 
945 	store_size(b1, avg_size);store_size(b2, min_size);
946 	store_size(b3, max_size);store_size(b4, total_size);
947 	printf("Memory    %10s  %10s  %10s  %10s\n",
948 			b1,	b2,	b3,	b4);
949 
950 	store_size(b1, avg_used);store_size(b2, min_used);
951 	store_size(b3, max_used);store_size(b4, total_used);
952 	printf("Used      %10s  %10s  %10s  %10s\n",
953 			b1,	b2,	b3,	b4);
954 
955 	store_size(b1, avg_waste);store_size(b2, min_waste);
956 	store_size(b3, max_waste);store_size(b4, total_waste);
957 	printf("Loss      %10s  %10s  %10s  %10s\n",
958 			b1,	b2,	b3,	b4);
959 
960 	printf("\n");
961 	printf("Per Object   Average         Min         Max\n");
962 	printf("---------------------------------------------\n");
963 
964 	store_size(b1, avg_memobj);store_size(b2, min_memobj);
965 	store_size(b3, max_memobj);
966 	printf("Memory    %10s  %10s  %10s\n",
967 			b1,	b2,	b3);
968 	store_size(b1, avg_objsize);store_size(b2, min_objsize);
969 	store_size(b3, max_objsize);
970 	printf("User      %10s  %10s  %10s\n",
971 			b1,	b2,	b3);
972 
973 	store_size(b1, avg_objwaste);store_size(b2, min_objwaste);
974 	store_size(b3, max_objwaste);
975 	printf("Loss      %10s  %10s  %10s\n",
976 			b1,	b2,	b3);
977 }
978 
sort_slabs(void)979 void sort_slabs(void)
980 {
981 	struct slabinfo *s1,*s2;
982 
983 	for (s1 = slabinfo; s1 < slabinfo + slabs; s1++) {
984 		for (s2 = s1 + 1; s2 < slabinfo + slabs; s2++) {
985 			int result;
986 
987 			if (sort_size)
988 				result = slab_size(s1) < slab_size(s2);
989 			else if (sort_active)
990 				result = slab_activity(s1) < slab_activity(s2);
991 			else
992 				result = strcasecmp(s1->name, s2->name);
993 
994 			if (show_inverted)
995 				result = -result;
996 
997 			if (result > 0) {
998 				struct slabinfo t;
999 
1000 				memcpy(&t, s1, sizeof(struct slabinfo));
1001 				memcpy(s1, s2, sizeof(struct slabinfo));
1002 				memcpy(s2, &t, sizeof(struct slabinfo));
1003 			}
1004 		}
1005 	}
1006 }
1007 
sort_aliases(void)1008 void sort_aliases(void)
1009 {
1010 	struct aliasinfo *a1,*a2;
1011 
1012 	for (a1 = aliasinfo; a1 < aliasinfo + aliases; a1++) {
1013 		for (a2 = a1 + 1; a2 < aliasinfo + aliases; a2++) {
1014 			char *n1, *n2;
1015 
1016 			n1 = a1->name;
1017 			n2 = a2->name;
1018 			if (show_alias && !show_inverted) {
1019 				n1 = a1->ref;
1020 				n2 = a2->ref;
1021 			}
1022 			if (strcasecmp(n1, n2) > 0) {
1023 				struct aliasinfo t;
1024 
1025 				memcpy(&t, a1, sizeof(struct aliasinfo));
1026 				memcpy(a1, a2, sizeof(struct aliasinfo));
1027 				memcpy(a2, &t, sizeof(struct aliasinfo));
1028 			}
1029 		}
1030 	}
1031 }
1032 
link_slabs(void)1033 void link_slabs(void)
1034 {
1035 	struct aliasinfo *a;
1036 	struct slabinfo *s;
1037 
1038 	for (a = aliasinfo; a < aliasinfo + aliases; a++) {
1039 
1040 		for (s = slabinfo; s < slabinfo + slabs; s++)
1041 			if (strcmp(a->ref, s->name) == 0) {
1042 				a->slab = s;
1043 				s->refs++;
1044 				break;
1045 			}
1046 		if (s == slabinfo + slabs)
1047 			fatal("Unresolved alias %s\n", a->ref);
1048 	}
1049 }
1050 
alias(void)1051 void alias(void)
1052 {
1053 	struct aliasinfo *a;
1054 	char *active = NULL;
1055 
1056 	sort_aliases();
1057 	link_slabs();
1058 
1059 	for(a = aliasinfo; a < aliasinfo + aliases; a++) {
1060 
1061 		if (!show_single_ref && a->slab->refs == 1)
1062 			continue;
1063 
1064 		if (!show_inverted) {
1065 			if (active) {
1066 				if (strcmp(a->slab->name, active) == 0) {
1067 					printf(" %s", a->name);
1068 					continue;
1069 				}
1070 			}
1071 			printf("\n%-12s <- %s", a->slab->name, a->name);
1072 			active = a->slab->name;
1073 		}
1074 		else
1075 			printf("%-20s -> %s\n", a->name, a->slab->name);
1076 	}
1077 	if (active)
1078 		printf("\n");
1079 }
1080 
1081 
rename_slabs(void)1082 void rename_slabs(void)
1083 {
1084 	struct slabinfo *s;
1085 	struct aliasinfo *a;
1086 
1087 	for (s = slabinfo; s < slabinfo + slabs; s++) {
1088 		if (*s->name != ':')
1089 			continue;
1090 
1091 		if (s->refs > 1 && !show_first_alias)
1092 			continue;
1093 
1094 		a = find_one_alias(s);
1095 
1096 		if (a)
1097 			s->name = a->name;
1098 		else {
1099 			s->name = "*";
1100 			actual_slabs--;
1101 		}
1102 	}
1103 }
1104 
slab_mismatch(char * slab)1105 int slab_mismatch(char *slab)
1106 {
1107 	return regexec(&pattern, slab, 0, NULL, 0);
1108 }
1109 
read_slab_dir(void)1110 void read_slab_dir(void)
1111 {
1112 	DIR *dir;
1113 	struct dirent *de;
1114 	struct slabinfo *slab = slabinfo;
1115 	struct aliasinfo *alias = aliasinfo;
1116 	char *p;
1117 	char *t;
1118 	int count;
1119 
1120 	if (chdir("/sys/kernel/slab") && chdir("/sys/slab"))
1121 		fatal("SYSFS support for SLUB not active\n");
1122 
1123 	dir = opendir(".");
1124 	while ((de = readdir(dir))) {
1125 		if (de->d_name[0] == '.' ||
1126 			(de->d_name[0] != ':' && slab_mismatch(de->d_name)))
1127 				continue;
1128 		switch (de->d_type) {
1129 		   case DT_LNK:
1130 		   	alias->name = strdup(de->d_name);
1131 			count = readlink(de->d_name, buffer, sizeof(buffer));
1132 
1133 			if (count < 0)
1134 				fatal("Cannot read symlink %s\n", de->d_name);
1135 
1136 			buffer[count] = 0;
1137 			p = buffer + count;
1138 			while (p > buffer && p[-1] != '/')
1139 				p--;
1140 			alias->ref = strdup(p);
1141 			alias++;
1142 			break;
1143 		   case DT_DIR:
1144 			if (chdir(de->d_name))
1145 				fatal("Unable to access slab %s\n", slab->name);
1146 		   	slab->name = strdup(de->d_name);
1147 			slab->alias = 0;
1148 			slab->refs = 0;
1149 			slab->aliases = get_obj("aliases");
1150 			slab->align = get_obj("align");
1151 			slab->cache_dma = get_obj("cache_dma");
1152 			slab->cpu_slabs = get_obj("cpu_slabs");
1153 			slab->destroy_by_rcu = get_obj("destroy_by_rcu");
1154 			slab->hwcache_align = get_obj("hwcache_align");
1155 			slab->object_size = get_obj("object_size");
1156 			slab->objects = get_obj("objects");
1157 			slab->objects_partial = get_obj("objects_partial");
1158 			slab->objects_total = get_obj("objects_total");
1159 			slab->objs_per_slab = get_obj("objs_per_slab");
1160 			slab->order = get_obj("order");
1161 			slab->partial = get_obj("partial");
1162 			slab->partial = get_obj_and_str("partial", &t);
1163 			decode_numa_list(slab->numa_partial, t);
1164 			free(t);
1165 			slab->poison = get_obj("poison");
1166 			slab->reclaim_account = get_obj("reclaim_account");
1167 			slab->red_zone = get_obj("red_zone");
1168 			slab->sanity_checks = get_obj("sanity_checks");
1169 			slab->slab_size = get_obj("slab_size");
1170 			slab->slabs = get_obj_and_str("slabs", &t);
1171 			decode_numa_list(slab->numa, t);
1172 			free(t);
1173 			slab->store_user = get_obj("store_user");
1174 			slab->trace = get_obj("trace");
1175 			slab->alloc_fastpath = get_obj("alloc_fastpath");
1176 			slab->alloc_slowpath = get_obj("alloc_slowpath");
1177 			slab->free_fastpath = get_obj("free_fastpath");
1178 			slab->free_slowpath = get_obj("free_slowpath");
1179 			slab->free_frozen= get_obj("free_frozen");
1180 			slab->free_add_partial = get_obj("free_add_partial");
1181 			slab->free_remove_partial = get_obj("free_remove_partial");
1182 			slab->alloc_from_partial = get_obj("alloc_from_partial");
1183 			slab->alloc_slab = get_obj("alloc_slab");
1184 			slab->alloc_refill = get_obj("alloc_refill");
1185 			slab->free_slab = get_obj("free_slab");
1186 			slab->cpuslab_flush = get_obj("cpuslab_flush");
1187 			slab->deactivate_full = get_obj("deactivate_full");
1188 			slab->deactivate_empty = get_obj("deactivate_empty");
1189 			slab->deactivate_to_head = get_obj("deactivate_to_head");
1190 			slab->deactivate_to_tail = get_obj("deactivate_to_tail");
1191 			slab->deactivate_remote_frees = get_obj("deactivate_remote_frees");
1192 			slab->order_fallback = get_obj("order_fallback");
1193 			chdir("..");
1194 			if (slab->name[0] == ':')
1195 				alias_targets++;
1196 			slab++;
1197 			break;
1198 		   default :
1199 			fatal("Unknown file type %lx\n", de->d_type);
1200 		}
1201 	}
1202 	closedir(dir);
1203 	slabs = slab - slabinfo;
1204 	actual_slabs = slabs;
1205 	aliases = alias - aliasinfo;
1206 	if (slabs > MAX_SLABS)
1207 		fatal("Too many slabs\n");
1208 	if (aliases > MAX_ALIASES)
1209 		fatal("Too many aliases\n");
1210 }
1211 
output_slabs(void)1212 void output_slabs(void)
1213 {
1214 	struct slabinfo *slab;
1215 
1216 	for (slab = slabinfo; slab < slabinfo + slabs; slab++) {
1217 
1218 		if (slab->alias)
1219 			continue;
1220 
1221 
1222 		if (show_numa)
1223 			slab_numa(slab, 0);
1224 		else if (show_track)
1225 			show_tracking(slab);
1226 		else if (validate)
1227 			slab_validate(slab);
1228 		else if (shrink)
1229 			slab_shrink(slab);
1230 		else if (set_debug)
1231 			slab_debug(slab);
1232 		else if (show_ops)
1233 			ops(slab);
1234 		else if (show_slab)
1235 			slabcache(slab);
1236 		else if (show_report)
1237 			report(slab);
1238 	}
1239 }
1240 
1241 struct option opts[] = {
1242 	{ "aliases", 0, NULL, 'a' },
1243 	{ "activity", 0, NULL, 'A' },
1244 	{ "debug", 2, NULL, 'd' },
1245 	{ "display-activity", 0, NULL, 'D' },
1246 	{ "empty", 0, NULL, 'e' },
1247 	{ "first-alias", 0, NULL, 'f' },
1248 	{ "help", 0, NULL, 'h' },
1249 	{ "inverted", 0, NULL, 'i'},
1250 	{ "numa", 0, NULL, 'n' },
1251 	{ "ops", 0, NULL, 'o' },
1252 	{ "report", 0, NULL, 'r' },
1253 	{ "shrink", 0, NULL, 's' },
1254 	{ "slabs", 0, NULL, 'l' },
1255 	{ "track", 0, NULL, 't'},
1256 	{ "validate", 0, NULL, 'v' },
1257 	{ "zero", 0, NULL, 'z' },
1258 	{ "1ref", 0, NULL, '1'},
1259 	{ NULL, 0, NULL, 0 }
1260 };
1261 
main(int argc,char * argv[])1262 int main(int argc, char *argv[])
1263 {
1264 	int c;
1265 	int err;
1266 	char *pattern_source;
1267 
1268 	page_size = getpagesize();
1269 
1270 	while ((c = getopt_long(argc, argv, "aAd::Defhil1noprstvzTS",
1271 						opts, NULL)) != -1)
1272 		switch (c) {
1273 		case '1':
1274 			show_single_ref = 1;
1275 			break;
1276 		case 'a':
1277 			show_alias = 1;
1278 			break;
1279 		case 'A':
1280 			sort_active = 1;
1281 			break;
1282 		case 'd':
1283 			set_debug = 1;
1284 			if (!debug_opt_scan(optarg))
1285 				fatal("Invalid debug option '%s'\n", optarg);
1286 			break;
1287 		case 'D':
1288 			show_activity = 1;
1289 			break;
1290 		case 'e':
1291 			show_empty = 1;
1292 			break;
1293 		case 'f':
1294 			show_first_alias = 1;
1295 			break;
1296 		case 'h':
1297 			usage();
1298 			return 0;
1299 		case 'i':
1300 			show_inverted = 1;
1301 			break;
1302 		case 'n':
1303 			show_numa = 1;
1304 			break;
1305 		case 'o':
1306 			show_ops = 1;
1307 			break;
1308 		case 'r':
1309 			show_report = 1;
1310 			break;
1311 		case 's':
1312 			shrink = 1;
1313 			break;
1314 		case 'l':
1315 			show_slab = 1;
1316 			break;
1317 		case 't':
1318 			show_track = 1;
1319 			break;
1320 		case 'v':
1321 			validate = 1;
1322 			break;
1323 		case 'z':
1324 			skip_zero = 0;
1325 			break;
1326 		case 'T':
1327 			show_totals = 1;
1328 			break;
1329 		case 'S':
1330 			sort_size = 1;
1331 			break;
1332 
1333 		default:
1334 			fatal("%s: Invalid option '%c'\n", argv[0], optopt);
1335 
1336 	}
1337 
1338 	if (!show_slab && !show_alias && !show_track && !show_report
1339 		&& !validate && !shrink && !set_debug && !show_ops)
1340 			show_slab = 1;
1341 
1342 	if (argc > optind)
1343 		pattern_source = argv[optind];
1344 	else
1345 		pattern_source = ".*";
1346 
1347 	err = regcomp(&pattern, pattern_source, REG_ICASE|REG_NOSUB);
1348 	if (err)
1349 		fatal("%s: Invalid pattern '%s' code %d\n",
1350 			argv[0], pattern_source, err);
1351 	read_slab_dir();
1352 	if (show_alias)
1353 		alias();
1354 	else
1355 	if (show_totals)
1356 		totals();
1357 	else {
1358 		link_slabs();
1359 		rename_slabs();
1360 		sort_slabs();
1361 		output_slabs();
1362 	}
1363 	return 0;
1364 }
1365