mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 0/2] tools/mm/slabinfo: report sheaf and barn statistics
@ 2026-09-27  5:57 Seongjun Hong
  2026-09-27  5:57 ` [PATCH 1/2] tools/mm/slabinfo: refactor slab attribute reading Seongjun Hong
  2026-09-27  5:57 ` [PATCH 2/2] tools/mm/slabinfo: report percpu sheaves and barn statistics Seongjun Hong
  0 siblings, 2 replies; 5+ messages in thread
From: Seongjun Hong @ 2026-09-27  5:57 UTC (permalink / raw)
  To: Vlastimil Babka, Harry Yoo, Andrew Morton, Hao Li,
	Christoph Lameter, David Rientjes, Roman Gushchin
  Cc: linux-mm, linux-kernel, Seongjun Hong

Since commit 2d517aa09bbc ("slab: add opt-in caching layer of percpu
sheaves"), kernel exposes sheaf and barn statistics through sysfs but
slabinfo did not utilize this information. Make slabinfo report
kmem_cache statistics including sheaf and barn counters.

Signed-off-by: Seongjun Hong <hsj0512@snu.ac.kr>
---
Seongjun Hong (2):
      tools/mm/slabinfo: refactor slab attribute reading
      tools/mm/slabinfo: report percpu sheaves and barn statistics

 tools/mm/slabinfo.c | 303 ++++++++++++++++++++++++++++++++--------------------
 1 file changed, 189 insertions(+), 114 deletions(-)
---
base-commit: 9b87fdc9af2fbfcdb5c24a64139685ef80f6573f
change-id: 20260921-tools-mm-update-slabinfo-8eab37191831

Best regards,
-- 
Best regards,
Seongjun Hong


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/2] tools/mm/slabinfo: refactor slab attribute reading
  2026-09-27  5:57 [PATCH 0/2] tools/mm/slabinfo: report sheaf and barn statistics Seongjun Hong
