Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c00f08d7 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 'slub-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/christoph/vm:
  SLUB: fix checkpatch warnings
  Use non atomic unlock
  SLUB: Support for performance statistics
  SLUB: Alternate fast paths using cmpxchg_local
  SLUB: Use unique end pointer for each slab page.
  SLUB: Deal with annoying gcc warning on kfree()
parents c8b6de16 3adbefee
Loading
Loading
Loading
Loading
+138 −11
Original line number Original line Diff line number Diff line
@@ -32,6 +32,13 @@ struct slabinfo {
	int sanity_checks, slab_size, store_user, trace;
	int sanity_checks, slab_size, store_user, trace;
	int order, poison, reclaim_account, red_zone;
	int order, poison, reclaim_account, red_zone;
	unsigned long partial, objects, slabs;
	unsigned long partial, objects, slabs;
	unsigned long alloc_fastpath, alloc_slowpath;
	unsigned long free_fastpath, free_slowpath;
	unsigned long free_frozen, free_add_partial, free_remove_partial;
	unsigned long alloc_from_partial, alloc_slab, free_slab, alloc_refill;
	unsigned long cpuslab_flush, deactivate_full, deactivate_empty;
	unsigned long deactivate_to_head, deactivate_to_tail;
	unsigned long deactivate_remote_frees;
	int numa[MAX_NODES];
	int numa[MAX_NODES];
	int numa_partial[MAX_NODES];
	int numa_partial[MAX_NODES];
} slabinfo[MAX_SLABS];
} slabinfo[MAX_SLABS];
@@ -64,8 +71,10 @@ int show_inverted = 0;
int show_single_ref = 0;
int show_single_ref = 0;
int show_totals = 0;
int show_totals = 0;
int sort_size = 0;
int sort_size = 0;
int sort_active = 0;
int set_debug = 0;
int set_debug = 0;
int show_ops = 0;
int show_ops = 0;
int show_activity = 0;


/* Debug options */
/* Debug options */
int sanity = 0;
int sanity = 0;
@@ -93,7 +102,9 @@ void usage(void)
	printf("slabinfo 5/7/2007. (c) 2007 sgi. clameter@sgi.com\n\n"
	printf("slabinfo 5/7/2007. (c) 2007 sgi. clameter@sgi.com\n\n"
		"slabinfo [-ahnpvtsz] [-d debugopts] [slab-regexp]\n"
		"slabinfo [-ahnpvtsz] [-d debugopts] [slab-regexp]\n"
		"-a|--aliases           Show aliases\n"
		"-a|--aliases           Show aliases\n"
		"-A|--activity          Most active slabs first\n"
		"-d<options>|--debug=<options> Set/Clear Debug options\n"
		"-d<options>|--debug=<options> Set/Clear Debug options\n"
		"-D|--display-active    Switch line format to activity\n"
		"-e|--empty             Show empty slabs\n"
		"-e|--empty             Show empty slabs\n"
		"-f|--first-alias       Show first alias\n"
		"-f|--first-alias       Show first alias\n"
		"-h|--help              Show usage information\n"
		"-h|--help              Show usage information\n"
@@ -281,6 +292,9 @@ int line = 0;


void first_line(void)
void first_line(void)
{
{
	if (show_activity)
		printf("Name                   Objects    Alloc     Free   %%Fast\n");
	else
		printf("Name                   Objects Objsize    Space "
		printf("Name                   Objects Objsize    Space "
			"Slabs/Part/Cpu  O/S O %%Fr %%Ef Flg\n");
			"Slabs/Part/Cpu  O/S O %%Fr %%Ef Flg\n");
}
}
@@ -309,6 +323,12 @@ unsigned long slab_size(struct slabinfo *s)
	return 	s->slabs * (page_size << s->order);
	return 	s->slabs * (page_size << s->order);
}
}


unsigned long slab_activity(struct slabinfo *s)
{
	return 	s->alloc_fastpath + s->free_fastpath +
		s->alloc_slowpath + s->free_slowpath;
}

void slab_numa(struct slabinfo *s, int mode)
void slab_numa(struct slabinfo *s, int mode)
{
{
	int node;
	int node;
@@ -392,6 +412,71 @@ const char *onoff(int x)
	return "Off";
	return "Off";
}
}


