Skip to content

Commit 5595cff

Browse files
author
Pekka Enberg
committed
SLUB: dynamic per-cache MIN_PARTIAL
This patch changes the static MIN_PARTIAL to a dynamic per-cache ->min_partial value that is calculated from object size. The bigger the object size, the more pages we keep on the partial list. I tested SLAB, SLUB, and SLUB with this patch on Jens Axboe's 'netio' example script of the fio benchmarking tool. The script stresses the networking subsystem which should also give a fairly good beating of kmalloc() et al. To run the test yourself, first clone the fio repository: git clone git://git.kernel.dk/fio.git and then run the following command n times on your machine: time ./fio examples/netio The results on my 2-way 64-bit x86 machine are as follows: [ the minimum, maximum, and average are captured from 50 individual runs ] real time (seconds) min max avg sd SLAB 22.76 23.38 22.98 0.17 SLUB 22.80 25.78 23.46 0.72 SLUB (dynamic) 22.74 23.54 23.00 0.20 sys time (seconds) min max avg sd SLAB 6.90 8.28 7.70 0.28 SLUB 7.42 16.95 8.89 2.28 SLUB (dynamic) 7.17 8.64 7.73 0.29 user time (seconds) min max avg sd SLAB 36.89 38.11 37.50 0.29 SLUB 30.85 37.99 37.06 1.67 SLUB (dynamic) 36.75 38.07 37.59 0.32 As you can see from the above numbers, this patch brings SLUB to the same level as SLAB for this particular workload fixing a ~2% regression. I'd expect this change to help similar workloads that allocate a lot of objects that are close to the size of a page. Cc: Matthew Wilcox <matthew@wil.cx> Cc: Andrew Morton <akpm@linux-foundation.org> Acked-by: Christoph Lameter <cl@linux-foundation.org> Signed-off-by: Pekka Enberg <penberg@cs.helsinki.fi>
1 parent 231367f commit 5595cff

File tree

2 files changed

+20
-7
lines changed

2 files changed

+20
-7
lines changed

include/linux/slub_def.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ struct kmem_cache_cpu {
4646
struct kmem_cache_node {
4747
spinlock_t list_lock; /* Protect partial list and nr_partial */
4848
unsigned long nr_partial;
49+
unsigned long min_partial;
4950
struct list_head partial;
5051
#ifdef CONFIG_SLUB_DEBUG
5152
atomic_long_t nr_slabs;

mm/slub.c

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1329,7 +1329,7 @@ static struct page *get_any_partial(struct kmem_cache *s, gfp_t flags)
13291329
n = get_node(s, zone_to_nid(zone));
13301330

13311331
if (n && cpuset_zone_allowed_hardwall(zone, flags) &&
1332-
n->nr_partial > MIN_PARTIAL) {
1332+
n->nr_partial > n->min_partial) {
13331333
page = get_partial_node(n);
13341334
if (page)
13351335
return page;
@@ -1381,7 +1381,7 @@ static void unfreeze_slab(struct kmem_cache *s, struct page *page, int tail)
13811381
slab_unlock(page);
13821382
} else {
13831383
stat(c, DEACTIVATE_EMPTY);
1384-
if (n->nr_partial < MIN_PARTIAL) {
1384+
if (n->nr_partial < n->min_partial) {
13851385
/*
13861386
* Adding an empty slab to the partial slabs in order
13871387
* to avoid page allocator overhead. This slab needs
@@ -1913,9 +1913,21 @@ static void init_kmem_cache_cpu(struct kmem_cache *s,
19131913
#endif
19141914
}
19151915

1916-
static void init_kmem_cache_node(struct kmem_cache_node *n)
1916+
static void
1917+
init_kmem_cache_node(struct kmem_cache_node *n, struct kmem_cache *s)
19171918
{
19181919
n->nr_partial = 0;
1920+
1921+
/*
1922+
* The larger the object size is, the more pages we want on the partial
1923+
* list to avoid pounding the page allocator excessively.
1924+
*/
1925+
n->min_partial = ilog2(s->size);
1926+
if (n->min_partial < MIN_PARTIAL)
1927+
n->min_partial = MIN_PARTIAL;
1928+
else if (n->min_partial > MAX_PARTIAL)
1929+
n->min_partial = MAX_PARTIAL;
1930+
19191931
spin_lock_init(&n->list_lock);
19201932
INIT_LIST_HEAD(&n->partial);
19211933
#ifdef CONFIG_SLUB_DEBUG
@@ -2087,7 +2099,7 @@ static struct kmem_cache_node *early_kmem_cache_node_alloc(gfp_t gfpflags,
20872099
init_object(kmalloc_caches, n, 1);
20882100
init_tracking(kmalloc_caches, n);
20892101
#endif
2090-
init_kmem_cache_node(n);
2102+
init_kmem_cache_node(n, kmalloc_caches);
20912103
inc_slabs_node(kmalloc_caches, node, page->objects);
20922104

20932105
/*
@@ -2144,7 +2156,7 @@ static int init_kmem_cache_nodes(struct kmem_cache *s, gfp_t gfpflags)
21442156

21452157
}
21462158
s->node[node] = n;
2147-
init_kmem_cache_node(n);
2159+
init_kmem_cache_node(n, s);
21482160
}
21492161
return 1;
21502162
}
@@ -2155,7 +2167,7 @@ static void free_kmem_cache_nodes(struct kmem_cache *s)
21552167

21562168
static int init_kmem_cache_nodes(struct kmem_cache *s, gfp_t gfpflags)
21572169
{
2158-
init_kmem_cache_node(&s->local_node);
2170+
init_kmem_cache_node(&s->local_node, s);
21592171
return 1;
21602172
}
21612173
#endif
@@ -2889,7 +2901,7 @@ static int slab_mem_going_online_callback(void *arg)
28892901
ret = -ENOMEM;
28902902
goto out;
28912903
}
2892-
init_kmem_cache_node(n);
2904+
init_kmem_cache_node(n, s);
28932905
s->node[nid] = n;
28942906
}
28952907
out:

0 commit comments

Comments
 (0)