brintos

brintos / linux-shallow public Read only

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