Slub: cleanups V1
Subsystems (2)
cover Slub: cleanups V1
A series of cleanup patches that resulted from the rework of the allocation paths to not disable interrupts.
The patches remove the node field from kmem_cache_cpu and generally clean up code in the critical paths.
Hackbench performance before and after using 3.3-rc1
Before After
100 process 20000 152.3 151.2
100 process 20000 160.6 154.8
100 process 20000 161.2 155.5
10 process 20000 15.9 15.5
10 process 20000 15.7 15.5
10 process 20000 15.8 15.5
1 process 20000 1.8 1.6
1 process 20000 1.6 1.6
1 process 20000 1.7 1.6
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 1/9 slub: Use freelist instead of "object" in __slab_alloc
The variable "object" really refers to a list of objects that we are handling.
--- mm/slub.c | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-)
mm/slub.c +20 -18
@@ -2102,7 +2102,7 @@ slab_out_of_memory(struct kmem_cache *s,static inline void *new_slab_objects (struct kmem_cache *s,gfp_t flags,int node,struct kmem_cache_cpu **pc) { -void *object; +void *freelist;struct kmem_cache_cpu *c;struct page *page =new_slab (s, flags, node);
@@ -2115,7 +2115,7 @@ static inline void *new_slab_objects(str* No other reference to the page yet so we can * muck around with it freely without cmpxchg */ - object = page->freelist; + freelist = page->freelist; page->freelist =NULL ;stat (s,ALLOC_SLAB );
@@ -2123,9 +2123,9 @@ static inline void *new_slab_objects(str c->page = page; *pc = c; }else - object =NULL ; + freelist =NULL ; -return object; +return freelist; }/*
@@ -2145,6 +2145,7 @@ static inline void *get_freelist(struct do { freelist = page->freelist; counters = page->counters; + new.counters = counters; VM_BUG_ON(!new.frozen);
@@ -2178,7 +2179,7 @@ static inline void *get_freelist(structstatic void *__slab_alloc (struct kmem_cache *s,gfp_t gfpflags,int node,unsigned long addr,struct kmem_cache_cpu *c) { -void **object; +void *freelist;unsigned long flags;local_irq_save (flags);
@@ -2194,6 +2195,7 @@ static void *__slab_alloc(struct kmem_caif (!c->page) goto new_slab; redo: +if (unlikely (!node_match (c, node))) {stat (s,ALLOC_NODE_MISMATCH );deactivate_slab (s, c);
@@ -2201,15 +2203,15 @@ redo: }/* must check again c->freelist in case of cpu migration or IRQ */ - object = c->freelist; -if (object) + freelist = c->freelist; +if (freelist) goto load_freelist;stat (s,ALLOC_SLOWPATH ); - object =get_freelist (s, c->page); + freelist =get_freelist (s, c->page); -if (!object) { +if (!freelist) { c->page =NULL ;stat (s,DEACTIVATE_BYPASS ); goto new_slab;
@@ -2218,10 +2220,10 @@ redo:stat (s,ALLOC_REFILL ); load_freelist: - c->freelist =get_freepointer (s, object); + c->freelist =get_freepointer (s, freelist); c->tid =next_tid (c->tid);local_irq_restore (flags); -return object; +return freelist; new_slab:
@@ -2235,13 +2237,13 @@ new_slab: }/* Then do expensive stuff like retrieving pages from the partial lists */ - object =get_partial (s, gfpflags, node, c); + freelist =get_partial (s, gfpflags, node, c); -if (unlikely (!object)) { +if (unlikely (!freelist)) { - object =new_slab_objects (s, gfpflags, node, &c); + freelist =new_slab_objects (s, gfpflags, node, &c); -if (unlikely (!object)) { +if (unlikely (!freelist)) {if (!(gfpflags & __GFP_NOWARN) &&printk_ratelimit ())slab_out_of_memory (s, gfpflags, node);
@@ -2254,14 +2256,14 @@ new_slab: goto load_freelist;/* Only entered in the debug case */ -if (!alloc_debug_processing (s, c->page, object, addr)) +if (!alloc_debug_processing (s, c->page, freelist, addr)) goto new_slab;/* Slab failed checks. Next slab needed */ - c->freelist =get_freepointer (s, object); + c->freelist =get_freepointer (s, freelist);deactivate_slab (s, c); c->node =NUMA_NO_NODE ;local_irq_restore (flags); -return object; +return freelist; }/*
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [Slub cleanup 1/9] slub: Use freelist instead of "object" in __slab_alloc
Quoted 3 lines · Christoph Lameter
The variable "object" really refers to a list of objects that we are handling.
... so use "freelist" instead for clarity.
Quoted 1 line
Signed-off-by Christoph Lameter <[email protected]>
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 2/9 slub: Add frozen check in __slab_alloc
In reply to Christoph LameterVerify that objects returned from __slab_alloc come from slab pages in the correct state.
--- mm/slub.c | 6 ++++++ 1 file changed, 6 insertions(+)
mm/slub.c +6 -0
@@ -2220,6 +2220,12 @@ redo:stat (s,ALLOC_REFILL ); load_freelist: +/* +* freelist is pointing to the list of objects to be used. +* page is pointing to the page from which the objects are obtained. +* That page must be frozen for per cpu allocations to work. +*/ +VM_BUG_ON (!c->page->frozen); c->freelist =get_freepointer (s, freelist); c->tid =next_tid (c->tid);local_irq_restore (flags);
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [Slub cleanup 2/9] slub: Add frozen check in __slab_alloc
Quoted 4 lines · Christoph Lameter
Verify that objects returned from
__slab_alloccome from slab pages in the correct state.Signed-off-by Christoph Lameter <[email protected]>
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 3/9 slub: Acquire_slab() avoid loop
In reply to Christoph LameterAvoid the loop in acquire slab and simply fail if there is a conflict.
This will cause the next page on the list to be considered.
--- mm/slub.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-)
mm/slub.c +15 -13
@@ -1484,12 +1484,12 @@ static inline void remove_partial(struct }/* -* Lock slab, remove from the partial list and put the object into the -* per cpu freelist. +* Remove slab from the partial list, freeze it and +* return the pointer to the freelist. * * Returns a list of objects or NULL if it fails. * -* Must hold list_lock. +* Must hold list_lock since we modify the partial list. */ static inline void *acquire_slab(struct kmem_cache *s, struct kmem_cache_node *n, struct page *page,
@@ -1504,22 +1504,24 @@ static inline void *acquire_slab(struct* The old freelist is the list of objects for the * per cpu allocation list. */ -do { - freelist = page->freelist; - counters = page->counters; - new.counters = counters; -if (mode) - new.inuse = page->objects; + freelist = page->freelist; + counters = page->counters; + new.counters = counters; +if (mode) + new.inuse = page->objects; -VM_BUG_ON (new.frozen); - new.frozen =1 ; +VM_BUG_ON (new.frozen); + new.frozen =1 ; - }while (!__cmpxchg_double_slab (s, page, +if (!__cmpxchg_double_slab (s, page, freelist, counters,NULL , new.counters, -"lock and freeze" )); +"acquire_slab" )) + +return NULL ;remove_partial (n, page); +WARN_ON (!freelist);return freelist; }
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 4/9 slub: Simplify control flow in __slab_alloc()
In reply to Christoph LameterSimplify control flow a bit avoiding nesting.
--- mm/slub.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-)
mm/slub.c +6 -8
@@ -2247,17 +2247,15 @@ new_slab:/* Then do expensive stuff like retrieving pages from the partial lists */ freelist =get_partial (s, gfpflags, node, c); -if (unlikely (!freelist)) { - +if (!freelist) freelist =new_slab_objects (s, gfpflags, node, &c); -if (unlikely (!freelist)) { -if (!(gfpflags & __GFP_NOWARN) &&printk_ratelimit ()) -slab_out_of_memory (s, gfpflags, node); +if (unlikely (!freelist)) { +if (!(gfpflags & __GFP_NOWARN) &&printk_ratelimit ()) +slab_out_of_memory (s, gfpflags, node); -local_irq_restore (flags); -return NULL ; - } +local_irq_restore (flags); +return NULL ; }if (likely (!kmem_cache_debug (s)))
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [Slub cleanup 4/9] slub: Simplify control flow in __slab_alloc()
Quoted 3 lines · Christoph Lameter
Simplify control flow a bit avoiding nesting.
Signed-off-by Christoph Lameter <[email protected]>
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 6/9 slub: Get rid of the node field
In reply to Christoph LameterThe node field is always page_to_nid(c->page). So its rather easy to replace. Note that there maybe slightly more overhead in various hot paths due to the need to shift the bits from page->flags. However, that is mostly compensated for by a smaller footprint of the kmem_cache_cpu structure (this patch reduces that to 3 words per cache) which allows better caching.
--- include/linux/slub_def.h | 1 - mm/slub.c | 35 ++++++++++++++++------------------- 2 files changed, 16 insertions(+), 20 deletions(-)
mm/slub.c +16 -19
@@ -1555,7 +1555,6 @@ static void *get_partial_node(struct kmeif (!object) { c->page = page; - c->node =page_to_nid (page);stat (s,ALLOC_FROM_PARTIAL ); object = t; available = page->objects - page->inuse;
@@ -2032,7 +2031,7 @@ static void flush_all(struct kmem_cachestatic inline int node_match (struct kmem_cache_cpu *c,int node) {#ifdef CONFIG_NUMA -if (node !=NUMA_NO_NODE && c->node != node) +if (node !=NUMA_NO_NODE &&page_to_nid (c->page) != node)return 0 ;#endif return 1 ;
@@ -2127,7 +2126,6 @@ static inline void *new_slab_objects(str page->freelist =NULL ;stat (s,ALLOC_SLAB ); - c->node =page_to_nid (page); c->page = page; *pc = c; }else
@@ -2244,7 +2242,6 @@ new_slab:if (c->partial) { c->page = c->partial; c->partial = c->page->next; - c->node =page_to_nid (c->page);stat (s,CPU_PARTIAL_ALLOC ); c->freelist =NULL ; goto redo;
@@ -2269,7 +2266,6 @@ new_slab: c->freelist =get_freepointer (s, freelist);deactivate_slab (s, c); - c->node =NUMA_NO_NODE ;local_irq_restore (flags);return freelist; }
@@ -4474,30 +4470,31 @@ static ssize_t show_slab_objects(structfor_each_possible_cpu (cpu) {struct kmem_cache_cpu *c =per_cpu_ptr (s->cpu_slab, cpu); -int node =ACCESS_ONCE (c->node); +int node;struct page *page; -if (node <0 ) -continue ; page =ACCESS_ONCE (c->page); -if (page) { -if (flags &SO_TOTAL ) - x = page->objects; -else if (flags &SO_OBJECTS ) - x = page->inuse; -else - x =1 ; +if (!page) +continue ; - total += x; - nodes[node] += x; - } - page = c->partial; + node =page_to_nid (page); +if (flags &SO_TOTAL ) + x = page->objects; +else if (flags &SO_OBJECTS ) + x = page->inuse; +else + x =1 ; + total += x; + nodes[node] += x; + + page =ACCESS_ONCE (c->partial);if (page) { x = page->pobjects; total += x; nodes[node] += x; } + per_cpu[node]++; } }
include/linux/slub_def.h +0 -1
@@ -45,7 +45,6 @@ struct kmem_cache_cpu {unsigned long tid;/* Globally unique transaction id */ struct page *page;/* The slab from which we are allocating */ struct page *partial;/* Partially allocated frozen slabs */ -int node;/* The node of the page (or -1 for debug) */ #ifdef CONFIG_SLUB_STATS unsigned stat[NR_SLUB_STAT_ITEMS ];#endif
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [Slub cleanup 6/9] slub: Get rid of the node field
Quoted 6 lines · Christoph Lameter
The node field is always
page_to_nid(c->page). So its rather easy to replace. Note that there maybe slightly more overhead in various hot paths due to the need to shift the bits frompage->flags. However, that is mostly compensated for by a smaller footprint of thekmem_cache_cpustructure (this patch reduces that to 3 words per cache) which allows better caching.
s/3 words per cache/4 words per cache/
Quoted 1 line
Signed-off-by Christoph Lameter <[email protected]>
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 7/9 slub: Separate out kmem_cache_cpu processing from deactivate_slab
In reply to Christoph LameterProcessing on fields of kmem_cache_cpu is cleaner if code working on fields of this struct is taken out of deactivate_slab().
--- mm/slub.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-)
mm/slub.c +12 -12
@@ -1712,14 +1712,12 @@ void init_kmem_cache_cpus(struct kmem_ca/* * Remove the cpu slab */ -static void deactivate_slab (struct kmem_cache *s,struct kmem_cache_cpu *c) +static void deactivate_slab (struct kmem_cache *s,struct page *page,void *freelist) {enum slab_modes {M_NONE ,M_PARTIAL ,M_FULL ,M_FREE }; -struct page *page = c->page;struct kmem_cache_node *n =get_node (s,page_to_nid (page));int lock =0 ;enum slab_modes l =M_NONE , m =M_NONE ; -void *freelist;void *nextfree;int tail =DEACTIVATE_TO_HEAD ;struct page new;
@@ -1730,11 +1728,6 @@ static void deactivate_slab(struct kmem_ tail =DEACTIVATE_TO_TAIL ; } - c->tid =next_tid (c->tid); - c->page =NULL ; - freelist = c->freelist; - c->freelist =NULL ; -/* * Stage one: Free all available per cpu objects back * to the page freelist while it is still frozen. Leave the
@@ -1992,7 +1985,11 @@ int put_cpu_partial(struct kmem_cache *sstatic inline void flush_slab (struct kmem_cache *s,struct kmem_cache_cpu *c) {stat (s,CPUSLAB_FLUSH ); -deactivate_slab (s, c); +deactivate_slab (s, c->page, c->freelist); + + c->tid =next_tid (c->tid); + c->page =NULL ; + c->freelist =NULL ; }/*
@@ -2204,7 +2201,9 @@ redo:if (unlikely (!node_match (c, node))) {stat (s,ALLOC_NODE_MISMATCH ); -deactivate_slab (s, c); +deactivate_slab (s, c->page, c->freelist); + c->page =NULL ; + c->freelist =NULL ; goto new_slab; }
@@ -2264,8 +2263,9 @@ new_slab:if (!alloc_debug_processing (s, c->page, freelist, addr)) goto new_slab;/* Slab failed checks. Next slab needed */ - c->freelist =get_freepointer (s, freelist); -deactivate_slab (s, c); +deactivate_slab (s, c->page,get_freepointer (s, freelist)); + c->page =NULL ; + c->freelist =NULL ;local_irq_restore (flags);return freelist; }
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 8/9 slub: Use page variable instead of c->page.
In reply to Christoph LameterStore the value of c->page to avoid additional fetches from per cpu data.
--- mm/slub.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-)
mm/slub.c +10 -7
@@ -2183,6 +2183,7 @@ static void *__slab_alloc(struct kmem_ca unsigned long addr, struct kmem_cache_cpu *c) { void *freelist; +struct page *page;unsigned long flags;local_irq_save (flags);
@@ -2195,13 +2196,14 @@ static void *__slab_alloc(struct kmem_ca c =this_cpu_ptr (s->cpu_slab);#endif -if (!c->page) + page = c->page; +if (!page) goto new_slab; redo:if (unlikely (!node_match (c, node))) {stat (s,ALLOC_NODE_MISMATCH ); -deactivate_slab (s, c->page, c->freelist); +deactivate_slab (s, page, c->freelist); c->page =NULL ; c->freelist =NULL ; goto new_slab;
@@ -2214,7 +2216,7 @@ redo:stat (s,ALLOC_SLOWPATH ); - freelist =get_freelist (s, c->page); + freelist =get_freelist (s, page);if (!freelist) { c->page =NULL ;
@@ -2239,8 +2241,8 @@ load_freelist: new_slab:if (c->partial) { - c->page = c->partial; - c->partial = c->page->next; + page = c->page = c->partial; + c->partial = page->next;stat (s,CPU_PARTIAL_ALLOC ); c->freelist =NULL ; goto redo;
@@ -2256,14 +2258,15 @@ new_slab:return NULL ; } + page = c->page;if (likely (!kmem_cache_debug (s))) goto load_freelist;/* Only entered in the debug case */ -if (!alloc_debug_processing (s, c->page, freelist, addr)) +if (!alloc_debug_processing (s, page, freelist, addr)) goto new_slab;/* Slab failed checks. Next slab needed */ -deactivate_slab (s, c->page,get_freepointer (s, freelist)); +deactivate_slab (s, page,get_freepointer (s, freelist)); c->page =NULL ; c->freelist =NULL ;local_irq_restore (flags);
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 9/9 slub: pass page to node_match() instead of kmem_cache_cpu structure
In reply to Christoph LameterAvoid passing the kmem_cache_cpu pointer to node_match. This makes the node_match function more generic and easier to understand.
--- mm/slub.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
mm/slub.c +6 -4
@@ -2025,10 +2025,10 @@ static void flush_all(struct kmem_cache* Check if the objects in a per cpu structure fit numa * locality expectations. */ -static inline int node_match (struct kmem_cache_cpu *c,int node) +static inline int node_match (struct page *page,int node) {#ifdef CONFIG_NUMA -if (node !=NUMA_NO_NODE &&page_to_nid (c->page) != node) +if (node !=NUMA_NO_NODE &&page_to_nid (page) != node)return 0 ;#endif return 1 ;
@@ -2201,7 +2201,7 @@ static void *__slab_alloc(struct kmem_ca goto new_slab; redo: -if (unlikely (!node_match (c, node))) { +if (unlikely (!node_match (page, node))) {stat (s,ALLOC_NODE_MISMATCH );deactivate_slab (s, page, c->freelist); c->page =NULL ;
@@ -2288,6 +2288,7 @@ static __always_inline void *slab_alloc( {void **object;struct kmem_cache_cpu *c; +struct page *page;unsigned long tid;if (slab_pre_alloc_hook (s, gfpflags))
@@ -2313,7 +2314,8 @@ redo:barrier (); object = c->freelist; -if (unlikely (!object || !node_match (c, node))) + page = c->page; +if (unlikely (!object || !node_match (page, node))) object =__slab_alloc (s, gfpflags, node, addr, c);
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
A message that is not in the archive (sent off-list or not yet received): [email protected]
Re: [Slub cleanup 5/9] slub: new_slab_objects() can also get objects from partial list
Quoted 4 lines · Christoph Lameter
Moving the attempt to get a slab page from the partial lists simplifies
__slab_allocwhich is rather complicated.Signed-off-by Christoph Lameter <[email protected]>
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>