@ 2026-09-27  5:57 ` Seongjun Hong
  2026-09-28 15:52   ` Harry Yoo
  2026-09-27  5:57 ` [PATCH 2/2] tools/mm/slabinfo: report percpu sheaves and barn statistics Seongjun Hong
  1 sibling, 1 reply; 5+ messages in thread
From: Seongjun Hong @ 2026-09-27  5:57 UTC (permalink / raw)
  To: Vlastimil Babka, Harry Yoo, Andrew Morton, Hao Li,
	Christoph Lameter, David Rientjes, Roman Gushchin
  Cc: linux-mm, linux-kernel, Seongjun Hong

The fields of struct slabinfo were mixed with deprecated sysfs files,
which looks complicated. Organize every field of struct slabinfo by
config option and the attribute order in mm/slub.c's slab_attrs[]. Because
slabinfo should be able to run on previous kernel releases, leave the
deprecated members for this time.

read_slab_dir() had ~50 lines of attribute reads inlined. Move them to a
new fill_slabinfo() helper so that directory walk and per-cache
attribute reading are separated.

Fold get_obj_and_str() and decode_numa_list() into get_obj_and_decode()
to avoid unnecessary strdup() and leave only one member assignment in
fill_slabinfo() for each sysfs file.

Make broken statements into a single line for better readibility.

Remove alias field from struct slabinfo because it is initialized to 0
and never updated. The only usage of this field "if (slab->alias)" is dead.

No functional change intended.

Signed-off-by: Seongjun Hong <hsj0512@snu.ac.kr>
---
 tools/mm/slabinfo.c | 245 ++++++++++++++++++++++++++++------------------------
 1 file changed, 131 insertions(+), 114 deletions(-)

diff --git a/tools/mm/slabinfo.c b/tools/mm/slabinfo.c
index 48d1ee8b0e81..84359d628f2e 100644
--- a/tools/mm/slabinfo.c
+++ b/tools/mm/slabinfo.c
@@ -27,25 +27,49 @@
 
 struct slabinfo {
 	char *name;
-	int alias;
 	int refs;
-	int aliases, align, cache_dma, cpu_slabs, destroy_by_rcu;
-	unsigned int hwcache_align, object_size, objs_per_slab;
-	unsigned int sanity_checks, slab_size, store_user, trace;
-	int order, poison, reclaim_account, red_zone;
-	unsigned long partial, objects, slabs, objects_partial, total_objects;
+	int numa_slabs[MAX_NODES];
+	int numa_partial[MAX_NODES];
+
+	unsigned int slab_size, object_size;
+	unsigned int objs_per_slab, order;
+	unsigned long objects_partial, partial;
+	int aliases;
+	unsigned int align;
+	int hwcache_align;
+	int reclaim_account;
+	int destroy_by_rcu;
+
+	/* CONFIG_SLUB_DEBUG */
+	unsigned long total_objects, objects, slabs;
+	int sanity_checks, trace, red_zone, poison, store_user;
+
+	/* CONFIG_ZONE_DMA */
+	int cache_dma;
+
+	/* CONFIG_SLUB_STATS */
 	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 free_add_partial, free_remove_partial;
+	unsigned long alloc_slab, alloc_node_mismatch, free_slab;
+	unsigned long order_fallback;
+	unsigned long cmpxchg_double_fail;
+
+	/*
+	 * Deprecated files:
+	 * No STAT_ATTR()/SLAB_ATTR() for these exists in mm/slub.c's
+	 * slab_attrs[] anymore. Although cpu_slabs remains as a file,
+	 * it is also outdated and always prints 0. Keep these for backward
+	 * compatibility, but they should be removed later.
+	 */
+	int cpu_slabs;
+	unsigned long free_frozen;
 	unsigned long deactivate_to_head, deactivate_to_tail;
-	unsigned long deactivate_remote_frees, order_fallback;
-	unsigned long cmpxchg_double_cpu_fail, cmpxchg_double_fail;
-	unsigned long alloc_node_mismatch, deactivate_bypass;
+	unsigned long alloc_from_partial, alloc_refill;
+	unsigned long cpuslab_flush, deactivate_full, deactivate_empty;
+	unsigned long deactivate_remote_frees, deactivate_bypass;
+	unsigned long cmpxchg_double_cpu_fail;
 	unsigned long cpu_partial_alloc, cpu_partial_free;
-	int numa[MAX_NODES];
-	int numa_partial[MAX_NODES];
 } slabinfo[MAX_SLABS];
 
 struct aliasinfo {
@@ -174,6 +198,30 @@ static unsigned long read_obj(const char *name)
 	return strlen(buffer);
 }
 
+static void decode_numa_list(int *numa, char *t)
+{
+	int node;
+	int nr;
+
+	memset(numa, 0, MAX_NODES * sizeof(int));
+
+	if (!t)
+		return;
+
+	while (*t == 'N') {
+		t++;
+		node = strtoul(t, &t, 10);
+		if (*t == '=') {
+			t++;
+			nr = strtoul(t, &t, 10);
+			numa[node] = nr;
+			if (node > highest_node)
+				highest_node = node;
+		}
+		while (*t == ' ')
+			t++;
+	}
+}
 
 /*
  * Get the contents of an attribute
@@ -186,21 +234,19 @@ static unsigned long get_obj(const char *name)
 	return atol(buffer);
 }
 
-static unsigned long get_obj_and_str(const char *name, char **x)
+static unsigned long get_obj_and_decode(int *numa, const char *name)
 {
 	unsigned long result = 0;
 	char *p;
 
-	*x = NULL;
-
 	if (!read_obj(name))
 		return 0;
 
 	result = strtoul(buffer, &p, 10);
 	while (*p == ' ')
 		p++;
-	if (*p)
-		*x = strdup(p);
+
+	decode_numa_list(numa, p);
 	return result;
 }
 
@@ -293,31 +339,6 @@ static int store_size(char *buffer, unsigned long value)
 	return n;
 }
 
-static void decode_numa_list(int *numa, char *t)
-{
-	int node;
-	int nr;
-
-	memset(numa, 0, MAX_NODES * sizeof(int));
-
-	if (!t)
-		return;
-
-	while (*t == 'N') {
-		t++;
-		node = strtoul(t, &t, 10);
-		if (*t == '=') {
-			t++;
-			nr = strtoul(t, &t, 10);
-			numa[node] = nr;
-			if (node > highest_node)
-				highest_node = node;
-		}
-		while (*t == ' ')
-			t++;
-	}
-}
-
 static void slab_validate(struct slabinfo *s)
 {
 	if (strcmp(s->name, "*") == 0)
@@ -410,7 +431,7 @@ static void slab_numa(struct slabinfo *s, int mode)
 	for(node = 0; node <= highest_node; node++) {
 		char b[20];
 
-		store_size(b, s->numa[node]);
+		store_size(b, s->numa_slabs[node]);
 		printf(" %4s", b);
 	}
 	printf("\n");
@@ -1210,6 +1231,57 @@ static int slab_mismatch(char *slab)
 	return regexec(&pattern, slab, 0, NULL, 0);
 }
 
+static void fill_slabinfo(struct slabinfo *slab, const char *name)
+{
+	slab->name = strdup(name);
+	slab->refs = 0;
+	slab->aliases = get_obj("aliases");
+	slab->align = get_obj("align");
+	slab->cache_dma = get_obj("cache_dma");
+	slab->cpu_slabs = get_obj("cpu_slabs");
+	slab->destroy_by_rcu = get_obj("destroy_by_rcu");
+	slab->hwcache_align = get_obj("hwcache_align");
+	slab->object_size = get_obj("object_size");
+	slab->objects = get_obj("objects");
+	slab->objects_partial = get_obj("objects_partial");
+	slab->total_objects = get_obj("total_objects");
+	slab->objs_per_slab = get_obj("objs_per_slab");
+	slab->order = get_obj("order");
+	slab->partial = get_obj_and_decode(slab->numa_partial, "partial");
+	slab->poison = get_obj("poison");
+	slab->reclaim_account = get_obj("reclaim_account");
+	slab->red_zone = get_obj("red_zone");
+	slab->sanity_checks = get_obj("sanity_checks");
+	slab->slab_size = get_obj("slab_size");
+	slab->slabs = get_obj_and_decode(slab->numa_slabs, "slabs");
+	slab->store_user = get_obj("store_user");
+	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");
+	slab->order_fallback = get_obj("order_fallback");
+	slab->cmpxchg_double_cpu_fail = get_obj("cmpxchg_double_cpu_fail");
+	slab->cmpxchg_double_fail = get_obj("cmpxchg_double_fail");
+	slab->cpu_partial_alloc = get_obj("cpu_partial_alloc");
+	slab->cpu_partial_free = get_obj("cpu_partial_free");
+	slab->alloc_node_mismatch = get_obj("alloc_node_mismatch");
+	slab->deactivate_bypass = get_obj("deactivate_bypass");
+}
+
 static void read_slab_dir(void)
 {
 	DIR *dir;
@@ -1217,7 +1289,6 @@ static void read_slab_dir(void)
 	struct slabinfo *slab = slabinfo;
 	struct aliasinfo *alias = aliasinfo;
 	char *p;
-	char *t;
 	int count;
 
 	if (chdir("/sys/kernel/slab") && chdir("/sys/slab"))
@@ -1226,14 +1297,14 @@ static void read_slab_dir(void)
 	dir = opendir(".");
 	while ((de = readdir(dir))) {
 		if (de->d_name[0] == '.' ||
-			(de->d_name[0] != ':' && slab_mismatch(de->d_name)))
-				continue;
+		    (de->d_name[0] != ':' && slab_mismatch(de->d_name)))
+			continue;
 		switch (de->d_type) {
-		   case DT_LNK:
+		case DT_LNK:
 			if (alias - aliasinfo == MAX_ALIASES)
 				fatal("Too many aliases\n");
 			alias->name = strdup(de->d_name);
-			count = readlink(de->d_name, buffer, sizeof(buffer)-1);
+			count = readlink(de->d_name, buffer, sizeof(buffer) - 1);
 
 			if (count < 0)
 				fatal("Cannot read symlink %s\n", de->d_name);
@@ -1245,71 +1316,21 @@ static void read_slab_dir(void)
 			alias->ref = strdup(p);
 			alias++;
 			break;
-		   case DT_DIR:
+		case DT_DIR:
 			if (slab - slabinfo == MAX_SLABS)
 				fatal("Too many slabs\n");
 			if (chdir(de->d_name))
 				fatal("Unable to access slab %s\n", slab->name);
-			slab->name = strdup(de->d_name);
-			slab->alias = 0;
-			slab->refs = 0;
-			slab->aliases = get_obj("aliases");
-			slab->align = get_obj("align");
-			slab->cache_dma = get_obj("cache_dma");
-			slab->cpu_slabs = get_obj("cpu_slabs");
-			slab->destroy_by_rcu = get_obj("destroy_by_rcu");
-			slab->hwcache_align = get_obj("hwcache_align");
-			slab->object_size = get_obj("object_size");
-			slab->objects = get_obj("objects");
-			slab->objects_partial = get_obj("objects_partial");
-			slab->total_objects = get_obj("total_objects");
-			slab->objs_per_slab = get_obj("objs_per_slab");
-			slab->order = get_obj("order");
-			slab->partial = get_obj_and_str("partial", &t);
-			decode_numa_list(slab->numa_partial, t);
-			free(t);
-			slab->poison = get_obj("poison");
-			slab->reclaim_account = get_obj("reclaim_account");
-			slab->red_zone = get_obj("red_zone");
-			slab->sanity_checks = get_obj("sanity_checks");
-			slab->slab_size = get_obj("slab_size");
-			slab->slabs = get_obj_and_str("slabs", &t);
-			decode_numa_list(slab->numa, t);
-			free(t);
-			slab->store_user = get_obj("store_user");
-			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");
-			slab->order_fallback = get_obj("order_fallback");
-			slab->cmpxchg_double_cpu_fail = get_obj("cmpxchg_double_cpu_fail");
-			slab->cmpxchg_double_fail = get_obj("cmpxchg_double_fail");
-			slab->cpu_partial_alloc = get_obj("cpu_partial_alloc");
-			slab->cpu_partial_free = get_obj("cpu_partial_free");
-			slab->alloc_node_mismatch = get_obj("alloc_node_mismatch");
-			slab->deactivate_bypass = get_obj("deactivate_bypass");
+
+			fill_slabinfo(slab, de->d_name);
+
 			if (chdir(".."))
-				fatal("Unable to chdir from slab ../%s\n",
-				      slab->name);
+				fatal("Unable to chdir from slab ../%s\n", slab->name);
 			if (slab->name[0] == ':')
 				alias_targets++;
 			slab++;
 			break;
-		   default :
+		default:
 			fatal("Unknown file type %lx\n", de->d_type);
 		}
 	}
@@ -1324,12 +1345,7 @@ static void output_slabs(void)
 	struct slabinfo *slab;
 	int lines = output_lines;
 
-	for (slab = slabinfo; (slab < slabinfo + slabs) &&
-			lines != 0; slab++) {
-
-		if (slab->alias)
-			continue;
-
+	for (slab = slabinfo; (slab < slabinfo + slabs) && lines != 0; slab++) {
 		if (lines != -1)
 			lines--;
 
@@ -1528,9 +1544,10 @@ int main(int argc, char *argv[])
 
 	err = regcomp(&pattern, pattern_source, REG_ICASE|REG_NOSUB);
 	if (err)
-		fatal("%s: Invalid pattern '%s' code %d\n",
-			argv[0], pattern_source, err);
+		fatal("%s: Invalid pattern '%s' code %d\n", argv[0], pattern_source, err);
+
 	read_slab_dir();
+
 	if (show_alias) {
 		alias();
 	} else if (extended_totals) {

-- 
2.43.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 2/2] tools/mm/slabinfo: report percpu sheaves and barn statistics
  2026-09-27  5:57 [PATCH 0/2] tools/mm/slabinfo: report sheaf and barn statistics Seongjun Hong
  2026-09-27  5:57 ` [PATCH 1/2] tools/mm/slabinfo: refactor slab attribute reading Seongjun Hong
