Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[PATCH] add kmalloc_node, inline cleanup

The patch makes the following function calls available to allocate memory
on a specific node without changing the basic operation of the slab
allocator:

kmem_cache_alloc_node(kmem_cache_t *cachep, unsigned int flags, int node);
kmalloc_node(size_t size, unsigned int flags, int node);

in a similar way to the existing node-blind functions:

kmem_cache_alloc(kmem_cache_t *cachep, unsigned int flags);
kmalloc(size, flags);

kmem_cache_alloc_node was changed to pass flags and the node information
through the existing layers of the slab allocator (which lead to some minor
rearrangements). The functions at the lowest layer (kmem_getpages,
cache_grow) are already node aware. Also __alloc_percpu can call
kmalloc_node now.

Performance measurements (using the pageset localization patch) yields:

w/o patches:
Tasks jobs/min jti jobs/min/task real cpu
1 484.27 100 484.2736 12.02 1.97 Wed Mar 30 20:50:43 2005
100 25170.83 91 251.7083 23.12 150.10 Wed Mar 30 20:51:06 2005
200 34601.66 84 173.0083 33.64 294.14 Wed Mar 30 20:51:40 2005
300 37154.47 86 123.8482 46.99 436.56 Wed Mar 30 20:52:28 2005
400 39839.82 80 99.5995 58.43 580.46 Wed Mar 30 20:53:27 2005
500 40036.32 79 80.0726 72.68 728.60 Wed Mar 30 20:54:40 2005
600 44074.21 79 73.4570 79.23 872.10 Wed Mar 30 20:55:59 2005
700 44016.60 78 62.8809 92.56 1015.84 Wed Mar 30 20:57:32 2005
800 40411.05 80 50.5138 115.22 1161.13 Wed Mar 30 20:59:28 2005
900 42298.56 79 46.9984 123.83 1303.42 Wed Mar 30 21:01:33 2005
1000 40955.05 80 40.9551 142.11 1441.92 Wed Mar 30 21:03:55 2005

with pageset localization and slab API patches:
Tasks jobs/min jti jobs/min/task real cpu
1 484.19 100 484.1930 12.02 1.98 Wed Mar 30 21:10:18 2005
100 27428.25 92 274.2825 21.22 149.79 Wed Mar 30 21:10:40 2005
200 37228.94 86 186.1447 31.27 293.49 Wed Mar 30 21:11:12 2005
300 41725.42 85 139.0847 41.84 434.10 Wed Mar 30 21:11:54 2005
400 43032.22 82 107.5805 54.10 582.06 Wed Mar 30 21:12:48 2005
500 42211.23 83 84.4225 68.94 722.61 Wed Mar 30 21:13:58 2005
600 40084.49 82 66.8075 87.12 873.11 Wed Mar 30 21:15:25 2005
700 44169.30 79 63.0990 92.24 1008.77 Wed Mar 30 21:16:58 2005
800 43097.94 79 53.8724 108.03 1155.88 Wed Mar 30 21:18:47 2005
900 41846.75 79 46.4964 125.17 1303.38 Wed Mar 30 21:20:52 2005
1000 40247.85 79 40.2478 144.60 1442.21 Wed Mar 30 21:23:17 2005

Signed-off-by: Christoph Lameter <christoph@lameter.com>
Signed-off-by: Manfred Spraul <manfred@colorfullife.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by

Manfred Spraul and committed by
Linus Torvalds
97e2bde4 dd1d5afc