void slab_stats(struct slabinfo *s)
{
	unsigned long total_alloc;
	unsigned long total_free;
	unsigned long total;

	if (!s->alloc_slab)
		return;

	total_alloc = s->alloc_fastpath + s->alloc_slowpath;
	total_free = s->free_fastpath + s->free_slowpath;

	if (!total_alloc)
		return;

	printf("\n");
	printf("Slab Perf Counter       Alloc     Free %%Al %%Fr\n");
	printf("--------------------------------------------------\n");
	printf("Fastpath             %8lu %8lu %3lu %3lu\n",
		s->alloc_fastpath, s->free_fastpath,
		s->alloc_fastpath * 100 / total_alloc,
		s->free_fastpath * 100 / total_free);
	printf("Slowpath             %8lu %8lu %3lu %3lu\n",
		total_alloc - s->alloc_fastpath, s->free_slowpath,
		(total_alloc - s->alloc_fastpath) * 100 / total_alloc,
		s->free_slowpath * 100 / total_free);
	printf("Page Alloc           %8lu %8lu %3lu %3lu\n",
		s->alloc_slab, s->free_slab,
		s->alloc_slab * 100 / total_alloc,
		s->free_slab * 100 / total_free);
	printf("Add partial          %8lu %8lu %3lu %3lu\n",
		s->deactivate_to_head + s->deactivate_to_tail,
		s->free_add_partial,
		(s->deactivate_to_head + s->deactivate_to_tail) * 100 / total_alloc,
		s->free_add_partial * 100 / total_free);
	printf("Remove partial       %8lu %8lu %3lu %3lu\n",
		s->alloc_from_partial, s->free_remove_partial,
		s->alloc_from_partial * 100 / total_alloc,
		s->free_remove_partial * 100 / total_free);

	printf("RemoteObj/SlabFrozen %8lu %8lu %3lu %3lu\n",
		s->deactivate_remote_frees, s->free_frozen,
		s->deactivate_remote_frees * 100 / total_alloc,
		s->free_frozen * 100 / total_free);

	printf("Total                %8lu %8lu\n\n", total_alloc, total_free);

	if (s->cpuslab_flush)
		printf("Flushes %8lu\n", s->cpuslab_flush);

	if (s->alloc_refill)
		printf("Refill %8lu\n", s->alloc_refill);

	total = s->deactivate_full + s->deactivate_empty +
			s->deactivate_to_head + s->deactivate_to_tail;

	if (total)
		printf("Deactivate Full=%lu(%lu%%) Empty=%lu(%lu%%) "
			"ToHead=%lu(%lu%%) ToTail=%lu(%lu%%)\n",
			s->deactivate_full, (s->deactivate_full * 100) / total,
			s->deactivate_empty, (s->deactivate_empty * 100) / total,
			s->deactivate_to_head, (s->deactivate_to_head * 100) / total,
			s->deactivate_to_tail, (s->deactivate_to_tail * 100) / total);
}

void report(struct slabinfo *s)
void report(struct slabinfo *s)
{
{
	if (strcmp(s->name, "*") == 0)
	if (strcmp(s->name, "*") == 0)
@@ -430,6 +515,7 @@ void report(struct slabinfo *s)
	ops(s);
	ops(s);
	show_tracking(s);
	show_tracking(s);
	slab_numa(s, 1);
	slab_numa(s, 1);
	slab_stats(s);
}
}