@ 2026-09-27  5:57 ` Seongjun Hong
  2026-09-28 16:00   ` Harry Yoo
  1 sibling, 1 reply; 5+ messages in thread
From: Seongjun Hong @ 2026-09-27  5:57 UTC (permalink / raw)
  To: Vlastimil Babka, Harry Yoo, Andrew Morton, Hao Li,
	Christoph Lameter, David Rientjes, Roman Gushchin
  Cc: linux-mm, linux-kernel, Seongjun Hong

Since commit 2d517aa09bbc ("slab: add opt-in caching layer of percpu
sheaves") sysfs provides the statistics of sheaf and barn, but slabinfo
did not utilize this information. Display perf, API, and sheaf allocation
counters on slabinfo report(-r).

Example slabinfo report output:

	$ slabinfo -r kmalloc-1k

	Sheaf capacity             12 objects

	Sheaf Perf Counter    Success     Fail
	--------------------------------------------------
	Barn get                    4       43
	Barn put                    4        0
	RCU sheaf free             34        0

	Sheaf API Counter        Fast     Slow
	--------------------------------------------------
	Prefill                     0        0
	Return                      0        0

	Sheaf Objects/Allocations
	--------------------------------------------------
	Objects flushed to slabs             0
	Objects refilled into sheaves      516
	Sheaves allocated                    7
	Sheaves freed                        0
	Oversize sheaves for prefill         0

Signed-off-by: Seongjun Hong <hsj0512@snu.ac.kr>
---
 tools/mm/slabinfo.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 58 insertions(+)

diff --git a/tools/mm/slabinfo.c b/tools/mm/slabinfo.c
index 84359d628f2e..dbc72582ffab 100644
--- a/tools/mm/slabinfo.c
+++ b/tools/mm/slabinfo.c
@@ -33,6 +33,7 @@ struct slabinfo {
 
 	unsigned int slab_size, object_size;
 	unsigned int objs_per_slab, order;
+	unsigned int sheaf_capacity;
 	unsigned long objects_partial, partial;
 	int aliases;
 	unsigned int align;
@@ -49,12 +50,19 @@ struct slabinfo {
 
 	/* CONFIG_SLUB_STATS */
 	unsigned long alloc_fastpath, alloc_slowpath;
+	unsigned long free_rcu_sheaf, free_rcu_sheaf_fail;
 	unsigned long free_fastpath, free_slowpath;
 	unsigned long free_add_partial, free_remove_partial;
 	unsigned long alloc_slab, alloc_node_mismatch, free_slab;
 	unsigned long order_fallback;
 	unsigned long cmpxchg_double_fail;
 
+	unsigned long sheaf_flush, sheaf_refill, sheaf_alloc, sheaf_free;
+	unsigned long barn_get, barn_get_fail, barn_put, barn_put_fail;
+	unsigned long sheaf_prefill_fast, sheaf_prefill_slow,
+		sheaf_prefill_oversize;
+	unsigned long sheaf_return_fast, sheaf_return_slow;
+
 	/*
 	 * Deprecated files:
 	 * No STAT_ATTR()/SLAB_ATTR() for these exists in mm/slub.c's
@@ -574,6 +582,39 @@ static void slab_stats(struct slabinfo *s)
 	}
 }
 
+static void sheaf_stats(struct slabinfo *s)
+{
+	if (!s->sheaf_capacity)
+		return;
+
+	printf("\nSheaf capacity       %8u objects\n", s->sheaf_capacity);
+
+	printf("\nSheaf Perf Counter    Success     Fail\n");
+	printf("--------------------------------------------------\n");
+	printf("Barn get             %8lu %8lu\n",
+		s->barn_get, s->barn_get_fail);
+	printf("Barn put             %8lu %8lu\n",
+		s->barn_put, s->barn_put_fail);
+	printf("RCU sheaf free       %8lu %8lu\n",
+		s->free_rcu_sheaf, s->free_rcu_sheaf_fail);
+
+	printf("\nSheaf API Counter        Fast     Slow\n");
+	printf("--------------------------------------------------\n");
+	printf("Prefill              %8lu %8lu\n",
+		s->sheaf_prefill_fast, s->sheaf_prefill_slow);
+	printf("Return               %8lu %8lu\n",
+		s->sheaf_return_fast, s->sheaf_return_slow);
+
+	printf("\nSheaf Objects/Allocations\n");
+	printf("--------------------------------------------------\n");
+	printf("Objects flushed to slabs      %8lu\n", s->sheaf_flush);
+	printf("Objects refilled into sheaves %8lu\n", s->sheaf_refill);
+	printf("Sheaves allocated             %8lu\n", s->sheaf_alloc);
+	printf("Sheaves freed                 %8lu\n", s->sheaf_free);
+	printf("Oversize sheaves for prefill  %8lu\n",
+		s->sheaf_prefill_oversize);
+}
+
 static void report(struct slabinfo *s)
 {
 	if (strcmp(s->name, "*") == 0)
@@ -613,6 +654,7 @@ static void report(struct slabinfo *s)
 	show_tracking(s);
 	slab_numa(s, 1);
 	slab_stats(s);
+	sheaf_stats(s);
 }
 
 static void slabcache(struct slabinfo *s)
@@ -1280,6 +1322,22 @@ static void fill_slabinfo(struct slabinfo *slab, const char *name)
 	slab->cpu_partial_free = get_obj("cpu_partial_free");
 	slab->alloc_node_mismatch = get_obj("alloc_node_mismatch");
 	slab->deactivate_bypass = get_obj("deactivate_bypass");
+	slab->sheaf_capacity = get_obj("sheaf_capacity");
+	slab->free_rcu_sheaf = get_obj("free_rcu_sheaf");
+	slab->free_rcu_sheaf_fail = get_obj("free_rcu_sheaf_fail");
+	slab->sheaf_flush = get_obj("sheaf_flush");
+	slab->sheaf_refill = get_obj("sheaf_refill");
+	slab->sheaf_alloc = get_obj("sheaf_alloc");
+	slab->sheaf_free = get_obj("sheaf_free");
+	slab->barn_get = get_obj("barn_get");
+	slab->barn_get_fail = get_obj("barn_get_fail");
+	slab->barn_put = get_obj("barn_put");
+	slab->barn_put_fail = get_obj("barn_put_fail");
+	slab->sheaf_prefill_fast = get_obj("sheaf_prefill_fast");
+	slab->sheaf_prefill_slow = get_obj("sheaf_prefill_slow");
+	slab->sheaf_prefill_oversize = get_obj("sheaf_prefill_oversize");
+	slab->sheaf_return_fast = get_obj("sheaf_return_fast");
+	slab->sheaf_return_slow = get_obj("sheaf_return_slow");
 }
 
 static void read_slab_dir(void)

-- 
2.43.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/2] tools/mm/slabinfo: refactor slab attribute reading
  2026-09-27  5:57 ` [PATCH 1/2] tools/mm/slabinfo: refactor slab attribute reading Seongjun Hong
@ 2026-09-28 15:52   ` Harry Yoo
  0 siblings, 0 replies; 5+ messages in thread
From: Harry Yoo @ 2026-09-28 15:52 UTC (permalink / raw)
  To: Seongjun Hong
  Cc: Vlastimil Babka, Andrew Morton, Hao Li, Christoph Lameter,
	David Rientjes, Roman Gushchin, linux-mm, linux-kernel

Hi Seongjun, thanks for working on tools/mm/slabinfo improvements!
My comments inlined below.

On Sun, Sep 27, 2026 at 05:57:27AM +0000, Seongjun Hong wrote:
> The fields of struct slabinfo were mixed with deprecated sysfs files,
> which looks complicated. Organize every field of struct slabinfo by
> config option and the attribute order in mm/slub.c's slab_attrs[]. Because
> slabinfo should be able to run on previous kernel releases, leave the
> deprecated members for this time.
>
> read_slab_dir() had ~50 lines of attribute reads inlined. Move them to a
> new fill_slabinfo() helper so that directory walk and per-cache
> attribute reading are separated.
> 
> Fold get_obj_and_str() and decode_numa_list() into get_obj_and_decode()
> to avoid unnecessary strdup() and leave only one member assignment in
> fill_slabinfo() for each sysfs file.
> 
> Make broken statements into a single line for better readibility.
> 
> Remove alias field from struct slabinfo because it is initialized to 0
> and never updated. The only usage of this field "if (slab->alias)" is dead.

Would you please separate this patch into multiple patches?
It's hard to review when multiple refactorings are done in a single
patch.

> No functional change intended.
> 
> Signed-off-by: Seongjun Hong <hsj0512@snu.ac.kr>
> ---
>
>  tools/mm/slabinfo.c | 245 ++++++++++++++++++++++++++++------------------------
>  1 file changed, 131 insertions(+), 114 deletions(-)
> 
> diff --git a/tools/mm/slabinfo.c b/tools/mm/slabinfo.c
> index 48d1ee8b0e81..84359d628f2e 100644
> --- a/tools/mm/slabinfo.c
> +++ b/tools/mm/slabinfo.c
> @@ -27,25 +27,49 @@
>  
>  struct slabinfo {
>  	char *name;
> -	int alias;
>  	int refs;
> -	int aliases, align, cache_dma, cpu_slabs, destroy_by_rcu;
> -	unsigned int hwcache_align, object_size, objs_per_slab;
> -	unsigned int sanity_checks, slab_size, store_user, trace;
> -	int order, poison, reclaim_account, red_zone;
> -	unsigned long partial, objects, slabs, objects_partial, total_objects;
> +	int numa_slabs[MAX_NODES];
> +	int numa_partial[MAX_NODES];
> +
> +	unsigned int slab_size, object_size;
> +	unsigned int objs_per_slab, order;
> +	unsigned long objects_partial, partial;
> +	int aliases;
> +	unsigned int align;
> +	int hwcache_align;
> +	int reclaim_account;
> +	int destroy_by_rcu;
> +
> +	/* CONFIG_SLUB_DEBUG */
> +	unsigned long total_objects, objects, slabs;
> +	int sanity_checks, trace, red_zone, poison, store_user;
> +
> +	/* CONFIG_ZONE_DMA */
> +	int cache_dma;
> +
> +	/* CONFIG_SLUB_STATS */
>  	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 free_add_partial, free_remove_partial;
> +	unsigned long alloc_slab, alloc_node_mismatch, free_slab;
> +	unsigned long order_fallback;
> +	unsigned long cmpxchg_double_fail;
> +
> +	/*
> +	 * Deprecated files:
> +	 * No STAT_ATTR()/SLAB_ATTR() for these exists in mm/slub.c's
> +	 * slab_attrs[] anymore.

This part of the comment looks fine, but

> Although cpu_slabs remains as a file,
> +	 * it is also outdated and always prints 0. Keep these for backward
> +	 * compatibility, but they should be removed later.

This doesn't seem useful information to put in the comment.

We were able to remove some files when
Documentation/ABI/testing/sysfs-kernel-slab says
"Available when CONFIG_SLUB_STATS is enabled", because that implies that
those files may not exist. 

But it's not the case for files like cpu_slabs,
and I don't think we're going to remove them in the future.

Probably simply say something like

"Deprecated files: the kernel does not create those files anymore or
 always prints hardecoded "0" since they are deprecated" ?

> +	 */
> +	int cpu_slabs;
> +	unsigned long free_frozen;
>  	unsigned long deactivate_to_head, deactivate_to_tail;
> -	unsigned long deactivate_remote_frees, order_fallback;
> -	unsigned long cmpxchg_double_cpu_fail, cmpxchg_double_fail;
> -	unsigned long alloc_node_mismatch, deactivate_bypass;
> +	unsigned long alloc_from_partial, alloc_refill;
> +	unsigned long cpuslab_flush, deactivate_full, deactivate_empty;
> +	unsigned long deactivate_remote_frees, deactivate_bypass;
> +	unsigned long cmpxchg_double_cpu_fail;
>  	unsigned long cpu_partial_alloc, cpu_partial_free;
> -	int numa[MAX_NODES];
> -	int numa_partial[MAX_NODES];
>  } slabinfo[MAX_SLABS];

-- 
Cheers,
Harry / Hyeonggon

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 2/2] tools/mm/slabinfo: report percpu sheaves and barn statistics
  2026-09-27  5:57 ` [PATCH 2/2] tools/mm/slabinfo: report percpu sheaves and barn statistics Seongjun Hong
@ 2026-09-28 16:00   ` Harry Yoo
  0 siblings, 0 replies; 5+ messages in thread
From: Harry Yoo @ 2026-09-28 16:00 UTC (permalink / raw)
  To: Seongjun Hong
  Cc: Vlastimil Babka, Andrew Morton, Hao Li, Christoph Lameter,
	David Rientjes, Roman Gushchin, linux-mm, linux-kernel

On Sun, Sep 27, 2026 at 05:57:28AM +0000, Seongjun Hong wrote:
> Since commit 2d517aa09bbc ("slab: add opt-in caching layer of percpu
> sheaves") sysfs provides the statistics of sheaf and barn, but slabinfo
> did not utilize this information. Display perf, API, and sheaf allocation
> counters on slabinfo report(-r).
> 
> Example slabinfo report output:
> 
> 	$ slabinfo -r kmalloc-1k
> 
> 	Sheaf capacity             12 objects
> 
> 	Sheaf Perf Counter    Success     Fail
> 	--------------------------------------------------
> 	Barn get                    4       43
> 	Barn put                    4        0
> 	RCU sheaf free             34        0
> 
> 	Sheaf API Counter        Fast     Slow
> 	--------------------------------------------------
> 	Prefill                     0        0
> 	Return                      0        0

You mean "Prefilled Sheaf API Counter"?

> 	Sheaf Objects/Allocations

This doesn't make sense to me.

Perhaps should be separated into
"Sheaf Allocation/Free" and
"Sheaf Refill/Flush" ?


> 	--------------------------------------------------
> 	Objects flushed to slabs             0
> 	Objects refilled into sheaves      516
> 	Sheaves allocated                    7
> 	Sheaves freed                        0
> 	Oversize sheaves for prefill         0
> 
> Signed-off-by: Seongjun Hong <hsj0512@snu.ac.kr>
> ---
>  tools/mm/slabinfo.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 58 insertions(+)
> 
> diff --git a/tools/mm/slabinfo.c b/tools/mm/slabinfo.c
> index 84359d628f2e..dbc72582ffab 100644
> --- a/tools/mm/slabinfo.c
> +++ b/tools/mm/slabinfo.c
> @@ -574,6 +582,39 @@ static void slab_stats(struct slabinfo *s)
>  	}
>  }
>  
> +static void sheaf_stats(struct slabinfo *s)