+46 -22
+15 -8
include/linux/slab.h
··· 62 62 extern int kmem_cache_destroy(kmem_cache_t *); 63 63 extern int kmem_cache_shrink(kmem_cache_t *); 64 64 extern void *kmem_cache_alloc(kmem_cache_t *, unsigned int __nocast); 65 - #ifdef CONFIG_NUMA 66 - extern void *kmem_cache_alloc_node(kmem_cache_t *, int); 67 - #else 68 - static inline void *kmem_cache_alloc_node(kmem_cache_t *cachep, int node) 69 - { 70 - return kmem_cache_alloc(cachep, GFP_KERNEL); 71 - } 72 - #endif 73 65 extern void kmem_cache_free(kmem_cache_t *, void *); 74 66 extern unsigned int kmem_cache_size(kmem_cache_t *); 67 + extern kmem_cache_t *kmem_find_general_cachep(size_t size, int gfpflags); 75 68 76 69 /* Size description struct for general caches. */ 77 70 struct cache_sizes { ··· 101 108 extern void *kcalloc(size_t, size_t, unsigned int __nocast); 102 109 extern void kfree(const void *); 103 110 extern unsigned int ksize(const void *); 111 + 112 + #ifdef CONFIG_NUMA 113 + extern void *kmem_cache_alloc_node(kmem_cache_t *, int flags, int node); 114 + extern void *kmalloc_node(size_t size, int flags, int node); 115 + #else 116 + static inline void *kmem_cache_alloc_node(kmem_cache_t *cachep, int flags, int node) 117 + { 118 + return kmem_cache_alloc(cachep, flags); 119 + } 120 + static inline void *kmalloc_node(size_t size, int flags, int node) 121 + { 122 + return kmalloc(size, flags); 123 + } 124 + #endif 104 125 105 126 extern int FASTCALL(kmem_cache_reap(int)); 106 127 extern int FASTCALL(kmem_ptr_validate(kmem_cache_t *cachep, void *ptr));
+31 -14
mm/slab.c
··· 583 583 return cachep->array[smp_processor_id()]; 584 584 } 585 585 586 - static inline kmem_cache_t *kmem_find_general_cachep(size_t size, int gfpflags) 586 + static inline kmem_cache_t *__find_general_cachep(size_t size, int gfpflags) 587 587 { 588 588 struct cache_sizes *csizep = malloc_sizes; 589 589 ··· 606 606 return csizep->cs_dmacachep; 607 607 return csizep->cs_cachep; 608 608 } 609 + 610 + kmem_cache_t *kmem_find_general_cachep(size_t size, int gfpflags) 611 + { 612 + return __find_general_cachep(size, gfpflags); 613 + } 614 + EXPORT_SYMBOL(kmem_find_general_cachep); 609 615 610 616 /* Cal the num objs, wastage, and bytes left over for a given slab size. */ 611 617 static void cache_estimate(unsigned long gfporder, size_t size, size_t align, ··· 678 672 int memsize = sizeof(void*)*entries+sizeof(struct array_cache); 679 673 struct array_cache *nc = NULL; 680 674 681 - if (cpu != -1) { 682 - kmem_cache_t *cachep; 683 - cachep = kmem_find_general_cachep(memsize, GFP_KERNEL); 684 - if (cachep) 685 - nc = kmem_cache_alloc_node(cachep, cpu_to_node(cpu)); 686 - } 687 - if (!nc) 675 + if (cpu == -1) 688 676 nc = kmalloc(memsize, GFP_KERNEL); 677 + else 678 + nc = kmalloc_node(memsize, GFP_KERNEL, cpu_to_node(cpu)); 679 + 689 680 if (nc) { 690 681 nc->avail = 0; 691 682 nc->limit = entries; ··· 2364 2361 * and can sleep. And it will allocate memory on the given node, which 2365 2362 * can improve the performance for cpu bound structures. 2366 2363 */ 2367 - void *kmem_cache_alloc_node(kmem_cache_t *cachep, int nodeid) 2364 + void *kmem_cache_alloc_node(kmem_cache_t *cachep, int flags, int nodeid) 2368 2365 { 2369 2366 int loop; 2370 2367 void *objp; ··· 2396 2393 spin_unlock_irq(&cachep->spinlock); 2397 2394 2398 2395 local_irq_disable(); 2399 - if (!cache_grow(cachep, GFP_KERNEL, nodeid)) { 2396 + if (!cache_grow(cachep, flags, nodeid)) { 2400 2397 local_irq_enable(); 2401 2398 return NULL; 2402 2399 } ··· 2438 2435 } 2439 2436 EXPORT_SYMBOL(kmem_cache_alloc_node); 2440 2437 2438 + void *kmalloc_node(size_t size, int flags, int node) 2439 + { 2440 + kmem_cache_t *cachep; 2441 + 2442 + cachep = kmem_find_general_cachep(size, flags); 2443 + if (unlikely(cachep == NULL)) 2444 + return NULL; 2445 + return kmem_cache_alloc_node(cachep, flags, node); 2446 + } 2447 + EXPORT_SYMBOL(kmalloc_node); 2441 2448 #endif 2442 2449 2443 2450 /** ··· 2475 2462 { 2476 2463 kmem_cache_t *cachep; 2477 2464 2478 - cachep = kmem_find_general_cachep(size, flags); 2465 + /* If you want to save a few bytes .text space: replace 2466 + * __ with kmem_. 2467 + * Then kmalloc uses the uninlined functions instead of the inline 2468 + * functions. 2469 + */ 2470 + cachep = __find_general_cachep(size, flags); 2479 2471 if (unlikely(cachep == NULL)) 2480 2472 return NULL; 2481 2473 return __cache_alloc(cachep, flags); ··· 2507 2489 for (i = 0; i < NR_CPUS; i++) { 2508 2490 if (!cpu_possible(i)) 2509 2491 continue; 2510 - pdata->ptrs[i] = kmem_cache_alloc_node( 2511 - kmem_find_general_cachep(size, GFP_KERNEL), 2512 - cpu_to_node(i)); 2492 + pdata->ptrs[i] = kmalloc_node(size, GFP_KERNEL, 2493 + cpu_to_node(i)); 2513 2494 2514 2495 if (!pdata->ptrs[i]) 2515 2496 goto unwind_oom;