void slabcache(struct slabinfo *s)
void slabcache(struct slabinfo *s)
@@ -479,6 +565,20 @@ void slabcache(struct slabinfo *s)
		*p++ = 'T';
		*p++ = 'T';


	*p = 0;
	*p = 0;
	if (show_activity) {
		unsigned long total_alloc;
		unsigned long total_free;

		total_alloc = s->alloc_fastpath + s->alloc_slowpath;
		total_free = s->free_fastpath + s->free_slowpath;

		printf("%-21s %8ld %8ld %8ld %3ld %3ld \n",
			s->name, s->objects,
			total_alloc, total_free,
			total_alloc ? (s->alloc_fastpath * 100 / total_alloc) : 0,
			total_free ? (s->free_fastpath * 100 / total_free) : 0);
	}
	else
		printf("%-21s %8ld %7d %8s %14s %4d %1d %3ld %3ld %s\n",
		printf("%-21s %8ld %7d %8s %14s %4d %1d %3ld %3ld %s\n",
			s->name, s->objects, s->object_size, size_str, dist_str,
			s->name, s->objects, s->object_size, size_str, dist_str,
			s->objs_per_slab, s->order,
			s->objs_per_slab, s->order,
@@ -892,6 +992,8 @@ void sort_slabs(void)


			if (sort_size)
			if (sort_size)
				result = slab_size(s1) < slab_size(s2);
				result = slab_size(s1) < slab_size(s2);
			else if (sort_active)
				result = slab_activity(s1) < slab_activity(s2);
			else
			else
				result = strcasecmp(s1->name, s2->name);
				result = strcasecmp(s1->name, s2->name);


@@ -1074,6 +1176,23 @@ void read_slab_dir(void)
			free(t);
			free(t);
			slab->store_user = get_obj("store_user");
			slab->store_user = get_obj("store_user");
			slab->trace = get_obj("trace");
			slab->trace = get_obj("trace");
			slab->alloc_fastpath = get_obj("alloc_fastpath");
			slab->alloc_slowpath = get_obj("alloc_slowpath");
			slab->free_fastpath = get_obj("free_fastpath");
			slab->free_slowpath = get_obj("free_slowpath");
			slab->free_frozen= get_obj("free_frozen");
			slab->free_add_partial = get_obj("free_add_partial");
			slab->free_remove_partial = get_obj("free_remove_partial");
			slab->alloc_from_partial = get_obj("alloc_from_partial");
			slab->alloc_slab = get_obj("alloc_slab");
			slab->alloc_refill = get_obj("alloc_refill");
			slab->free_slab = get_obj("free_slab");
			slab->cpuslab_flush = get_obj("cpuslab_flush");
			slab->deactivate_full = get_obj("deactivate_full");
			slab->deactivate_empty = get_obj("deactivate_empty");
			slab->deactivate_to_head = get_obj("deactivate_to_head");
			slab->deactivate_to_tail = get_obj("deactivate_to_tail");
			slab->deactivate_remote_frees = get_obj("deactivate_remote_frees");
			chdir("..");
			chdir("..");
			if (slab->name[0] == ':')
			if (slab->name[0] == ':')
				alias_targets++;
				alias_targets++;
@@ -1124,7 +1243,9 @@ void output_slabs(void)


struct option opts[] = {
struct option opts[] = {
	{ "aliases", 0, NULL, 'a' },
	{ "aliases", 0, NULL, 'a' },
	{ "activity", 0, NULL, 'A' },
	{ "debug", 2, NULL, 'd' },
	{ "debug", 2, NULL, 'd' },
	{ "display-activity", 0, NULL, 'D' },
	{ "empty", 0, NULL, 'e' },
	{ "empty", 0, NULL, 'e' },
	{ "first-alias", 0, NULL, 'f' },
	{ "first-alias", 0, NULL, 'f' },
	{ "help", 0, NULL, 'h' },
	{ "help", 0, NULL, 'h' },
@@ -1149,7 +1270,7 @@ int main(int argc, char *argv[])


	page_size = getpagesize();
	page_size = getpagesize();


	while ((c = getopt_long(argc, argv, "ad::efhil1noprstvzTS",
	while ((c = getopt_long(argc, argv, "aAd::Defhil1noprstvzTS",
						opts, NULL)) != -1)
						opts, NULL)) != -1)
		switch (c) {
		switch (c) {
		case '1':
		case '1':
@@ -1158,11 +1279,17 @@ int main(int argc, char *argv[])
		case 'a':
		case 'a':
			show_alias = 1;
			show_alias = 1;
			break;
			break;
		case 'A':
			sort_active = 1;
			break;
		case 'd':
		case 'd':
			set_debug = 1;
			set_debug = 1;
			if (!debug_opt_scan(optarg))
			if (!debug_opt_scan(optarg))
				fatal("Invalid debug option '%s'\n", optarg);
				fatal("Invalid debug option '%s'\n", optarg);
			break;
			break;
		case 'D':
			show_activity = 1;
			break;
		case 'e':
		case 'e':
			show_empty = 1;
			show_empty = 1;
			break;
			break;
+4 −0
Original line number Original line Diff line number Diff line
@@ -52,6 +52,10 @@ config HAVE_LATENCYTOP_SUPPORT
config SEMAPHORE_SLEEPERS
config SEMAPHORE_SLEEPERS
	def_bool y
	def_bool y


config FAST_CMPXCHG_LOCAL
	bool
	default y

config MMU
config MMU
	def_bool y
	def_bool y


+4 −1
Original line number Original line Diff line number Diff line
@@ -64,7 +64,10 @@ struct page {
#if NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS
#if NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS
	    spinlock_t ptl;
	    spinlock_t ptl;
#endif
#endif
	    struct {
		   struct kmem_cache *slab;	/* SLUB: Pointer to slab */
		   struct kmem_cache *slab;	/* SLUB: Pointer to slab */
		   void *end;			/* SLUB: end marker */
	    };
	    struct page *first_page;	/* Compound tail pages */
	    struct page *first_page;	/* Compound tail pages */
	};
	};
	union {
	union {
+23 −0
Original line number Original line Diff line number Diff line
@@ -11,12 +11,35 @@
#include <linux/workqueue.h>
#include <linux/workqueue.h>
#include <linux/kobject.h>
#include <linux/kobject.h>


enum stat_item {
	ALLOC_FASTPATH,		/* Allocation from cpu slab */
	ALLOC_SLOWPATH,		/* Allocation by getting a new cpu slab */
	FREE_FASTPATH,		/* Free to cpu slub */
	FREE_SLOWPATH,		/* Freeing not to cpu slab */
	FREE_FROZEN,		/* Freeing to frozen slab */
	FREE_ADD_PARTIAL,	/* Freeing moves slab to partial list */
	FREE_REMOVE_PARTIAL,	/* Freeing removes last object */
	ALLOC_FROM_PARTIAL,	/* Cpu slab acquired from partial list */
	ALLOC_SLAB,		/* Cpu slab acquired from page allocator */
	ALLOC_REFILL,		/* Refill cpu slab from slab freelist */
	FREE_SLAB,		/* Slab freed to the page allocator */
	CPUSLAB_FLUSH,		/* Abandoning of the cpu slab */
	DEACTIVATE_FULL,	/* Cpu slab was full when deactivated */
	DEACTIVATE_EMPTY,	/* Cpu slab was empty when deactivated */
	DEACTIVATE_TO_HEAD,	/* Cpu slab was moved to the head of partials */
	DEACTIVATE_TO_TAIL,	/* Cpu slab was moved to the tail of partials */
	DEACTIVATE_REMOTE_FREES,/* Slab contained remotely freed objects */
	NR_SLUB_STAT_ITEMS };

struct kmem_cache_cpu {
struct kmem_cache_cpu {
	void **freelist;	/* Pointer to first free per cpu object */
	void **freelist;	/* Pointer to first free per cpu object */
	struct page *page;	/* The slab from which we are allocating */
	struct page *page;	/* The slab from which we are allocating */
	int node;		/* The node of the page (or -1 for debug) */
	int node;		/* The node of the page (or -1 for debug) */
	unsigned int offset;	/* Freepointer offset (in word units) */
	unsigned int offset;	/* Freepointer offset (in word units) */
	unsigned int objsize;	/* Size of an object (from kmem_cache) */
	unsigned int objsize;	/* Size of an object (from kmem_cache) */
#ifdef CONFIG_SLUB_STATS
	unsigned stat[NR_SLUB_STAT_ITEMS];
#endif
};
};


struct kmem_cache_node {
struct kmem_cache_node {
+13 −0
Original line number Original line Diff line number Diff line
@@ -205,6 +205,19 @@ config SLUB_DEBUG_ON
	  off in a kernel built with CONFIG_SLUB_DEBUG_ON by specifying
	  off in a kernel built with CONFIG_SLUB_DEBUG_ON by specifying
	  "slub_debug=-".
	  "slub_debug=-".


config SLUB_STATS
	default n
	bool "Enable SLUB performance statistics"
	depends on SLUB
	help
	  SLUB statistics are useful to debug SLUBs allocation behavior in
	  order find ways to optimize the allocator. This should never be
	  enabled for production use since keeping statistics slows down
	  the allocator by a few percentage points. The slabinfo command
	  supports the determination of the most active slabs to figure
	  out which slabs are relevant to a particular load.
	  Try running: slabinfo -DA

config DEBUG_PREEMPT
config DEBUG_PREEMPT
	bool "Debug preemptible kernel"
	bool "Debug preemptible kernel"
	depends on DEBUG_KERNEL && PREEMPT && (TRACE_IRQFLAGS_SUPPORT || PPC64)
	depends on DEBUG_KERNEL && PREEMPT && (TRACE_IRQFLAGS_SUPPORT || PPC64)
Loading