Perhaps let's fold this into slab_stats()?
I'm not sure why this should be in a separate function.
These files are part of SLUB_STATS files, that are related to sheaves.

-- 
Cheers,
Harry / Hyeonggon

> +{
> +	if (!s->sheaf_capacity)
> +		return;
> +
> +	printf("\nSheaf capacity       %8u objects\n", s->sheaf_capacity);
> +
> +	printf("\nSheaf Perf Counter    Success     Fail\n");
> +	printf("--------------------------------------------------\n");
> +	printf("Barn get             %8lu %8lu\n",
> +		s->barn_get, s->barn_get_fail);
> +	printf("Barn put             %8lu %8lu\n",
> +		s->barn_put, s->barn_put_fail);
> +	printf("RCU sheaf free       %8lu %8lu\n",
> +		s->free_rcu_sheaf, s->free_rcu_sheaf_fail);
> +
> +	printf("\nSheaf API Counter        Fast     Slow\n");
> +	printf("--------------------------------------------------\n");
> +	printf("Prefill              %8lu %8lu\n",
> +		s->sheaf_prefill_fast, s->sheaf_prefill_slow);
> +	printf("Return               %8lu %8lu\n",
> +		s->sheaf_return_fast, s->sheaf_return_slow);
> +
> +	printf("\nSheaf Objects/Allocations\n");
> +	printf("--------------------------------------------------\n");
> +	printf("Objects flushed to slabs      %8lu\n", s->sheaf_flush);
> +	printf("Objects refilled into sheaves %8lu\n", s->sheaf_refill);
> +	printf("Sheaves allocated             %8lu\n", s->sheaf_alloc);
> +	printf("Sheaves freed                 %8lu\n", s->sheaf_free);
> +	printf("Oversize sheaves for prefill  %8lu\n",
> +		s->sheaf_prefill_oversize);
> +}
> +
>  static void report(struct slabinfo *s)
>  {
>  	if (strcmp(s->name, "*") == 0)
> @@ -613,6 +654,7 @@ static void report(struct slabinfo *s)
>  	show_tracking(s);
>  	slab_numa(s, 1);
>  	slab_stats(s);
> +	sheaf_stats(s);
>  }

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-09-28 16:00 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-27  5:57 [PATCH 0/2] tools/mm/slabinfo: report sheaf and barn statistics Seongjun Hong
2026-09-27  5:57 ` [PATCH 1/2] tools/mm/slabinfo: refactor slab attribute reading Seongjun Hong
2026-09-28 15:52   ` Harry Yoo
2026-09-27  5:57 ` [PATCH 2/2] tools/mm/slabinfo: report percpu sheaves and barn statistics Seongjun Hong
2026-09-28 16:00   ` Harry Yoo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®