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