aboutsummaryrefslogtreecommitdiffstats
path: root/mm/slab.c
diff options
context:
space:
mode:
authorJoonsoo Kim <iamjoonsoo.kim@lge.com>2013-12-02 03:49:42 -0500
committerPekka Enberg <penberg@kernel.org>2014-02-08 05:12:38 -0500
commita41adfaa23dfe58d0832e74bef54b98db8dcc774 (patch)
tree08c45463bb7f7c8d6ecaaf4c3c9a8f3543c92134 /mm/slab.c
parentf315e3fa1cf5b3317fc948708645fff889ce1e63 (diff)
slab: introduce byte sized index for the freelist of a slab
Currently, the freelist of a slab consist of unsigned int sized indexes. Since most of slabs have less number of objects than 256, large sized indexes is needless. For example, consider the minimum kmalloc slab. It's object size is 32 byte and it would consist of one page, so 256 indexes through byte sized index are enough to contain all possible indexes. There can be some slabs whose object size is 8 byte. We cannot handle this case with byte sized index, so we need to restrict minimum object size. Since these slabs are not major, wasted memory from these slabs would be negligible. Some architectures' page size isn't 4096 bytes and rather larger than 4096 bytes (One example is 64KB page size on PPC or IA64) so that byte sized index doesn't fit to them. In this case, we will use two bytes sized index. Below is some number for this patch. * Before * kmalloc-512 525 640 512 8 1 : tunables 54 27 0 : slabdata 80 80 0 kmalloc-256 210 210 256 15 1 : tunables 120 60 0 : slabdata 14 14 0 kmalloc-192 1016 1040 192 20 1 : tunables 120 60 0 : slabdata 52 52 0 kmalloc-96 560 620 128 31 1 : tunables 120 60 0 : slabdata 20 20 0 kmalloc-64 2148 2280 64 60 1 : tunables 120 60 0 : slabdata 38 38 0 kmalloc-128 647 682 128 31 1 : tunables 120 60 0 : slabdata 22 22 0 kmalloc-32 11360 11413 32 113 1 : tunables 120 60 0 : slabdata 101 101 0 kmem_cache 197 200 192 20 1 : tunables 120 60 0 : slabdata 10 10 0 * After * kmalloc-512 521 648 512 8 1 : tunables 54 27 0 : slabdata 81 81 0 kmalloc-256 208 208 256 16 1 : tunables 120 60 0 : slabdata 13 13 0 kmalloc-192 1029 1029 192 21 1 : tunables 120 60 0 : slabdata 49 49 0 kmalloc-96 529 589 128 31 1 : tunables 120 60 0 : slabdata 19 19 0 kmalloc-64 2142 2142 64 63 1 : tunables 120 60 0 : slabdata 34 34 0 kmalloc-128 660 682 128 31 1 : tunables 120 60 0 : slabdata 22 22 0 kmalloc-32 11716 11780 32 124 1 : tunables 120 60 0 : slabdata 95 95 0 kmem_cache 197 210 192 21 1 : tunables 120 60 0 : slabdata 10 10 0 kmem_caches consisting of objects less than or equal to 256 byte have one or more objects than before. In the case of kmalloc-32, we have 11 more objects, so 352 bytes (11 * 32) are saved and this is roughly 9% saving of memory. Of couse, this percentage decreases as the number of objects in a slab decreases. Here are the performance results on my 4 cpus machine. * Before * Performance counter stats for 'perf bench sched messaging -g 50 -l 1000' (10 runs): 229,945,138 cache-misses ( +- 0.23% ) 11.627897174 seconds time elapsed ( +- 0.14% ) * After * Performance counter stats for 'perf bench sched messaging -g 50 -l 1000' (10 runs): 218,640,472 cache-misses ( +- 0.42% ) 11.504999837 seconds time elapsed ( +- 0.21% ) cache-misses are reduced by this patchset, roughly 5%. And elapsed times are improved by 1%. Acked-by: Christoph Lameter <cl@linux.com> Acked-by: David Rientjes <rientjes@google.com> Signed-off-by: Joonsoo Kim <iamjoonsoo.kim@lge.com> Signed-off-by: Pekka Enberg <penberg@kernel.org>
Diffstat (limited to 'mm/slab.c')
-rw-r--r--mm/slab.c18
1 files changed, 9 insertions, 9 deletions
diff --git a/mm/slab.c b/mm/slab.c
index 9d4c7b50dfdc..b514bf81aca8 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -634,8 +634,8 @@ static void cache_estimate(unsigned long gfporder, size_t buffer_size,
634 634
635 } else { 635 } else {
636 nr_objs = calculate_nr_objs(slab_size, buffer_size, 636 nr_objs = calculate_nr_objs(slab_size, buffer_size,
637 sizeof(unsigned int), align); 637 sizeof(freelist_idx_t), align);
638 mgmt_size = ALIGN(nr_objs * sizeof(unsigned int), align); 638 mgmt_size = ALIGN(nr_objs * sizeof(freelist_idx_t), align);
639 } 639 }
640 *num = nr_objs; 640 *num = nr_objs;
641 *left_over = slab_size - nr_objs*buffer_size - mgmt_size; 641 *left_over = slab_size - nr_objs*buffer_size - mgmt_size;
@@ -2038,7 +2038,7 @@ static size_t calculate_slab_order(struct kmem_cache *cachep,
2038 * looping condition in cache_grow(). 2038 * looping condition in cache_grow().
2039 */ 2039 */
2040 offslab_limit = size; 2040 offslab_limit = size;
2041 offslab_limit /= sizeof(unsigned int); 2041 offslab_limit /= sizeof(freelist_idx_t);
2042 2042
2043 if (num > offslab_limit) 2043 if (num > offslab_limit)
2044 break; 2044 break;
@@ -2286,7 +2286,7 @@ __kmem_cache_create (struct kmem_cache *cachep, unsigned long flags)
2286 return -E2BIG; 2286 return -E2BIG;
2287 2287
2288 freelist_size = 2288 freelist_size =
2289 ALIGN(cachep->num * sizeof(unsigned int), cachep->align); 2289 ALIGN(cachep->num * sizeof(freelist_idx_t), cachep->align);
2290 2290
2291 /* 2291 /*
2292 * If the slab has been placed off-slab, and we have enough space then 2292 * If the slab has been placed off-slab, and we have enough space then
@@ -2299,7 +2299,7 @@ __kmem_cache_create (struct kmem_cache *cachep, unsigned long flags)
2299 2299
2300 if (flags & CFLGS_OFF_SLAB) { 2300 if (flags & CFLGS_OFF_SLAB) {
2301 /* really off slab. No need for manual alignment */ 2301 /* really off slab. No need for manual alignment */
2302 freelist_size = cachep->num * sizeof(unsigned int); 2302 freelist_size = cachep->num * sizeof(freelist_idx_t);
2303 2303
2304#ifdef CONFIG_PAGE_POISONING 2304#ifdef CONFIG_PAGE_POISONING
2305 /* If we're going to use the generic kernel_map_pages() 2305 /* If we're going to use the generic kernel_map_pages()
@@ -2569,15 +2569,15 @@ static void *alloc_slabmgmt(struct kmem_cache *cachep,
2569 return freelist; 2569 return freelist;
2570} 2570}
2571 2571
2572static inline unsigned int get_free_obj(struct page *page, unsigned int idx) 2572static inline freelist_idx_t get_free_obj(struct page *page, unsigned char idx)
2573{ 2573{
2574 return ((unsigned int *)page->freelist)[idx]; 2574 return ((freelist_idx_t *)page->freelist)[idx];
2575} 2575}
2576 2576
2577static inline void set_free_obj(struct page *page, 2577static inline void set_free_obj(struct page *page,
2578 unsigned int idx, unsigned int val) 2578 unsigned char idx, freelist_idx_t val)
2579{ 2579{
2580 ((unsigned int *)(page->freelist))[idx] = val; 2580 ((freelist_idx_t *)(page->freelist))[idx] = val;
2581} 2581}
2582 2582
2583static void cache_init_objs(struct kmem_cache *cachep, 2583static void cache_init_objs(struct kmem_cache *cachep,