Slab Movable Objects (SMO)
Subsystems (6)
v5 cover Slab Movable Objects (SMO)
Hi,
Another iteration of the SMO patch set, updates to this version are restricted to the XArray patches (#9 and #10 and tested with module implemented in #11).
Applies on top of Linus' tree (tag: v5.2-rc1).
This is a patch set implementing movable objects within the SLUB allocator. This is work based on Christopher Lameter's patch set:
https://lore.kernel.org/patchwork/project/lkml/list/?series=377335
The original code logic is from that set and implemented by Christopher. Clean up, refactoring, documentation, and additional features by myself. Responsibility for any bugs remaining falls solely with myself.
I am intending on sending a non-RFC version soon after this one (if XArray stuff is ok). If anyone has any objects with SMO in general please yell at me now.
Changes to this version:
Patch XArray to use a separate slab cache. Currently the radix tree and XArray use the same slab cache. Radix tree nodes can not be moved but XArray nodes can.
Matthew,
Does this fit in ok with your plans for the XArray and radix tree? I don't really like the function names used here or the init function name (xarray_slabcache_init()). If there is a better way to do this please mercilessly correct me :)
Thanks for looking at this,
Tobin.
Tobin C. Harding (16):
slub: Add isolate() and migrate() methods tools/vm/slabinfo: Add support for -C and -M options
slub: Sort slab cache list
slub: Slab defrag core
tools/vm/slabinfo: Add remote node defrag ratio output tools/vm/slabinfo: Add defrag_used_ratio output tools/testing/slab: Add object migration test module tools/testing/slab: Add object migration test suite
lib: Separate radix_tree_node and xa_node slab cache
xarray: Implement migration function for xa_node objects tools/testing/slab: Add XArray movable objects tests
slub: Enable moving objects to/from specific nodes
slub: Enable balancing slabs across nodes
dcache: Provide a dentry constructor
dcache: Implement partial shrink via Slab Movable Objects
dcache: Add CONFIG_DCACHE_SMO
Documentation/ABI/testing/sysfs-kernel-slab | 14 + fs/dcache.c | 110 ++- include/linux/slab.h | 71 ++ include/linux/slub_def.h | 10 + include/linux/xarray.h | 3 + init/main.c | 2 + lib/radix-tree.c | 2 +- lib/xarray.c | 109 ++- mm/Kconfig | 14 + mm/slab_common.c | 2 +- mm/slub.c | 819 ++++++++++++++++++-- tools/testing/slab/Makefile | 10 + tools/testing/slab/slub_defrag.c | 567 ++++++++++++++ tools/testing/slab/slub_defrag.py | 451 +++++++++++ tools/testing/slab/slub_defrag_xarray.c | 211 +++++ tools/vm/slabinfo.c | 51 +- 16 files changed, 2343 insertions(+), 103 deletions(-) create mode 100644 tools/testing/slab/Makefile create mode 100644 tools/testing/slab/slub_defrag.c create mode 100755 tools/testing/slab/slub_defrag.py create mode 100644 tools/testing/slab/slub_defrag_xarray.c
Signature · 1 line
2.21.0
RFC PATCH v5 1/16 slub: Add isolate() and migrate() methods
Add the two methods needed for moving objects and enable the display of the callbacks via the /sys/kernel/slab interface.
Add documentation explaining the use of these methods and the prototypes for slab.h. Add functions to setup the callbacks method for a slab cache.
Add empty functions for SLAB/SLOB. The API is generic so it could be theoretically implemented for these allocators as well.
Change sysfs 'ctor' field to be 'ops' to contain all the callback operations defined for a slab cache. Display the existing 'ctor' callback in the ops fields contents along with 'isolate' and 'migrate' callbacks.
--- include/linux/slab.h | 70 ++++++++++++++++++++++++++++++++++++++++ include/linux/slub_def.h | 3 ++ mm/slub.c | 59 +++++++++++++++++++++++++++++---- 3 files changed, 126 insertions(+), 6 deletions(-)
include/linux/slab.h +70 -0
@@ -154,6 +154,76 @@ void memcg_create_kmem_cache(struct mem_cgroup *, struct kmem_cache *);void memcg_deactivate_kmem_caches (struct mem_cgroup *);void memcg_destroy_kmem_caches (struct mem_cgroup *); +/* +* Function prototypes passed to kmem_cache_setup_mobility() to enable +* mobile objects and targeted reclaim in slab caches. +*/ + +/** +* typedef kmem_cache_isolate_func - Object migration callback function. +* @s: The cache we are working on. +* @ptr: Pointer to an array of pointers to the objects to isolate. +* @nr: Number of objects in @ptr array. +* +* The purpose of kmem_cache_isolate_func() is to pin each object so that +* they cannot be freed until kmem_cache_migrate_func() has processed +* them. This may be accomplished by increasing the refcount or setting +* a flag. +* +* The object pointer array passed is also passed to +* kmem_cache_migrate_func(). The function may remove objects from the +* array by setting pointers to %NULL. This is useful if we can +* determine that an object is being freed because +* kmem_cache_isolate_func() was called when the subsystem was calling +* kmem_cache_free(). In that case it is not necessary to increase the +* refcount or specially mark the object because the release of the slab +* lock will lead to the immediate freeing of the object. +* +* Context: Called with locks held so that the slab objects cannot be +* freed. We are in an atomic context and no slab operations +* may be performed. +* Return: A pointer that is passed to the migrate function. If any +* objects cannot be touched at this point then the pointer may +* indicate a failure and then the migration function can simply +* remove the references that were already obtained. The private +* data could be used to track the objects that were already pinned. +*/ +typedef void *kmem_cache_isolate_func (struct kmem_cache *s,void **ptr,int nr); + +/** +* typedef kmem_cache_migrate_func - Object migration callback function. +* @s: The cache we are working on. +* @ptr: Pointer to an array of pointers to the objects to migrate. +* @nr: Number of objects in @ptr array. +* @node: The NUMA node where the object should be allocated. +* @private: The pointer returned by kmem_cache_isolate_func(). +* +* This function is responsible for migrating objects. Typically, for +* each object in the input array you will want to allocate an new +* object, copy the original object, update any pointers, and free the +* old object. +* +* After this function returns all pointers to the old object should now +* point to the new object. +* +* Context: Called with no locks held and interrupts enabled. Sleeping +* is possible. Any operation may be performed. +*/ +typedef void kmem_cache_migrate_func (struct kmem_cache *s,void **ptr, +int nr,int node,void *private); + +/* +* kmem_cache_setup_mobility() is used to setup callbacks for a slab cache. +*/ +#ifdef CONFIG_SLUB +void kmem_cache_setup_mobility (struct kmem_cache *,kmem_cache_isolate_func , +kmem_cache_migrate_func ); +#else +static inline void +kmem_cache_setup_mobility (struct kmem_cache *s,kmem_cache_isolate_func isolate, +kmem_cache_migrate_func migrate) {} +#endif +/* * Please use this macro to create slab caches. Simply specify the * name of the structure and maybe some flags that are listed above.
include/linux/slub_def.h +3 -0
@@ -99,6 +99,9 @@ struct kmem_cache {gfp_t allocflags;/* gfp flags to use on each alloc */ int refcount;/* Refcount for slab cache destroy */ void (*ctor)(void *); +kmem_cache_isolate_func *isolate; +kmem_cache_migrate_func *migrate; +unsigned int inuse;/* Offset to metadata */ unsigned int align;/* Alignment */ unsigned int red_left_pad;/* Left redzone padding size */
mm/slub.c +53 -6
79 lines not on this page · raw message
Signature · 1 line
2.21.0
Re: [RFC PATCH v5 01/16] slub: Add isolate() and migrate() methods
Quoted 15 lines · Tobin C. Harding
Add the two methods needed for moving objects and enable the display of the callbacks via the
/sys/kernel/slabinterface.Add documentation explaining the use of these methods and the prototypes for
slab.h. Add functions to setup the callbacks method for a slab cache.Add empty functions for SLAB/SLOB. The API is generic so it could be theoretically implemented for these allocators as well.
Change sysfs 'ctor' field to be 'ops' to contain all the callback operations defined for a slab cache. Display the existing 'ctor' callback in the ops fields contents along with 'isolate' and 'migrate' callbacks.
Quoted 7 lines
Co-developed-by Christoph Lameter <[email protected]>Signed-off-by Tobin C. Harding <[email protected]>--- include/linux/slab.h | 70 ++++++++++++++++++++++++++++++++++++++++ include/linux/slub_def.h | 3 ++ mm/slub.c | 59 +++++++++++++++++++++++++++++---- 3 files changed, 126 insertions(+), 6 deletions(-)
Thanks!
RFC PATCH v5 2/16 tools/vm/slabinfo: Add support for -C and -M options
In reply to Tobin C. Harding-C lists caches that use a ctor.
-M lists caches that support object migration.
Add command line options to show caches with a constructor and caches that are movable (i.e. have migrate function).
--- tools/vm/slabinfo.c | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-)
tools/vm/slabinfo.c +36 -4
@@ -33,6 +33,7 @@ struct slabinfo {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; +int movable, ctor;unsigned long partial, objects, slabs, objects_partial, objects_total;unsigned long alloc_fastpath, alloc_slowpath;unsigned long free_fastpath, free_slowpath;
@@ -67,6 +68,8 @@ int show_report;int show_alias;int show_slab;int skip_zero =1 ; +int show_movable; +int show_ctor;int show_numa;int show_track;int show_first_alias;
@@ -109,11 +112,13 @@ static void fatal(const char *x, ...)static void usage (void ) { -printf ("slabinfo 4/15/2011. (c) 2007 sgi/(c) 2011 Linux Foundation.\n\n" -"slabinfo [-aADefhilnosrStTvz1LXBU] [N=K] [-dafzput] [slab-regexp]\n" +printf ("slabinfo 4/15/2017. (c) 2007 sgi/(c) 2011 Linux Foundation/(c) 2017 Jump Trading LLC.\n\n" +"slabinfo [-aACDefhilMnosrStTvz1LXBU] [N=K] [-dafzput] [slab-regexp]\n" +"-a|--aliases Show aliases\n" "-A|--activity Most active slabs first\n" "-B|--Bytes Show size in bytes\n" +"-C|--ctor Show slabs with ctors\n" "-D|--display-active Switch line format to activity\n" "-e|--empty Show empty slabs\n" "-f|--first-alias Show first alias\n"
@@ -121,6 +126,7 @@ static void usage(void)"-i|--inverted Inverted list\n" "-l|--slabs Show slabs\n" "-L|--Loss Sort by loss\n" +"-M|--movable Show caches that support movable objects\n" "-n|--numa Show NUMA information\n" "-N|--lines=K Show the first K slabs\n" "-o|--ops Show kmem_cache_ops\n"
@@ -588,6 +594,12 @@ static void slabcache(struct slabinfo *s)if (show_empty && s->slabs)return ; +if (show_ctor && !s->ctor) +return ; + +if (show_movable && !s->movable) +return ; +if (sort_loss ==0 )store_size (size_str,slab_size (s));else
@@ -602,6 +614,10 @@ static void slabcache(struct slabinfo *s) *p++ ='*' ;if (s->cache_dma) *p++ ='d' ; +if (s->ctor) + *p++ ='C' ; +if (s->movable) + *p++ ='M' ;if (s->hwcache_align) *p++ ='A' ;if (s->poison)
@@ -636,7 +652,8 @@ static void slabcache(struct slabinfo *s)printf ("%-21s %8ld %7d %15s %14s %4d %1d %3ld %3ld %s\n" , s->name, s->objects, s->object_size, size_str, dist_str, s->objs_per_slab, s->order, - s->slabs ? (s->partial *100 ) / s->slabs :100 , + s->slabs ? (s->partial *100 ) / + (s->slabs * s->objs_per_slab) :100 , s->slabs ? (s->objects * s->object_size *100 ) / (s->slabs * (page_size << s->order)) :100 , flags);
@@ -1256,6 +1273,13 @@ static void read_slab_dir(void) slab->alloc_node_mismatch =get_obj ("alloc_node_mismatch" ); slab->deactivate_bypass =get_obj ("deactivate_bypass" );chdir (".." ); +if (read_slab_obj (slab,"ops" )) { +if (strstr (buffer,"ctor :" )) + slab->ctor =1 ; +if (strstr (buffer,"migrate :" )) + slab->movable =1 ; + } +if (slab->name[0 ] ==':' ) alias_targets++; slab++;
@@ -1332,6 +1356,8 @@ static void xtotals(void) }struct option opts[] = { + {"ctor" , no_argument,NULL ,'C' }, + {"movable" , no_argument,NULL ,'M' }, {"aliases" , no_argument,NULL ,'a' }, {"activity" , no_argument,NULL ,'A' }, {"debug" , optional_argument,NULL ,'d' },
@@ -1367,7 +1393,7 @@ int main(int argc, char *argv[]) page_size =getpagesize (); -while ((c =getopt_long (argc, argv,"aAd::Defhil1noprstvzTSN:LXBU" , +while ((c =getopt_long (argc, argv,"aACd::Defhil1MnoprstvzTSN:LXBU" , opts,NULL )) !=-1 )switch (c) {case '1' :
@@ -1376,6 +1402,9 @@ int main(int argc, char *argv[])case 'a' : show_alias =1 ;break ; +case 'C' : + show_ctor =1 ; +break ;case 'A' : sort_active =1 ;break ;
@@ -1399,6 +1428,9 @@ int main(int argc, char *argv[])case 'i' : show_inverted =1 ;break ; +case 'M' : + show_movable =1 ; +break ;case 'n' : show_numa =1 ;break ;
Signature · 1 line
2.21.0
RFC PATCH v5 3/16 slub: Sort slab cache list
In reply to Tobin C. HardingIt is advantageous to have all defragmentable slabs together at the beginning of the list of slabs so that there is no need to scan the complete list. Put defragmentable caches first when adding a slab cache and others last.
--- mm/slab_common.c | 2 +- mm/slub.c | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-)
mm/slab_common.c +1 -1
@@ -393,7 +393,7 @@ static struct kmem_cache *create_cache(const char *name, goto out_free_cache; s->refcount =1 ; -list_add (&s->list, &slab_caches); +list_add_tail (&s->list, &slab_caches);memcg_link_cache (s); out:if (err)
mm/slub.c +6 -0
@@ -4333,6 +4333,8 @@ void kmem_cache_setup_mobility(struct kmem_cache *s,return ; } +mutex_lock (&slab_mutex); + s->isolate = isolate; s->migrate = migrate;
@@ -4341,6 +4343,10 @@ void kmem_cache_setup_mobility(struct kmem_cache *s,* to disable fast cmpxchg based processing. */ s->flags &= ~__CMPXCHG_DOUBLE; + +list_move (&s->list, &slab_caches);/* Move to top */ + +mutex_unlock (&slab_mutex); }EXPORT_SYMBOL (kmem_cache_setup_mobility);
Signature · 1 line
2.21.0
Re: [RFC PATCH v5 03/16] slub: Sort slab cache list
Quoted 7 lines · Tobin C. Harding
It is advantageous to have all defragmentable slabs together at the beginning of the list of slabs so that there is no need to scan the complete list. Put defragmentable caches first when adding a slab cache and others last.
Co-developed-by Christoph Lameter <[email protected]>Signed-off-by Tobin C. Harding <[email protected]>
RFC PATCH v5 4/16 slub: Slab defrag core
In reply to Tobin C. HardingInternal fragmentation can occur within pages used by the slub allocator. Under some workloads large numbers of pages can be used by partial slab pages. This under-utilisation is bad simply because it wastes memory but also because if the system is under memory pressure higher order allocations may become difficult to satisfy. If we can defrag slab caches we can alleviate these problems.
Implement Slab Movable Objects in order to defragment slab caches.
Slab defragmentation may occur:
1. Unconditionally when __kmem_cache_shrink() is called on a slab cache by the kernel calling kmem_cache_shrink().
2. Unconditionally through the use of the slabinfo command.
slabinfo <cache> -s
3. Conditionally via the use of kmem_cache_defrag()
- Use Slab Movable Objects when shrinking cache.
Currently when the kernel calls kmem_cache_shrink() we curate the partial slabs list. If object migration is not enabled for the cache we still do this, if however, SMO is enabled we attempt to move objects in partially full slabs in order to defragment the cache. Shrink attempts to move all objects in order to reduce the cache to a single partial slab for each node.
- Add conditional per node defrag via new function:
kmem_defrag_slabs(int node).
kmem_defrag_slabs() attempts to defragment all slab caches for node. Defragmentation is done conditionally dependent on MAX_PARTIAL _and_ defrag_used_ratio.
Caches are only considered for defragmentation if the number of partial slabs exceeds MAX_PARTIAL (per node).
Also, defragmentation only occurs if the usage ratio of the slab is lower than the configured percentage (sysfs field added in this patch). Fragmentation ratios are measured by calculating the percentage of objects in use compared to the total number of objects that the slab page can accommodate.
The scanning of slab caches is optimized because the defragmentable slabs come first on the list. Thus we can terminate scans on the first slab encountered that does not support defragmentation.
kmem_defrag_slabs() takes a node parameter. This can either be -1 if defragmentation should be performed on all nodes, or a node number.
Defragmentation may be disabled by setting defrag ratio to 0
echo 0 > /sys/kernel/slab/<cache>/defrag_used_ratio
- Add a defrag ratio sysfs field and set it to 30% by default. A limit of 30% specifies that more than 3 out of 10 available slots for objects need to be in use otherwise slab defragmentation will be attempted on the remaining objects.
In order for a cache to be defragmentable the cache must support object migration (SMO). Enabling SMO for a cache is done via a call to the recently added function:
void kmem_cache_setup_mobility(struct kmem_cache *, kmem_cache_isolate_func, kmem_cache_migrate_func);
--- Documentation/ABI/testing/sysfs-kernel-slab | 14 + include/linux/slab.h | 1 + include/linux/slub_def.h | 7 + mm/slub.c | 385 ++++++++++++++++---- 4 files changed, 334 insertions(+), 73 deletions(-)
Documentation/ABI/testing/sysfs-kernel-slab +14 -0
@@ -180,6 +180,20 @@ Description: list. It can be written to clear the current count. Available when CONFIG_SLUB_STATS is enabled. +What: /sys/kernel/slab/cache/defrag_used_ratio +Date: May 2019 +KernelVersion: 5.2 +Contact: Christoph Lameter <[email protected]> + Pekka Enberg <[email protected]>, +Description: + The defrag_used_ratio file allows the control of how aggressive + slab fragmentation reduction works at reclaiming objects from + sparsely populated slabs. This is a percentage. If a slab has + less than this percentage of objects allocated then reclaim will + attempt to reclaim objects so that the whole slab page can be + freed. 0% specifies no reclaim attempt (defrag disabled), 100% + specifies attempt to reclaim all pages. The default is 30%. + What: /sys/kernel/slab/cache/deactivate_to_tail Date: February 2008 KernelVersion: 2.6.25
include/linux/slab.h +1 -0
@@ -149,6 +149,7 @@ struct kmem_cache *kmem_cache_create_usercopy(const char *name, void (*ctor)(void *));void kmem_cache_destroy (struct kmem_cache *);int kmem_cache_shrink (struct kmem_cache *); +unsigned long kmem_defrag_slabs (int node);void memcg_create_kmem_cache (struct mem_cgroup *,struct kmem_cache *);void memcg_deactivate_kmem_caches (struct mem_cgroup *);
include/linux/slub_def.h +7 -0
@@ -107,6 +107,13 @@ struct kmem_cache {unsigned int red_left_pad;/* Left redzone padding size */ const char *name;/* Name (only for display!) */ struct list_head list;/* List of slab caches */ +int defrag_used_ratio;/* +* Ratio used to check against the +* percentage of objects allocated in a +* slab page. If less than this ratio +* is allocated then reclaim attempts +* are made. +*/ #ifdef CONFIG_SYSFS struct kobject kobj;/* For sysfs */ struct work_struct kobj_remove_work;
mm/slub.c +312 -73
421 lines not on this page · raw message
Signature · 1 line
2.21.0
Re: [RFC PATCH v5 04/16] slub: Slab defrag core
Quoted 70 lines · Tobin C. Harding
Internal fragmentation can occur within pages used by the slub allocator. Under some workloads large numbers of pages can be used by partial slab pages. This under-utilisation is bad simply because it wastes memory but also because if the system is under memory pressure higher order allocations may become difficult to satisfy. If we can defrag slab caches we can alleviate these problems.
Implement Slab Movable Objects in order to defragment slab caches.
Slab defragmentation may occur:
1. Unconditionally when
__kmem_cache_shrink()is called on a slab cache by the kernel callingkmem_cache_shrink().2. Unconditionally through the use of the slabinfo command.
slabinfo <cache> -s
3. Conditionally via the use of
kmem_cache_defrag()- Use Slab Movable Objects when shrinking cache.
Currently when the kernel calls
kmem_cache_shrink()we curate the partial slabs list. If object migration is not enabled for the cache we still do this, if however, SMO is enabled we attempt to move objects in partially full slabs in order to defragment the cache. Shrink attempts to move all objects in order to reduce the cache to a single partial slab for each node.- Add conditional per node defrag via new function:
kmem_defrag_slabs(int node).
kmem_defrag_slabs()attempts to defragment all slab caches for node. Defragmentation is done conditionally dependent onMAX_PARTIAL_and_defrag_used_ratio.Caches are only considered for defragmentation if the number of partial slabs exceeds
MAX_PARTIAL(per node).Also, defragmentation only occurs if the usage ratio of the slab is lower than the configured percentage (sysfs field added in this patch). Fragmentation ratios are measured by calculating the percentage of objects in use compared to the total number of objects that the slab page can accommodate.
The scanning of slab caches is optimized because the defragmentable slabs come first on the list. Thus we can terminate scans on the first slab encountered that does not support defragmentation.
kmem_defrag_slabs()takes a node parameter. This can either be -1 if defragmentation should be performed on all nodes, or a node number.Defragmentation may be disabled by setting defrag ratio to 0
echo 0 > /sys/kernel/slab/<cache>/defrag_used_ratio
- Add a defrag ratio sysfs field and set it to 30% by default. A limit of 30% specifies that more than 3 out of 10 available slots for objects need to be in use otherwise slab defragmentation will be attempted on the remaining objects.
In order for a cache to be defragmentable the cache must support object migration (SMO). Enabling SMO for a cache is done via a call to the recently added function:
void kmem_cache_setup_mobility(struct kmem_cache *, kmem_cache_isolate_func, kmem_cache_migrate_func);
Quoted 8 lines
Co-developed-by Christoph Lameter <[email protected]>Signed-off-by Tobin C. Harding <[email protected]>--- Documentation/ABI/testing/sysfs-kernel-slab | 14 + include/linux/slab.h | 1 + include/linux/slub_def.h | 7 + mm/slub.c | 385 ++++++++++++++++---- 4 files changed, 334 insertions(+), 73 deletions(-)
Hi Tobin!
Overall looks very good to me! I'll take another look when you'll post a non-RFC version, but so far I can't find any issues.
A generic question: as I understand, you do support only root kmemcaches now. Is kmemcg support in plans?
Without it the patchset isn't as attractive to anyone using cgroups, as it could be. Also, I hope it can solve (or mitigate) the memcg-specific problem of scattering vfs cache workingset over multiple generations of the same cgroup (their kmem_caches).
Thanks!
Quoted 168 lines
Documentation/ABI/testing/sysfs-kernel-slab +14
-0@@ -180,6 +180,20 @@ Description: list. It can be written to clear the current count. Available when CONFIG_SLUB_STATS is enabled. +What: /sys/kernel/slab/cache/defrag_used_ratio +Date: May 2019 +KernelVersion: 5.2 +Contact: Christoph Lameter <[email protected]> + Pekka Enberg <[email protected]>, +Description: + The defrag_used_ratio file allows the control of how aggressive + slab fragmentation reduction works at reclaiming objects from + sparsely populated slabs. This is a percentage. If a slab has + less than this percentage of objects allocated then reclaim will + attempt to reclaim objects so that the whole slab page can be + freed. 0% specifies no reclaim attempt (defrag disabled), 100% + specifies attempt to reclaim all pages. The default is 30%. + What: /sys/kernel/slab/cache/deactivate_to_tail Date: February 2008 KernelVersion: 2.6.25include/linux/slab.h +1
-0@@ -149,6 +149,7 @@ struct kmem_cache *kmem_cache_create_usercopy(const char *name, void (*ctor)(void *));void kmem_cache_destroy (struct kmem_cache *);int kmem_cache_shrink (struct kmem_cache *); +unsigned long kmem_defrag_slabs (int node);void memcg_create_kmem_cache (struct mem_cgroup *,struct kmem_cache *);void memcg_deactivate_kmem_caches (struct mem_cgroup *);include/linux/slub_def.h +7
-0@@ -107,6 +107,13 @@ struct kmem_cache {unsigned int red_left_pad;/* Left redzone padding size */ const char *name;/* Name (only for display!) */ struct list_head list;/* List of slab caches */ +int defrag_used_ratio;/* +* Ratio used to check against the +* percentage of objects allocated in a +* slab page. If less than this ratio +* is allocated then reclaim attempts +* are made. +*/ #ifdef CONFIG_SYSFS struct kobject kobj;/* For sysfs */ struct work_struct kobj_remove_work;mm/slub.c +10
-73@@ -355,6 +355,12 @@ static __always_inline void slab_lock(struct page *page)bit_spin_lock (PG_locked, &page->flags); } +static __always_inline int slab_trylock(struct page *page) +{ +VM_BUG_ON_PAGE (PageTail (page), page); +return bit_spin_trylock (PG_locked, &page->flags); +} + static __always_inline void slab_unlock(struct page *page) {VM_BUG_ON_PAGE (PageTail (page), page);@@ -3634,6 +3640,7 @@ static int kmem_cache_open(struct kmem_cache *s, slab_flags_t flags)set_cpu_partial (s); + s->defrag_used_ratio =30 ;#ifdef CONFIG_NUMA s->remote_node_defrag_ratio =1000 ;#endif @@ -3950,79 +3957,6 @@ void kfree(const void *x) }EXPORT_SYMBOL (kfree); -#define SHRINK_PROMOTE_MAX 32 - -/* -* kmem_cache_shrink discards empty slabs and promotes the slabs filled -* up most to the head of the partial lists. New allocations will then -* fill those up and thus they can be removed from the partial lists. -* -* The slabs with the least items are placed last. This results in them -* being allocated from last increasing the chance that the last objects -* are freed in them. -*/ -int __kmem_cache_shrink (struct kmem_cache *s) -{ -int node; -int i; -struct kmem_cache_node *n; -struct page *page; -struct page *t; -struct list_head discard; -struct list_head promote[SHRINK_PROMOTE_MAX ]; -unsigned long flags; -int ret =0 ; - -flush_all (s); -for_each_kmem_cache_node (s, node, n) { -INIT_LIST_HEAD (&discard); -for (i =0 ; i <SHRINK_PROMOTE_MAX ; i++) -INIT_LIST_HEAD (promote + i); - -spin_lock_irqsave (&n->list_lock, flags); - -/* -* Build lists of slabs to discard or promote. -* -* Note that concurrent frees may occur while we hold the -* list_lock. page->inuse here is the upper limit. -*/ -list_for_each_entry_safe (page, t, &n->partial, slab_list) { -int free = page->objects - page->inuse; - -/* Do not reread page->inuse */ -barrier (); - -/* We do not keep full slabs on the list */ -BUG_ON (free <=0 ); - -if (free == page->objects) { -list_move (&page->slab_list, &discard); - n->nr_partial--; - }else if (free <=SHRINK_PROMOTE_MAX ) -list_move (&page->slab_list, promote + free -1 ); - } - -/* -* Promote the slabs filled up most to the head of the -* partial list. -*/ -for (i =SHRINK_PROMOTE_MAX -1 ; i >=0 ; i--) -list_splice (promote + i, &n->partial); - -spin_unlock_irqrestore (&n->list_lock, flags); - -/* Release empty slabs */ -list_for_each_entry_safe (page, t, &discard, slab_list) -discard_slab (s, page); - -if (slabs_node (s, node)) - ret =1 ; - } - -return ret; -} -#ifdef CONFIG_MEMCG static void kmemcg_cache_deact_after_rcu (struct kmem_cache *s) {@@ -4317,6 +4251,287 @@ int __kmem_cache_create(struct kmem_cache *s, slab_flags_t flags)return err; } +/* +* Allocate a slab scratch space that is sufficient to keep pointers to +* individual objects for all objects in cache and also a bitmap for the
mm/slub.c int __kmem_cache_create(struct kmem_cache *s, slab_flags_t flags) · line 4266
Quoted 10 lines
mm/slub.c +10
-0+* objects (used to mark which objects are active). +*/ +static inline void *alloc_scratch (struct kmem_cache *s) +{ +unsigned int size =oo_objects (s->max); + +return kmalloc (size *sizeof (void *) + +BITS_TO_LONGS (size) *sizeof (unsigned long ), +GFP_KERNEL ); +}
I'd pass a single number (s->max) instead of s here.
Quoted 312 lines
mm/slub.c +292
-0+ +/* +* move_slab_page() - Move all objects in the given slab. +* @page: The slab we are working on. +* @scratch: Pointer to scratch space. +* @node: The target node to move objects to. +* +* If the target node is not the current node then the object is moved +* to the target node. If the target node is the current node then this +* is an effective way of defragmentation since the current slab page +* with its object is exempt from allocation. +*/ +static void move_slab_page (struct page *page,void *scratch,int node) +{ +unsigned long objects; +struct kmem_cache *s; +unsigned long flags; +unsigned long *map; +void *private; +int count; +void *p; +void **vector = scratch; +void *addr =page_address (page); + +local_irq_save (flags); +slab_lock (page); + +BUG_ON (!PageSlab (page));/* Must be a slab page */ +BUG_ON (!page->frozen);/* Slab must have been frozen earlier */ + + s = page->slab_cache; + objects = page->objects; + map = scratch + objects *sizeof (void **); + +/* Determine used objects */ +bitmap_fill (map, objects); +for (p = page->freelist; p; p =get_freepointer (s, p)) +__clear_bit (slab_index (p, s, addr), map); + +/* Build vector of pointers to objects */ + count =0 ; +memset (vector,0 , objects *sizeof (void **)); +for_each_object (p, s, addr, objects) +if (test_bit (slab_index (p, s, addr), map)) + vector[count++] = p; + +if (s->isolate) + private = s->isolate (s, vector, count); +else +/* Objects do not need to be isolated */ + private =NULL ; + +/* +* Pinned the objects. Now we can drop the slab lock. The slab +* is frozen so it cannot vanish from under us nor will +* allocations be performed on the slab. However, unlocking the +* slab will allow concurrent slab_frees to proceed. So the +* subsystem must have a way to tell from the content of the +* object that it was freed. +* +* If neither RCU nor ctor is being used then the object may be +* modified by the allocator after being freed which may disrupt +* the ability of the migrate function to tell if the object is +* free or not. +*/ +slab_unlock (page); +local_irq_restore (flags); + +/* Perform callback to move the objects */ + s->migrate (s, vector, count, node, private); +} + +/* +* kmem_cache_defrag() - Defragment node. +* @s: cache we are working on. +* @node: The node to move objects from. +* @target_node: The node to move objects to. +* @ratio: The defrag ratio (percentage, between 0 and 100). +* +* Release slabs with zero objects and try to call the migration function +* for slabs with less than the 'ratio' percentage of objects allocated. +* +* Moved objects are allocated on @target_node. +* +* Return: The number of partial slabs left on @node after the +* operation. +*/ +static unsigned long kmem_cache_defrag (struct kmem_cache *s, +int node,int target_node,int ratio) +{ +struct kmem_cache_node *n =get_node (s, node); +struct page *page, *page2; +LIST_HEAD (move_list); +unsigned long flags; + +if (node == target_node && n->nr_partial <=1 ) { +/* +* Trying to reduce fragmentation on a node but there is +* only a single or no partial slab page. This is already +* the optimal object density that we can reach. +*/ +return n->nr_partial; + } + +spin_lock_irqsave (&n->list_lock, flags); +list_for_each_entry_safe (page, page2, &n->partial, lru) { +if (!slab_trylock (page)) +/* Busy slab. Get out of the way */ +continue ; + +if (page->inuse) { +if (page->inuse > ratio * page->objects /100 ) { +slab_unlock (page); +/* +* Skip slab because the object density +* in the slab page is high enough. +*/ +continue ; + } + +list_move (&page->lru, &move_list); +if (s->migrate) { +/* Stop page being considered for allocations */ + n->nr_partial--; + page->frozen =1 ; + } +slab_unlock (page); + }else {/* Empty slab page */ +list_del (&page->lru); + n->nr_partial--; +slab_unlock (page); +discard_slab (s, page); + } + } + +if (!s->migrate) { +/* +* No defrag method. By simply putting the zaplist at +* the end of the partial list we can let them simmer +* longer and thus increase the chance of all objects +* being reclaimed. +*/ +list_splice (&move_list, n->partial.prev); + } + +spin_unlock_irqrestore (&n->list_lock, flags); + +if (s->migrate && !list_empty (&move_list)) { +void **scratch =alloc_scratch (s); +if (scratch) { +/* Try to remove / move the objects left */ +list_for_each_entry (page, &move_list, lru) { +if (page->inuse) +move_slab_page (page, scratch, target_node); + } +kfree (scratch); + } + +/* Inspect results and dispose of pages */ +spin_lock_irqsave (&n->list_lock, flags); +list_for_each_entry_safe (page, page2, &move_list, lru) { +list_del (&page->lru); +slab_lock (page); + page->frozen =0 ; + +if (page->inuse) { +/* +* Objects left in slab page, move it to the +* tail of the partial list to increase the +* chance that the freeing of the remaining +* objects will free the slab page. +*/ + n->nr_partial++; +list_add_tail (&page->lru, &n->partial); +slab_unlock (page); + }else { +slab_unlock (page); +discard_slab (s, page); + } + } +spin_unlock_irqrestore (&n->list_lock, flags); + } + +return n->nr_partial; +} + +/** +* kmem_defrag_slabs() - Defrag slab caches. +* @node: The node to defrag or -1 for all nodes. +* +* Defrag slabs conditional on the amount of fragmentation in a page. +* +* Return: The total number of partial slabs in migratable caches left +* on @node after the operation. +*/ +unsigned long kmem_defrag_slabs (int node) +{ +struct kmem_cache *s; +unsigned long left =0 ; +int nid; + +if (node >=MAX_NUMNODES ) +return -EINVAL ; + +/* +* kmem_defrag_slabs() may be called from the reclaim path which +* may be called for any page allocator alloc. So there is the +* danger that we get called in a situation where slub already +* acquired the slub_lock for other purposes. +*/ +if (!mutex_trylock (&slab_mutex)) +return 0 ; + +list_for_each_entry (s, &slab_caches, list) { +/* +* Defragmentable caches come first. If the slab cache is +* not defragmentable then we can stop traversing the list. +*/ +if (!s->migrate) +break ; + +if (node >=0 ) { +if (s->node[node]->nr_partial >MAX_PARTIAL ) { + left +=kmem_cache_defrag (s, node, node, + s->defrag_used_ratio); + } +continue ; + } + +for_each_node_state (nid,N_NORMAL_MEMORY ) { +if (s->node[nid]->nr_partial >MAX_PARTIAL ) { + left +=kmem_cache_defrag (s, nid, nid, + s->defrag_used_ratio); + } + } + } +mutex_unlock (&slab_mutex); +return left; +} +EXPORT_SYMBOL (kmem_defrag_slabs); + +/** +* __kmem_cache_shrink() - Shrink a cache. +* @s: The cache to shrink. +* +* Reduces the memory footprint of a slab cache by as much as possible. +* +* This works by: +* 1. Removing empty slabs from the partial list. +* 2. Migrating slab objects to denser slab pages if the slab cache +* supports migration. If not, reorganizing the partial list so that +* more densely allocated slab pages come first. +* +* Not called directly, called by kmem_cache_shrink(). +*/ +int __kmem_cache_shrink (struct kmem_cache *s) +{ +int node; +int left =0 ; + +flush_all (s); +for_each_node_state (node,N_NORMAL_MEMORY ) + left +=kmem_cache_defrag (s, node, node,100 ); + +return left; +} +EXPORT_SYMBOL (__kmem_cache_shrink); +void kmem_cache_setup_mobility (struct kmem_cache *s,kmem_cache_isolate_func isolate,kmem_cache_migrate_func migrate)@@ -5168,6 +5383,29 @@ static ssize_t destroy_by_rcu_show(struct kmem_cache *s, char *buf) }SLAB_ATTR_RO (destroy_by_rcu); +static ssize_t defrag_used_ratio_show (struct kmem_cache *s,char *buf) +{ +return sprintf (buf,"%d\n" , s->defrag_used_ratio); +} + +static ssize_t defrag_used_ratio_store (struct kmem_cache *s, +const char *buf,size_t length) +{ +unsigned long ratio; +int err; + + err =kstrtoul (buf,10 , &ratio); +if (err) +return err; + +if (ratio >100 ) +return -EINVAL ; + + s->defrag_used_ratio = ratio; +return length; +} +SLAB_ATTR (defrag_used_ratio); +#ifdef CONFIG_SLUB_DEBUG static ssize_t slabs_show (struct kmem_cache *s,char *buf) {@@ -5492,6 +5730,7 @@ static struct attribute *slab_attrs[] = { &validate_attr.attr, &alloc_calls_attr.attr, &free_calls_attr.attr, + &defrag_used_ratio_attr.attr, #endif #ifdef CONFIG_ZONE_DMA &cache_dma_attr.attr,Signature · 1 line
2.21.0
Re: [RFC PATCH v5 04/16] slub: Slab defrag core
Quoted 80 lines · Roman Gushchin
Quoted 70 lines · Tobin C. Harding
Internal fragmentation can occur within pages used by the slub allocator. Under some workloads large numbers of pages can be used by partial slab pages. This under-utilisation is bad simply because it wastes memory but also because if the system is under memory pressure higher order allocations may become difficult to satisfy. If we can defrag slab caches we can alleviate these problems.
Implement Slab Movable Objects in order to defragment slab caches.
Slab defragmentation may occur:
1. Unconditionally when
__kmem_cache_shrink()is called on a slab cache by the kernel callingkmem_cache_shrink().2. Unconditionally through the use of the slabinfo command.
slabinfo <cache> -s
3. Conditionally via the use of
kmem_cache_defrag()- Use Slab Movable Objects when shrinking cache.
Currently when the kernel calls
kmem_cache_shrink()we curate the partial slabs list. If object migration is not enabled for the cache we still do this, if however, SMO is enabled we attempt to move objects in partially full slabs in order to defragment the cache. Shrink attempts to move all objects in order to reduce the cache to a single partial slab for each node.- Add conditional per node defrag via new function:
kmem_defrag_slabs(int node).
kmem_defrag_slabs()attempts to defragment all slab caches for node. Defragmentation is done conditionally dependent onMAX_PARTIAL_and_defrag_used_ratio.Caches are only considered for defragmentation if the number of partial slabs exceeds
MAX_PARTIAL(per node).Also, defragmentation only occurs if the usage ratio of the slab is lower than the configured percentage (sysfs field added in this patch). Fragmentation ratios are measured by calculating the percentage of objects in use compared to the total number of objects that the slab page can accommodate.
The scanning of slab caches is optimized because the defragmentable slabs come first on the list. Thus we can terminate scans on the first slab encountered that does not support defragmentation.
kmem_defrag_slabs()takes a node parameter. This can either be -1 if defragmentation should be performed on all nodes, or a node number.Defragmentation may be disabled by setting defrag ratio to 0
echo 0 > /sys/kernel/slab/<cache>/defrag_used_ratio
- Add a defrag ratio sysfs field and set it to 30% by default. A limit of 30% specifies that more than 3 out of 10 available slots for objects need to be in use otherwise slab defragmentation will be attempted on the remaining objects.
In order for a cache to be defragmentable the cache must support object migration (SMO). Enabling SMO for a cache is done via a call to the recently added function:
void kmem_cache_setup_mobility(struct kmem_cache *, kmem_cache_isolate_func, kmem_cache_migrate_func);Quoted 8 lines
Co-developed-by Christoph Lameter <[email protected]>Signed-off-by Tobin C. Harding <[email protected]>--- Documentation/ABI/testing/sysfs-kernel-slab | 14 + include/linux/slab.h | 1 + include/linux/slub_def.h | 7 + mm/slub.c | 385 ++++++++++++++++---- 4 files changed, 334 insertions(+), 73 deletions(-)
Quoted 4 lines
Hi Tobin!
Overall looks very good to me! I'll take another look when you'll post a non-RFC version, but so far I can't find any issues.
Thanks for the reviews.
Quoted 2 lines
A generic question: as I understand, you do support only root kmemcaches now. Is kmemcg support in plans?
I know very little about cgroups, I have no plans for this work. However, I'm not the architect behind this - Christoph is guiding the direction on this one. Perhaps he will comment.
Quoted 4 lines
Without it the patchset isn't as attractive to anyone using cgroups, as it could be. Also, I hope it can solve (or mitigate) the memcg-specific problem of scattering vfs cache workingset over multiple generations of the same cgroup (their
kmem_caches).
I'm keen to work on anything that makes this more useful so I'll do some research. Thanks for the idea.
Regards,
Tobin.
Re: [RFC PATCH v5 04/16] slub: Slab defrag core
Quoted 95 lines · Tobin C. Harding
Quoted 80 lines · Roman Gushchin
Quoted 70 lines · Tobin C. Harding
Internal fragmentation can occur within pages used by the slub allocator. Under some workloads large numbers of pages can be used by partial slab pages. This under-utilisation is bad simply because it wastes memory but also because if the system is under memory pressure higher order allocations may become difficult to satisfy. If we can defrag slab caches we can alleviate these problems.
Implement Slab Movable Objects in order to defragment slab caches.
Slab defragmentation may occur:
1. Unconditionally when
__kmem_cache_shrink()is called on a slab cache by the kernel callingkmem_cache_shrink().2. Unconditionally through the use of the slabinfo command.
slabinfo <cache> -s
3. Conditionally via the use of
kmem_cache_defrag()- Use Slab Movable Objects when shrinking cache.
Currently when the kernel calls
kmem_cache_shrink()we curate the partial slabs list. If object migration is not enabled for the cache we still do this, if however, SMO is enabled we attempt to move objects in partially full slabs in order to defragment the cache. Shrink attempts to move all objects in order to reduce the cache to a single partial slab for each node.- Add conditional per node defrag via new function:
kmem_defrag_slabs(int node).
kmem_defrag_slabs()attempts to defragment all slab caches for node. Defragmentation is done conditionally dependent onMAX_PARTIAL_and_defrag_used_ratio.Caches are only considered for defragmentation if the number of partial slabs exceeds
MAX_PARTIAL(per node).Also, defragmentation only occurs if the usage ratio of the slab is lower than the configured percentage (sysfs field added in this patch). Fragmentation ratios are measured by calculating the percentage of objects in use compared to the total number of objects that the slab page can accommodate.
The scanning of slab caches is optimized because the defragmentable slabs come first on the list. Thus we can terminate scans on the first slab encountered that does not support defragmentation.
kmem_defrag_slabs()takes a node parameter. This can either be -1 if defragmentation should be performed on all nodes, or a node number.Defragmentation may be disabled by setting defrag ratio to 0
echo 0 > /sys/kernel/slab/<cache>/defrag_used_ratio
- Add a defrag ratio sysfs field and set it to 30% by default. A limit of 30% specifies that more than 3 out of 10 available slots for objects need to be in use otherwise slab defragmentation will be attempted on the remaining objects.
In order for a cache to be defragmentable the cache must support object migration (SMO). Enabling SMO for a cache is done via a call to the recently added function:
void kmem_cache_setup_mobility(struct kmem_cache *, kmem_cache_isolate_func, kmem_cache_migrate_func);Quoted 8 lines
Co-developed-by Christoph Lameter <[email protected]>Signed-off-by Tobin C. Harding <[email protected]>--- Documentation/ABI/testing/sysfs-kernel-slab | 14 + include/linux/slab.h | 1 + include/linux/slub_def.h | 7 + mm/slub.c | 385 ++++++++++++++++---- 4 files changed, 334 insertions(+), 73 deletions(-)Quoted 4 lines
Hi Tobin!
Overall looks very good to me! I'll take another look when you'll post a non-RFC version, but so far I can't find any issues.
Thanks for the reviews.
Quoted 2 lines
A generic question: as I understand, you do support only root kmemcaches now. Is kmemcg support in plans?
I know very little about cgroups, I have no plans for this work. However, I'm not the architect behind this - Christoph is guiding the direction on this one. Perhaps he will comment.
Quoted 7 lines
Quoted 4 lines
Without it the patchset isn't as attractive to anyone using cgroups, as it could be. Also, I hope it can solve (or mitigate) the memcg-specific problem of scattering vfs cache workingset over multiple generations of the same cgroup (their
kmem_caches).I'm keen to work on anything that makes this more useful so I'll do some research. Thanks for the idea.
You're welcome! I'm happy to help or even to do it by myself, once your patches will be merged.
Thanks!
RFC PATCH v5 5/16 tools/vm/slabinfo: Add remote node defrag ratio output
In reply to Tobin C. HardingAdd output line for NUMA remote node defrag ratio.
--- tools/vm/slabinfo.c | 7 +++++++ 1 file changed, 7 insertions(+)
tools/vm/slabinfo.c +7 -0
@@ -34,6 +34,7 @@ struct slabinfo {unsigned int sanity_checks, slab_size, store_user, trace;int order, poison, reclaim_account, red_zone;int movable, ctor; +int remote_node_defrag_ratio;unsigned long partial, objects, slabs, objects_partial, objects_total;unsigned long alloc_fastpath, alloc_slowpath;unsigned long free_fastpath, free_slowpath;
@@ -377,6 +378,10 @@ static void slab_numa(struct slabinfo *s, int mode)if (skip_zero && !s->slabs)return ; +if (mode) { +printf ("\nNUMA remote node defrag ratio: %3d\n" , + s->remote_node_defrag_ratio); + }if (!line) {printf ("\n%-21s:" , mode ?"NUMA nodes" :"Slab" );for (node =0 ; node <= highest_node; node++)
@@ -1272,6 +1277,8 @@ static void read_slab_dir(void) 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->remote_node_defrag_ratio = +get_obj ("remote_node_defrag_ratio" );chdir (".." );if (read_slab_obj (slab,"ops" )) {if (strstr (buffer,"ctor :" ))
Signature · 1 line
2.21.0
RFC PATCH v5 6/16 tools/vm/slabinfo: Add defrag_used_ratio output
In reply to Tobin C. HardingAdd output for the newly added defrag_used_ratio sysfs knob.
--- tools/vm/slabinfo.c | 4 ++++ 1 file changed, 4 insertions(+)
tools/vm/slabinfo.c +4 -0
@@ -34,6 +34,7 @@ struct slabinfo {unsigned int sanity_checks, slab_size, store_user, trace;int order, poison, reclaim_account, red_zone;int movable, ctor; +int defrag_used_ratio;int remote_node_defrag_ratio;unsigned long partial, objects, slabs, objects_partial, objects_total;unsigned long alloc_fastpath, alloc_slowpath;
@@ -549,6 +550,8 @@ static void report(struct slabinfo *s)printf ("** Slabs are destroyed via RCU\n" );if (s->reclaim_account)printf ("** Reclaim accounting active\n" ); +if (s->movable) +printf ("** Defragmentation at %d%%\n" , s->defrag_used_ratio);printf ("\nSizes (bytes) Slabs Debug Memory\n" );printf ("------------------------------------------------------------------------\n" );
@@ -1279,6 +1282,7 @@ static void read_slab_dir(void) slab->deactivate_bypass =get_obj ("deactivate_bypass" ); slab->remote_node_defrag_ratio =get_obj ("remote_node_defrag_ratio" ); + slab->defrag_used_ratio =get_obj ("defrag_used_ratio" );chdir (".." );if (read_slab_obj (slab,"ops" )) {if (strstr (buffer,"ctor :" ))
Signature · 1 line
2.21.0
RFC PATCH v5 7/16 tools/testing/slab: Add object migration test module
In reply to Tobin C. HardingWe just implemented slab movable objects for the SLUB allocator. We should test that code. In order to do so we need to be able to do a number of things
- Create a cache
- Enable Slab Movable Objects for the cache
- Allocate objects to the cache
- Free objects from within specific slabs of the cache
We can do all this via a loadable module.
Add a module that defines functions that can be triggered from userspace via a debugfs entry. From the source:
/*
* SLUB defragmentation a.k.a. Slab Movable Objects (SMO). *
* This module is used for testing the SLUB allocator. Enables
* userspace to run kernel functions via a debugfs file.
*
* debugfs: /sys/kernel/debugfs/smo/callfn (write only)
*
* String written to callfn is parsed by the module and associated
* function is called. See fn_tab for mapping of strings to functions. */
References to allocated objects are kept by the module in a linked list so that userspace can control which object to free.
We introduce the following four functions via the function table
"enable": Enables object migration for the test cache. "alloc X": Allocates X objects
"free X [Y]": Frees X objects starting at list position Y (default Y==0) "test": Runs [stress] tests from within the module (see below).
{"enable", smo_enable_cache_mobility},
{"alloc", smo_alloc_objects},
{"free", smo_free_object},
{"test", smo_run_module_tests},Freeing from the start of the list creates a hole in the slab being freed from (i.e. creates a partial slab). The results of running these commands can be see using slabinfo (available in tools/vm/):
make -o slabinfo tools/vm/slabinfo.c
Stress tests can be run from within the module. These tests are internal to the module because we verify that object references are still good after object migration. These are called 'stress' tests because it is intended that they create/free a lot of objects. Userspace can control the number of objects to create, default is 1000.
Example test session
--------------------
Relevant /proc/slabinfo column headers:
name <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab>
# mount -t debugfs none /sys/kernel/debug/ $ cd path/to/linux/tools/testing/slab; make ...
# insmod slub_defrag.ko # cat /proc/slabinfo | grep smo_test | sed 's/:.*//' smo_test 0 0 392 20 2
From this we can see that the module created cache 'smo_test' with 20 objects per slab and 2 pages per slab (and cache is currently empty).
We can play with the slab allocator manually:
# insmod slub_defrag.ko # echo 'alloc 21' > callfn # cat /proc/slabinfo | grep smo_test | sed 's/:.*//' smo_test 21 40 392 20 2
We see here that 21 active objects have been allocated creating 2 slabs (40 total objects).
# slabinfo smo_test --report
Slabcache: smo_test Aliases: 0 Order : 1 Objects: 21
Sizes (bytes) Slabs Debug Memory
------------------------------------------------------------------------
Object : 56 Total : 2 Sanity Checks : On Total: 16384 SlabObj: 392 Full : 1 Redzoning : On Used : 1176 SlabSiz: 8192 Partial: 1 Poisoning : On Loss : 15208 Loss : 336 CpuSlab: 0 Tracking : On Lalig: 7056 Align : 8 Objects: 20 Tracing : Off Lpadd: 704
Now free an object from the first slot of the first slab
# echo 'free 1' > callfn # cat /proc/slabinfo | grep smo_test | sed 's/:.*//' smo_test 20 40 392 20 2
# slabinfo smo_test --report
Slabcache: smo_test Aliases: 0 Order : 1 Objects: 20
Sizes (bytes) Slabs Debug Memory
------------------------------------------------------------------------
Object : 56 Total : 2 Sanity Checks : On Total: 16384 SlabObj: 392 Full : 0 Redzoning : On Used : 1120 SlabSiz: 8192 Partial: 2 Poisoning : On Loss : 15264 Loss : 336 CpuSlab: 0 Tracking : On Lalig: 6720 Align : 8 Objects: 20 Tracing : Off Lpadd: 704
Calling shrink now on the cache does nothing because object migration is not enabled (output omitted). If we enable object migration then shrink the cache we expect the object from the second slab to me moved to the first slot in the first slab and the second slab to be removed from the partial list.
# echo 'enable' > callfn # slabinfo smo_test --shrink # slabinfo smo_test --report
Slabcache: smo_test Aliases: 0 Order : 1 Objects: 20
** Defragmentation at 30%
Sizes (bytes) Slabs Debug Memory
------------------------------------------------------------------------
Object : 56 Total : 1 Sanity Checks : On Total: 8192 SlabObj: 392 Full : 1 Redzoning : On Used : 1120 SlabSiz: 8192 Partial: 0 Poisoning : On Loss : 7072 Loss : 336 CpuSlab: 0 Tracking : On Lalig: 6720 Align : 8 Objects: 20 Tracing : Off Lpadd: 352
We can run the stress tests (with the default number of objects):
# cd /sys/kernel/debug/smo # echo 'test' > callfn [ 3.576617] smo: test using nr_objs: 1000 keep: 10 [ 3.580169] smo: Module tests completed successfully
--- tools/testing/slab/Makefile | 10 + tools/testing/slab/slub_defrag.c | 566 +++++++++++++++++++++++++++++++ 2 files changed, 576 insertions(+) create mode 100644 tools/testing/slab/Makefile create mode 100644 tools/testing/slab/slub_defrag.c
tools/testing/slab/Makefile new file +10 -0
@@ -0,0 +1,10 @@ +obj-m += slub_defrag.o + +KTREE=../../.. + +all: + make -C ${KTREE} M=$(PWD) modules + +clean: + make -C ${KTREE} M=$(PWD) clean +
tools/testing/slab/slub_defrag.c new file +566 -0
566 lines not on this page · raw message
Signature · 1 line
2.21.0
RFC PATCH v5 8/16 tools/testing/slab: Add object migration test suite
In reply to Tobin C. HardingWe just added a module that enables testing the SLUB allocators ability to defrag/shrink caches via movable objects. Tests are better when they are automated.
Add automated testing via a python script for SLUB movable objects.
Example output:
$ cd path/to/linux/tools/testing/slab $ /slub_defrag.py Please run script as root
$ sudo ./slub_defrag.py <test are quiet, no output on success>
$ sudo ./slub_defrag.py --debug Loading module ... Slab cache smo_test created Objects per slab: 20 Running sanity checks ...
Running module stress test (see dmesg for additional test output) ... Removing module slub_defrag ...
Loading module ...
Slab cache smo_test created
Running test non-movable ...
testing slab 'smo_test' prior to enabling movable objects ... verified non-movable slabs are NOT shrinkable
Running test movable ...
testing slab 'smo_test' after enabling movable objects ... verified movable slabs are shrinkable
Removing module slub_defrag ...
--- tools/testing/slab/slub_defrag.c | 1 + tools/testing/slab/slub_defrag.py | 451 ++++++++++++++++++++++++++++++ 2 files changed, 452 insertions(+) create mode 100755 tools/testing/slab/slub_defrag.py
tools/testing/slab/slub_defrag.c +1 -0
@@ -337,6 +337,7 @@ static int smo_run_module_tests(int nr_objs, int keep)/* * struct functions() - Map command to a function pointer. +* If you update this please update the documentation in slub_defrag.py */ struct functions {char *fn_name;
tools/testing/slab/slub_defrag.py new file +451 -0
451 lines not on this page · raw message
Signature · 1 line
2.21.0
RFC PATCH v5 9/16 lib: Separate radix_tree_node and xa_node slab cache
In reply to Tobin C. HardingEarlier, Slab Movable Objects (SMO) was implemented. The XArray is now able to take advantage of SMO in order to make xarray nodes movable (when using the SLUB allocator).
Currently the radix tree uses the same slab cache as the XArray. Only XArray nodes are movable _not_ radix tree nodes. We can give the radix tree its own slab cache to overcome this.
In preparation for implementing XArray object migration (xa_node objects) via Slab Movable Objects add a slab cache solely for XArray nodes and make the XArray use this slab cache instead of the radix_tree_node slab cache.
--- include/linux/xarray.h | 3 +++ init/main.c | 2 ++ lib/radix-tree.c | 2 +- lib/xarray.c | 48 ++++++++++++++++++++++++++++++++++-------- 4 files changed, 45 insertions(+), 10 deletions(-)
include/linux/xarray.h +3 -0
@@ -42,6 +42,9 @@#define BITS_PER_XA_VALUE (BITS_PER_LONG - 1) +/* Called from init/main.c */ +void xarray_slabcache_init (void ); +/** * xa_mk_value() - Create an XArray entry from an integer. * @v: Value to store in XArray.
init/main.c +2 -0
@@ -106,6 +106,7 @@ static int kernel_init(void *);extern void init_IRQ (void );extern void radix_tree_init (void ); +extern void xarray_slabcache_init (void );/* * Debug helper: via this flag we know that we are in 'early bootup code'
@@ -621,6 +622,7 @@ asmlinkage __visible void __init start_kernel(void) "Interrupts were enabled *very* early, fixing it\n"))local_irq_disable ();radix_tree_init (); +xarray_slabcache_init ();/* * Set up housekeeping before setting up workqueues to allow the unbound
lib/radix-tree.c +1 -1
@@ -44,7 +44,7 @@/* * Radix tree node cache. */ -struct kmem_cache *radix_tree_node_cachep; +static struct kmem_cache *radix_tree_node_cachep;/* * The radix tree is variable-height, so an insert operation not only has
lib/xarray.c +39 -9
98 lines not on this page · raw message
Signature · 1 line
2.21.0
RFC PATCH v5 10/16 xarray: Implement migration function for xa_node objects
In reply to Tobin C. HardingRecently Slab Movable Objects (SMO) was implemented for the SLUB allocator. The XArray can take advantage of this and make the xa_node slab cache objects movable.
Implement functions to migrate objects and activate SMO when we initialise the XArray slab cache.
This is based on initial code by Matthew Wilcox and was modified to work with slab object migration.
--- lib/xarray.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+)
lib/xarray.c +61 -0
@@ -1993,12 +1993,73 @@ static void xa_node_ctor(void *arg)INIT_LIST_HEAD (&node->private_list); } +static void xa_object_migrate (struct xa_node *node,int numa_node) +{ +struct xarray *xa =READ_ONCE (node->array); +void __rcu **slot; +struct xa_node *new_node; +int i; + +/* Freed or not yet in tree then skip */ +if (!xa || xa ==XA_RCU_FREE ) +return ; + + new_node =kmem_cache_alloc_node (xa_node_cachep,GFP_KERNEL , numa_node); +if (!new_node) { +pr_err ("%s: slab cache allocation failed\n" , __func__); +return ; + } + +xa_lock_irq (xa); + +/* Check again..... */ +if (xa != node->array) { + node = new_node; + goto unlock; + } + +memcpy (new_node, node,sizeof (struct xa_node )); + +if (list_empty (&node->private_list)) +INIT_LIST_HEAD (&new_node->private_list); +else +list_replace (&node->private_list, &new_node->private_list); + +for (i =0 ; i <XA_CHUNK_SIZE ; i++) { +void *x =xa_entry_locked (xa, new_node, i); + +if (xa_is_node (x)) +rcu_assign_pointer (xa_to_node (x)->parent, new_node); + } +if (!new_node->parent) + slot = &xa->xa_head; +else + slot = &xa_parent_locked (xa, new_node)->slots[new_node->offset]; +rcu_assign_pointer (*slot,xa_mk_node (new_node)); + +unlock: +xa_unlock_irq (xa); +xa_node_free (node); +rcu_barrier (); +} + +static void xa_migrate (struct kmem_cache *s,void **objects,int nr, +int node,void *_unused) +{ +int i; + +for (i =0 ; i < nr; i++) +xa_object_migrate (objects[i], node); +} + +void __init xarray_slabcache_init (void ) { xa_node_cachep =kmem_cache_create ("xarray_node" ,sizeof (struct xa_node ),0 ,SLAB_PANIC |SLAB_RECLAIM_ACCOUNT , xa_node_ctor); +kmem_cache_setup_mobility (xa_node_cachep,NULL , xa_migrate); }#ifdef XA_DEBUG
Signature · 1 line
2.21.0
RFC PATCH v5 11/16 tools/testing/slab: Add XArray movable objects tests
In reply to Tobin C. HardingWe just implemented movable objects for the XArray. Let's test it intree.
Add test module for the XArray's movable objects implementation.
Functionality of the XArray Slab Movable Object implementation can usually be seen by simply by using slabinfo on a running machine since the radix tree is typically in use on a running machine and will have partial slabs. For repeated testing we can use the test module to run to simulate a workload on the XArray then use slabinfo to test object migration is functioning.
If testing on freshly spun up VM (low radix tree workload) it may be necessary to load/unload the module a number of times to create partial slabs.
Example test session
--------------------
Relevant /proc/slabinfo column headers:
name <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab>
Prior to testing slabinfo report for radix_tree_node:
# slabinfo radix_tree_node --report
Slabcache: radix_tree_node Aliases: 0 Order : 2 Objects: 8352 ** Reclaim accounting active
** Defragmentation at 30%
Sizes (bytes) Slabs Debug Memory
------------------------------------------------------------------------
Object : 576 Total : 497 Sanity Checks : On Total: 8142848 SlabObj: 912 Full : 473 Redzoning : On Used : 4810752 SlabSiz: 16384 Partial: 24 Poisoning : On Loss : 3332096 Loss : 336 CpuSlab: 0 Tracking : On Lalig: 2806272 Align : 8 Objects: 17 Tracing : Off Lpadd: 437360
Here you can see the kernel was built with Slab Movable Objects enabled for the XArray (XArray uses the radix tree below the surface).
After inserting the test module (note we have triggered allocation of a number of radix tree nodes increasing the object count but decreasing the number of partial slabs):
# slabinfo radix_tree_node --report
Slabcache: radix_tree_node Aliases: 0 Order : 2 Objects: 8442 ** Reclaim accounting active
** Defragmentation at 30%
Sizes (bytes) Slabs Debug Memory
------------------------------------------------------------------------
Object : 576 Total : 499 Sanity Checks : On Total: 8175616 SlabObj: 912 Full : 484 Redzoning : On Used : 4862592 SlabSiz: 16384 Partial: 15 Poisoning : On Loss : 3313024 Loss : 336 CpuSlab: 0 Tracking : On Lalig: 2836512 Align : 8 Objects: 17 Tracing : Off Lpadd: 439120
Now we can shrink the radix_tree_node cache:
# slabinfo radix_tree_node --shrink # slabinfo radix_tree_node --report
Slabcache: radix_tree_node Aliases: 0 Order : 2 Objects: 8515 ** Reclaim accounting active
** Defragmentation at 30%
Sizes (bytes) Slabs Debug Memory
------------------------------------------------------------------------
Object : 576 Total : 501 Sanity Checks : On Total: 8208384 SlabObj: 912 Full : 500 Redzoning : On Used : 4904640 SlabSiz: 16384 Partial: 1 Poisoning : On Loss : 3303744 Loss : 336 CpuSlab: 0 Tracking : On Lalig: 2861040 Align : 8 Objects: 17 Tracing : Off Lpadd: 440880
Note the single remaining partial slab.
--- tools/testing/slab/Makefile | 2 +- tools/testing/slab/slub_defrag_xarray.c | 211 ++++++++++++++++++++++++ 2 files changed, 212 insertions(+), 1 deletion(-) create mode 100644 tools/testing/slab/slub_defrag_xarray.c
tools/testing/slab/Makefile +1 -1
@@ -1,4 +1,4 @@ -obj-m += slub_defrag.o +obj-m += slub_defrag.o slub_defrag_xarray.o KTREE=../../..
tools/testing/slab/slub_defrag_xarray.c new file +211 -0
211 lines not on this page · raw message
Signature · 1 line
2.21.0
RFC PATCH v5 12/16 slub: Enable moving objects to/from specific nodes
In reply to Tobin C. HardingWe have just implemented Slab Movable Objects (object migration). Currently object migration is used to defrag a cache. On NUMA systems it would be nice to be able to control the source and destination nodes when moving objects.
Add CONFIG_SMO_NODE to guard this feature. CONFIG_SMO_NODE depends on CONFIG_SLUB_DEBUG because we use the full list.
Implement moving all objects (including those in full slabs) to a specific node. Expose this functionality to userspace via a sysfs entry.
Add sysfs entry:
/sysfs/kernel/slab/<cache>/move
With this users get access to the following functionality:
- Move all objects to specified node.
echo "N1" > move
- Move all objects from specified node to other specified node (from N1 -> to N2):
echo "N1 N2" > move
This also enables shrinking slabs on a specific node:
echo "N1 N1" > move
--- mm/Kconfig | 7 ++ mm/slub.c | 249 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 256 insertions(+)
mm/Kconfig +7 -0
@@ -258,6 +258,13 @@ config ARCH_ENABLE_THP_MIGRATION config CONTIG_ALLOC def_bool (MEMORY_ISOLATION && COMPACTION) || CMA +config SMO_NODE + bool "Enable per node control of Slab Movable Objects" + depends on SLUB && SYSFS + select SLUB_DEBUG + help + On NUMA systems enable moving objects to and from a specified node. + config PHYS_ADDR_T_64BIT def_bool 64BIT
mm/slub.c +249 -0
273 lines not on this page · raw message
Signature · 1 line
2.21.0
RFC PATCH v5 13/16 slub: Enable balancing slabs across nodes
In reply to Tobin C. HardingWe have just implemented Slab Movable Objects (SMO). On NUMA systems slabs can become unbalanced i.e. many slabs on one node while other nodes have few slabs. Using SMO we can balance the slabs across all the nodes.
The algorithm used is as follows:
1. Move all objects to node 0 (this has the effect of defragmenting the
cache).
2. Calculate the desired number of slabs for each node (this is done using the approximation nr_slabs / nr_nodes).
3. Loop over the nodes moving the desired number of slabs from node 0 to the node.
Feature is conditionally built in with CONFIG_SMO_NODE, this is because we need the full list (we enable SLUB_DEBUG to get this). Future version may separate final list out of SLUB_DEBUG.
Expose this functionality to userspace via a sysfs entry. Add sysfs entry:
/sysfs/kernel/slab/<cache>/balance
Write of '1' to this file triggers balance, no other value accepted.
This feature relies on SMO being enable for the cache, this is done with a call to, after the isolate/migrate functions have been defined.
kmem_cache_setup_mobility(s, isolate, migrate)
--- mm/slub.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+)
mm/slub.c +120 -0
@@ -4574,6 +4574,109 @@ static unsigned long kmem_cache_move_to_node(struct kmem_cache *s, int node) return left; } + +/* +* kmem_cache_move_slabs() - Attempt to move @num slabs to target_node, +* @s: The cache we are working on. +* @node: The node to move objects from. +* @target_node: The node to move objects to. +* @num: The number of slabs to move. +* +* Attempts to move @num slabs from @node to @target_node. This is done +* by migrating objects from slabs on the full_list. +* +* Return: The number of slabs moved or error code. +*/ +static long kmem_cache_move_slabs (struct kmem_cache *s, +int node,int target_node,long num) +{ +struct kmem_cache_node *n =get_node (s, node); +LIST_HEAD (move_list); +struct page *page, *page2; +unsigned long flags; +void **scratch; +long done =0 ; + +if (node == target_node) +return -EINVAL ; + + scratch =alloc_scratch (s); +if (!scratch) +return -ENOMEM ; + +spin_lock_irqsave (&n->list_lock, flags); +list_for_each_entry_safe (page, page2, &n->full, lru) { +if (!slab_trylock (page)) +/* Busy slab. Get out of the way */ +continue ; + +list_move (&page->lru, &move_list); + page->frozen =1 ; +slab_unlock (page); + +if (++done >= num) +break ; + } +spin_unlock_irqrestore (&n->list_lock, flags); + +list_for_each_entry (page, &move_list, lru) { +if (page->inuse) +move_slab_page (page, scratch, target_node); + } +kfree (scratch); + +/* Inspect results and dispose of pages */ +spin_lock_irqsave (&n->list_lock, flags); +list_for_each_entry_safe (page, page2, &move_list, lru) { +list_del (&page->lru); +slab_lock (page); + page->frozen =0 ; + +if (page->inuse) { +/* +* This is best effort only, if slab still has +* objects just put it back on the partial list. +*/ + n->nr_partial++; +list_add_tail (&page->lru, &n->partial); +slab_unlock (page); + }else { +slab_unlock (page); +discard_slab (s, page); + } + } +spin_unlock_irqrestore (&n->list_lock, flags); + +return done; +} + +/* +* kmem_cache_balance_nodes() - Balance slabs across nodes. +* @s: The cache we are working on. +*/ +static void kmem_cache_balance_nodes (struct kmem_cache *s) +{ +struct kmem_cache_node *n =get_node (s,0 ); +unsigned long desired_nr_slabs_per_node; +unsigned long nr_slabs; +int nr_nodes =0 ; +int nid; + + (void )kmem_cache_move_to_node (s,0 ); + +for_each_node_state (nid,N_NORMAL_MEMORY ) + nr_nodes++; + + nr_slabs =atomic_long_read (&n->nr_slabs); + desired_nr_slabs_per_node = nr_slabs / nr_nodes; + +for_each_node_state (nid,N_NORMAL_MEMORY ) { +if (nid ==0 ) +continue ; + +kmem_cache_move_slabs (s,0 , nid, desired_nr_slabs_per_node); + } +}#endif /**
@@ -5838,6 +5941,22 @@ static ssize_t move_store(struct kmem_cache *s, const char *buf, size_t length) return length; }SLAB_ATTR (move); + +static ssize_t balance_show (struct kmem_cache *s,char *buf) +{ +return 0 ; +} + +static ssize_t balance_store (struct kmem_cache *s, +const char *buf,size_t length) +{ +if (buf[0 ] =='1' ) +kmem_cache_balance_nodes (s); +else +return -EINVAL ; +return length; +} +SLAB_ATTR (balance);#endif /* CONFIG_SMO_NODE */ #ifdef CONFIG_NUMA
@@ -5966,6 +6085,7 @@ static struct attribute *slab_attrs[] = { &shrink_attr.attr, #ifdef CONFIG_SMO_NODE &move_attr.attr, + &balance_attr.attr, #endif &slabs_cpu_partial_attr.attr, #ifdef CONFIG_SLUB_DEBUG
Signature · 1 line
2.21.0
Re: [RFC PATCH v5 13/16] slub: Enable balancing slabs across nodes
Quoted 9 lines · Tobin C. Harding
We have just implemented Slab Movable Objects (SMO). On NUMA systems slabs can become unbalanced i.e. many slabs on one node while other nodes have few slabs. Using SMO we can balance the slabs across all the nodes.
The algorithm used is as follows:
1. Move all objects to node 0 (this has the effect of defragmenting the
cache).
This already sounds dangerous (or costly). Can't it be done without cross-node data moves?
Quoted 3 lines
2. Calculate the desired number of slabs for each node (this is done using the approximation
nr_slabs/nr_nodes).
So that on this step only (actual data size - desired data size) has to be moved?
Thanks!
Re: [RFC PATCH v5 13/16] slub: Enable balancing slabs across nodes
Quoted 15 lines · Roman Gushchin
Quoted 9 lines · Tobin C. Harding
We have just implemented Slab Movable Objects (SMO). On NUMA systems slabs can become unbalanced i.e. many slabs on one node while other nodes have few slabs. Using SMO we can balance the slabs across all the nodes.
The algorithm used is as follows:
1. Move all objects to node 0 (this has the effect of defragmenting the
cache).This already sounds dangerous (or costly). Can't it be done without cross-node data moves?
Quoted 1 line
Quoted 5 lines
Quoted 2 lines
2. Calculate the desired number of slabs for each node (this is done using the approximation
nr_slabs/nr_nodes).So that on this step only (actual data size - desired data size) has to be moved?
This is just the most braindead algorithm I could come up with. Surely there are a bunch of things that could be improved. Since I don't know the exact use case it seemed best not to optimize for any one use case.
I'll review, comment on, and test any algorithm you come up with!
thanks,
Tobin.
RFC PATCH v5 14/16 dcache: Provide a dentry constructor
In reply to Tobin C. HardingIn order to support object migration on the dentry cache we need to have a determined object state at all times. Without a constructor the object would have a random state after allocation.
Provide a dentry constructor.
--- fs/dcache.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-)
fs/dcache.c +21 -9
@@ -1602,6 +1602,16 @@ void d_invalidate(struct dentry *dentry) }EXPORT_SYMBOL (d_invalidate); +static void dcache_ctor (void *p) +{ +struct dentry *dentry = p; + +/* Mimic lockref_mark_dead() */ + dentry->d_lockref.count =-128 ; + +spin_lock_init (&dentry->d_lock); +} +/** * __d_alloc - allocate a dcache entry * @sb: filesystem it will belong to
@@ -1657,7 +1667,6 @@ struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name) dentry->d_lockref.count =1 ; dentry->d_flags =0 ; -spin_lock_init (&dentry->d_lock);seqcount_init (&dentry->d_seq); dentry->d_inode =NULL ; dentry->d_parent = dentry;
@@ -3095,14 +3104,17 @@ static void __init dcache_init_early(void)static void __init dcache_init (void ) { -/* -* A constructor could be added for stable state like the lists, -* but it is probably not worth it because of the cache nature -* of the dcache. -*/ - dentry_cache =KMEM_CACHE_USERCOPY (dentry, -SLAB_RECLAIM_ACCOUNT |SLAB_PANIC |SLAB_MEM_SPREAD |SLAB_ACCOUNT , - d_iname); +slab_flags_t flags = +SLAB_RECLAIM_ACCOUNT |SLAB_PANIC |SLAB_MEM_SPREAD |SLAB_ACCOUNT ; + + dentry_cache = +kmem_cache_create_usercopy ("dentry" , +sizeof (struct dentry ), + __alignof__(struct dentry ), + flags, + offsetof(struct dentry , d_iname), + sizeof_field(struct dentry, d_iname), + dcache_ctor);/* Hash may have been set up in dcache_init_early */ if (!hashdist)
Signature · 1 line
2.21.0
RFC PATCH v5 15/16 dcache: Implement partial shrink via Slab Movable Objects
In reply to Tobin C. HardingThe dentry slab cache is susceptible to internal fragmentation. Now that we have Slab Movable Objects we can attempt to defragment the dcache. Dentry objects are inherently _not_ relocatable however under some conditions they can be free'd. This is the same as shrinking the dcache but instead of shrinking the whole cache we only attempt to free those objects that are located in partially full slab pages. There is no guarantee that this will reduce the memory usage of the system, it is a compromise between fragmented memory and total cache shrinkage with the hope that some memory pressure can be alleviated.
This is implemented using the newly added Slab Movable Objects infrastructure. The dcache 'migration' function is intentionally _not_ called 'd_migrate' because we only free, we do not migrate. Call it 'd_partial_shrink' to make explicit that no reallocation is done.
Implement isolate and 'migrate' functions for the dentry slab cache.
--- fs/dcache.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+)
fs/dcache.c +76 -0
@@ -31,6 +31,7 @@#include <linux/bit_spinlock.h> #include <linux/rculist_bl.h> #include <linux/list_lru.h> +#include <linux/backing-dev.h> #include "internal.h" #include "mount.h"
@@ -3071,6 +3072,79 @@ void d_tmpfile(struct dentry *dentry, struct inode *inode) }EXPORT_SYMBOL (d_tmpfile); +/* +* d_isolate() - Dentry isolation callback function. +* @s: The dentry cache. +* @v: Vector of pointers to the objects to isolate. +* @nr: Number of objects in @v. +* +* The slab allocator is holding off frees. We can safely examine +* the object without the danger of it vanishing from under us. +*/ +static void *d_isolate (struct kmem_cache *s,void **v,int nr) +{ +struct list_head *dispose; +struct dentry *dentry; +int i; + + dispose =kmalloc (sizeof (*dispose),GFP_KERNEL ); +if (!dispose) +return NULL ; + +INIT_LIST_HEAD (dispose); + +for (i =0 ; i < nr; i++) { + dentry = v[i]; +spin_lock (&dentry->d_lock); + +if (dentry->d_lockref.count >0 || + dentry->d_flags &DCACHE_SHRINK_LIST ) { +spin_unlock (&dentry->d_lock); +continue ; + } + +if (dentry->d_flags &DCACHE_LRU_LIST ) +d_lru_del (dentry); + +d_shrink_add (dentry, dispose); +spin_unlock (&dentry->d_lock); + } + +return dispose; +} + +/* +* d_partial_shrink() - Dentry migration callback function. +* @s: The dentry cache. +* @_unused: We do not access the vector. +* @__unused: No need for length of vector. +* @___unused: We do not do any allocation. +* @private: list_head pointer representing the shrink list. +* +* Dispose of the shrink list created during isolation function. +* +* Dentry objects can _not_ be relocated and shrinking the whole dcache +* can be expensive. This is an effort to free dentry objects that are +* stopping slab pages from being free'd without clearing the whole dcache. +* +* This callback is called from the SLUB allocator object migration +* infrastructure in attempt to free up slab pages by freeing dentry +* objects from partially full slabs. +*/ +static void d_partial_shrink (struct kmem_cache *s,void **_unused,int __unused, +int ___unused,void *private) +{ +struct list_head *dispose = private; + +if (!private)/* kmalloc error during isolate. */ +return ; + +if (!list_empty (dispose)) +shrink_dentry_list (dispose); + +kfree (private); +} +static __initdata unsigned long dhash_entries;static int __init set_dhash_entries (char *str) {
@@ -3116,6 +3190,8 @@ static void __init dcache_init(void) sizeof_field(struct dentry, d_iname), dcache_ctor); +kmem_cache_setup_mobility (dentry_cache, d_isolate, d_partial_shrink); +/* Hash may have been set up in dcache_init_early */ if (!hashdist)return ;
Signature · 1 line
2.21.0
RFC PATCH v5 16/16 dcache: Add CONFIG_DCACHE_SMO
In reply to Tobin C. HardingIn an attempt to make the SMO patchset as non-invasive as possible add a config option CONFIG_DCACHE_SMO (under "Memory Management options") for enabling SMO for the DCACHE. Whithout this option dcache constructor is used but no other code is built in, with this option enabled slab mobility is enabled and the isolate/migrate functions are built in.
Add CONFIG_DCACHE_SMO to guard the partial shrinking of the dcache via Slab Movable Objects infrastructure.
--- fs/dcache.c | 4 ++++ mm/Kconfig | 7 +++++++ 2 files changed, 11 insertions(+)
fs/dcache.c +4 -0
@@ -3072,6 +3072,7 @@ void d_tmpfile(struct dentry *dentry, struct inode *inode) }EXPORT_SYMBOL (d_tmpfile); +#ifdef CONFIG_DCACHE_SMO /* * d_isolate() - Dentry isolation callback function. * @s: The dentry cache.
@@ -3144,6 +3145,7 @@ static void d_partial_shrink(struct kmem_cache *s, void **_unused, int __unused, kfree(private); } +#endif /* CONFIG_DCACHE_SMO */ static __initdata unsigned long dhash_entries;static int __init set_dhash_entries (char *str)
@@ -3190,7 +3192,9 @@ static void __init dcache_init(void) sizeof_field(struct dentry, d_iname), dcache_ctor); +#ifdef CONFIG_DCACHE_SMO kmem_cache_setup_mobility (dentry_cache, d_isolate, d_partial_shrink); +#endif /* Hash may have been set up in dcache_init_early */ if (!hashdist)
mm/Kconfig +7 -0
@@ -265,6 +265,13 @@ config SMO_NODE help On NUMA systems enable moving objects to and from a specified node. +config DCACHE_SMO + bool "Enable Slab Movable Objects for the dcache" + depends on SLUB + help + Under memory pressure we can try to free dentry slab cache objects from + the partial slab list if this is enabled. + config PHYS_ADDR_T_64BIT def_bool 64BIT
Signature · 1 line
2.21.0
Re: [RFC PATCH v5 16/16] dcache: Add CONFIG_DCACHE_SMO
Quoted 8 lines · Tobin C. Harding
In an attempt to make the SMO patchset as non-invasive as possible add a config option
CONFIG_DCACHE_SMO(under "Memory Management options") for enabling SMO for the DCACHE. Whithout this option dcache constructor is used but no other code is built in, with this option enabled slab mobility is enabled and the isolate/migrate functions are built in.Add
CONFIG_DCACHE_SMOto guard the partial shrinking of the dcache via Slab Movable Objects infrastructure.
Hm, isn't it better to make it a static branch? Or basically anything that allows switching on the fly?
It seems that the cost of just building it in shouldn't be that high. And the question if the defragmentation worth the trouble is so much easier to answer if it's possible to turn it on and off without rebooting.
Thanks!
Quoted 58 lines
Signed-off-by Tobin C. Harding <[email protected]>--- fs/dcache.c | 4 ++++ mm/Kconfig | 7 +++++++ 2 files changed, 11 insertions(+)fs/dcache.c +4
-0@@ -3072,6 +3072,7 @@ void d_tmpfile(struct dentry *dentry, struct inode *inode) }EXPORT_SYMBOL (d_tmpfile); +#ifdef CONFIG_DCACHE_SMO /* * d_isolate() - Dentry isolation callback function. * @s: The dentry cache. @@ -3144,6 +3145,7 @@ static void d_partial_shrink(struct kmem_cache *s, void **_unused, int __unused, kfree(private); } +#endif /* CONFIG_DCACHE_SMO */ static __initdata unsigned long dhash_entries;static int __init set_dhash_entries (char *str)@@ -3190,7 +3192,9 @@ static void __init dcache_init(void) sizeof_field(struct dentry, d_iname), dcache_ctor); +#ifdef CONFIG_DCACHE_SMO kmem_cache_setup_mobility (dentry_cache, d_isolate, d_partial_shrink); +#endif /* Hash may have been set up in dcache_init_early */ if (!hashdist)mm/Kconfig +7
-0@@ -265,6 +265,13 @@ config SMO_NODE help On NUMA systems enable moving objects to and from a specified node. +config DCACHE_SMO + bool "Enable Slab Movable Objects for the dcache" + depends on SLUB + help + Under memory pressure we can try to free dentry slab cache objects from + the partial slab list if this is enabled. + config PHYS_ADDR_T_64BIT def_bool 64BITSignature · 1 line
2.21.0
Re: [RFC PATCH v5 16/16] dcache: Add CONFIG_DCACHE_SMO
Quoted 7 lines · Roman Gushchin
Quoted 6 lines · Tobin C. Harding
In an attempt to make the SMO patchset as non-invasive as possible add a config option
CONFIG_DCACHE_SMO(under "Memory Management options") for enabling SMO for the DCACHE. Whithout this option dcache constructor is used but no other code is built in, with this option enabled slab mobility is enabled and the isolate/migrate functions are built in.
Quoted 5 lines
Quoted 2 lines
Add
CONFIG_DCACHE_SMOto guard the partial shrinking of the dcache via Slab Movable Objects infrastructure.Hm, isn't it better to make it a static branch? Or basically anything that allows switching on the fly?
If that is wanted, turning SMO on and off per cache, we can probably do this in the SMO code in SLUB.
Quoted 3 lines
It seems that the cost of just building it in shouldn't be that high. And the question if the defragmentation worth the trouble is so much easier to answer if it's possible to turn it on and off without rebooting.
If the question is 'is defragmentation worth the trouble for the dcache', I'm not sure having SMO turned off helps answer that question. If one doesn't shrink the dentry cache there should be very little overhead in having SMO enabled. So if one wants to explore this question then they can turn on the config option. Please correct me if I'm wrong.
The ifdef guard is there so memory management is not having any negative effects on the dcache/VFS (no matter how small). It also means that the VFS guys don't have to keep an eye on what SMO is doing, they can just configure SMO out. The dcache is already fairly complex, I'm not sure adding complexity to it without good reason is sound practice. At best SMO is only going to by mildly useful to the dcache so I feel we should err on the side of caution.
Open to ideas.
Thanks,
Tobin.
Re: [RFC PATCH v5 16/16] dcache: Add CONFIG_DCACHE_SMO
Quoted 8 lines · Tobin C. Harding
Quoted 7 lines · Roman Gushchin
Quoted 6 lines · Tobin C. Harding
In an attempt to make the SMO patchset as non-invasive as possible add a config option
CONFIG_DCACHE_SMO(under "Memory Management options") for enabling SMO for the DCACHE. Whithout this option dcache constructor is used but no other code is built in, with this option enabled slab mobility is enabled and the isolate/migrate functions are built in.
Quoted 8 lines
Quoted 5 lines
Quoted 2 lines
Add
CONFIG_DCACHE_SMOto guard the partial shrinking of the dcache via Slab Movable Objects infrastructure.Hm, isn't it better to make it a static branch? Or basically anything that allows switching on the fly?
If that is wanted, turning SMO on and off per cache, we can probably do this in the SMO code in SLUB.
Not necessarily per cache, but without recompiling the kernel.
Quoted 11 lines
Quoted 4 lines
It seems that the cost of just building it in shouldn't be that high. And the question if the defragmentation worth the trouble is so much easier to answer if it's possible to turn it on and off without rebooting.
If the question is 'is defragmentation worth the trouble for the dcache', I'm not sure having SMO turned off helps answer that question. If one doesn't shrink the dentry cache there should be very little overhead in having SMO enabled. So if one wants to explore this question then they can turn on the config option. Please correct me if I'm wrong.
The problem with a config option is that it's hard to switch over.
So just to test your changes in production a new kernel should be built, tested and rolled out to a representative set of machines (which can be measured in thousands of machines). Then if results are questionable, it should be rolled back.
What you're actually guarding is the kmem_cache_setup_mobility() call, which can be perfectly avoided using a boot option, for example. Turning it on and off completely dynamic isn't that hard too.
Of course, it's up to you, it's just probably easier to find new users of a new feature, when it's easy to test it.
Thanks!
Re: [RFC PATCH v5 16/16] dcache: Add CONFIG_DCACHE_SMO
Quoted 38 lines · Roman Gushchin
Quoted 8 lines · Tobin C. Harding
Quoted 7 lines · Roman Gushchin
Quoted 6 lines · Tobin C. Harding
In an attempt to make the SMO patchset as non-invasive as possible add a config option
CONFIG_DCACHE_SMO(under "Memory Management options") for enabling SMO for the DCACHE. Whithout this option dcache constructor is used but no other code is built in, with this option enabled slab mobility is enabled and the isolate/migrate functions are built in.Quoted 8 lines
Quoted 5 lines
Quoted 2 lines
Add
CONFIG_DCACHE_SMOto guard the partial shrinking of the dcache via Slab Movable Objects infrastructure.Hm, isn't it better to make it a static branch? Or basically anything that allows switching on the fly?
If that is wanted, turning SMO on and off per cache, we can probably do this in the SMO code in SLUB.
Not necessarily per cache, but without recompiling the kernel.
Quoted 11 lines
Quoted 4 lines
It seems that the cost of just building it in shouldn't be that high. And the question if the defragmentation worth the trouble is so much easier to answer if it's possible to turn it on and off without rebooting.
If the question is 'is defragmentation worth the trouble for the dcache', I'm not sure having SMO turned off helps answer that question. If one doesn't shrink the dentry cache there should be very little overhead in having SMO enabled. So if one wants to explore this question then they can turn on the config option. Please correct me if I'm wrong.
The problem with a config option is that it's hard to switch over.
So just to test your changes in production a new kernel should be built, tested and rolled out to a representative set of machines (which can be measured in thousands of machines). Then if results are questionable, it should be rolled back.
Quoted 6 lines
What you're actually guarding is the
kmem_cache_setup_mobility()call, which can be perfectly avoided using a boot option, for example. Turning it on and off completely dynamic isn't that hard too.Of course, it's up to you, it's just probably easier to find new users of a new feature, when it's easy to test it.
Ok, cool - I like it. Will add for next version.
thanks,
Tobin.
Re: [RFC PATCH v5 16/16] dcache: Add CONFIG_DCACHE_SMO
In reply to Roman GushchinQuoted 33 lines · Roman Gushchin
Quoted 8 lines · Tobin C. Harding
Quoted 7 lines · Roman Gushchin
Quoted 6 lines · Tobin C. Harding
In an attempt to make the SMO patchset as non-invasive as possible add a config option
CONFIG_DCACHE_SMO(under "Memory Management options") for enabling SMO for the DCACHE. Whithout this option dcache constructor is used but no other code is built in, with this option enabled slab mobility is enabled and the isolate/migrate functions are built in.Quoted 8 lines
Quoted 5 lines
Quoted 2 lines
Add
CONFIG_DCACHE_SMOto guard the partial shrinking of the dcache via Slab Movable Objects infrastructure.Hm, isn't it better to make it a static branch? Or basically anything that allows switching on the fly?
If that is wanted, turning SMO on and off per cache, we can probably do this in the SMO code in SLUB.
Not necessarily per cache, but without recompiling the kernel.
Quoted 11 lines
Quoted 4 lines
It seems that the cost of just building it in shouldn't be that high. And the question if the defragmentation worth the trouble is so much easier to answer if it's possible to turn it on and off without rebooting.
If the question is 'is defragmentation worth the trouble for the dcache', I'm not sure having SMO turned off helps answer that question. If one doesn't shrink the dentry cache there should be very little overhead in having SMO enabled. So if one wants to explore this question then they can turn on the config option. Please correct me if I'm wrong.
The problem with a config option is that it's hard to switch over.
Quoted 8 lines
So just to test your changes in production a new kernel should be built, tested and rolled out to a representative set of machines (which can be measured in thousands of machines). Then if results are questionable, it should be rolled back.
What you're actually guarding is the
kmem_cache_setup_mobility()call, which can be perfectly avoided using a boot option, for example. Turning it on and off completely dynamic isn't that hard too.
Hi Roman,
I've added a boot parameter to SLUB so that admins can enable/disable SMO at boot time system wide. Then for each object that implements SMO (currently XArray and dcache) I've also added a boot parameter to enable/disable SMO for that cache specifically (these depend on SMO being enabled system wide).
All three boot parameters default to 'off', I've added a config option to default each to 'on'.
I've got a little more testing to do on another part of the set then the PATCH version is coming at you :)
This is more a courtesy email than a request for comment, but please feel free to shout if you don't like the method outlined above.
Fully dynamic config is not currently possible because currently the SMO implementation does not support disabling mobility for a cache once it is turned on, a bit of extra logic would need to be added and some state stored - I'm not sure it warrants it ATM but that can be easily added later if wanted. Maybe Christoph will give his opinion on this.
thanks,
Tobin.
Re: [RFC PATCH v5 16/16] dcache: Add CONFIG_DCACHE_SMO
Quoted 57 lines · Tobin C. Harding
Quoted 33 lines · Roman Gushchin
Quoted 8 lines · Tobin C. Harding
Quoted 7 lines · Roman Gushchin
Quoted 6 lines · Tobin C. Harding
In an attempt to make the SMO patchset as non-invasive as possible add a config option
CONFIG_DCACHE_SMO(under "Memory Management options") for enabling SMO for the DCACHE. Whithout this option dcache constructor is used but no other code is built in, with this option enabled slab mobility is enabled and the isolate/migrate functions are built in.Quoted 8 lines
Quoted 5 lines
Quoted 2 lines
Add
CONFIG_DCACHE_SMOto guard the partial shrinking of the dcache via Slab Movable Objects infrastructure.Hm, isn't it better to make it a static branch? Or basically anything that allows switching on the fly?
If that is wanted, turning SMO on and off per cache, we can probably do this in the SMO code in SLUB.
Not necessarily per cache, but without recompiling the kernel.
Quoted 11 lines
Quoted 4 lines
It seems that the cost of just building it in shouldn't be that high. And the question if the defragmentation worth the trouble is so much easier to answer if it's possible to turn it on and off without rebooting.
If the question is 'is defragmentation worth the trouble for the dcache', I'm not sure having SMO turned off helps answer that question. If one doesn't shrink the dentry cache there should be very little overhead in having SMO enabled. So if one wants to explore this question then they can turn on the config option. Please correct me if I'm wrong.
The problem with a config option is that it's hard to switch over.
Quoted 8 lines
So just to test your changes in production a new kernel should be built, tested and rolled out to a representative set of machines (which can be measured in thousands of machines). Then if results are questionable, it should be rolled back.
What you're actually guarding is the
kmem_cache_setup_mobility()call, which can be perfectly avoided using a boot option, for example. Turning it on and off completely dynamic isn't that hard too.Hi Roman,
I've added a boot parameter to SLUB so that admins can enable/disable SMO at boot time system wide. Then for each object that implements SMO (currently XArray and dcache) I've also added a boot parameter to enable/disable SMO for that cache specifically (these depend on SMO being enabled system wide).
All three boot parameters default to 'off', I've added a config option to default each to 'on'.
I've got a little more testing to do on another part of the set then the PATCH version is coming at you :)
Quoted 8 lines
This is more a courtesy email than a request for comment, but please feel free to shout if you don't like the method outlined above.
Fully dynamic config is not currently possible because currently the SMO implementation does not support disabling mobility for a cache once it is turned on, a bit of extra logic would need to be added and some state stored - I'm not sure it warrants it ATM but that can be easily added later if wanted. Maybe Christoph will give his opinion on this.
Perfect!
Thanks.
Re: [RFC PATCH v5 16/16] dcache: Add CONFIG_DCACHE_SMO
Quoted 61 lines · Roman Gushchin
Quoted 60 lines · Tobin C. Harding
Quoted 33 lines · Roman Gushchin
Quoted 8 lines · Tobin C. Harding
Quoted 7 lines · Roman Gushchin
Quoted 6 lines · Tobin C. Harding
In an attempt to make the SMO patchset as non-invasive as possible add a config option
CONFIG_DCACHE_SMO(under "Memory Management options") for enabling SMO for the DCACHE. Whithout this option dcache constructor is used but no other code is built in, with this option enabled slab mobility is enabled and the isolate/migrate functions are built in.Quoted 8 lines
Quoted 5 lines
Quoted 2 lines
Add
CONFIG_DCACHE_SMOto guard the partial shrinking of the dcache via Slab Movable Objects infrastructure.Hm, isn't it better to make it a static branch? Or basically anything that allows switching on the fly?
If that is wanted, turning SMO on and off per cache, we can probably do this in the SMO code in SLUB.
Not necessarily per cache, but without recompiling the kernel.
Quoted 11 lines
Quoted 4 lines
It seems that the cost of just building it in shouldn't be that high. And the question if the defragmentation worth the trouble is so much easier to answer if it's possible to turn it on and off without rebooting.
If the question is 'is defragmentation worth the trouble for the dcache', I'm not sure having SMO turned off helps answer that question. If one doesn't shrink the dentry cache there should be very little overhead in having SMO enabled. So if one wants to explore this question then they can turn on the config option. Please correct me if I'm wrong.
The problem with a config option is that it's hard to switch over.
Quoted 8 lines
So just to test your changes in production a new kernel should be built, tested and rolled out to a representative set of machines (which can be measured in thousands of machines). Then if results are questionable, it should be rolled back.
What you're actually guarding is the
kmem_cache_setup_mobility()call, which can be perfectly avoided using a boot option, for example. Turning it on and off completely dynamic isn't that hard too.Hi Roman,
I've added a boot parameter to SLUB so that admins can enable/disable SMO at boot time system wide. Then for each object that implements SMO (currently XArray and dcache) I've also added a boot parameter to enable/disable SMO for that cache specifically (these depend on SMO being enabled system wide).
All three boot parameters default to 'off', I've added a config option to default each to 'on'.
I've got a little more testing to do on another part of the set then the PATCH version is coming at you :)
This is more a courtesy email than a request for comment, but please feel free to shout if you don't like the method outlined above.
Quoted 7 lines
Quoted 5 lines
Fully dynamic config is not currently possible because currently the SMO implementation does not support disabling mobility for a cache once it is turned on, a bit of extra logic would need to be added and some state stored - I'm not sure it warrants it ATM but that can be easily added later if wanted. Maybe Christoph will give his opinion on this.
Perfect!
Hi Roman,
I'm about to post PATCH series. I have removed all the boot time config options in contrast to what I stated in this thread. I feel it requires some comment so as not to seem rude to you. Please feel free to re-raise these issues on the series if you feel it is a better place to do it than on this thread.
I still hear you re making testing easier if there are boot parameters. I don't have extensive experience testing on a large number of machines so I have no basis to contradict what you said.
It was suggested to me that having switches to turn SMO off implies the series is not ready. I am claiming that SMO _is_ ready and also that it has no negative effects (especially on the dcache). I therefore think this comment is pertinent.
So ... I re-did the boot parameters defaulting to 'on'. However I could then see no reason (outside of testing) to turn them off. It seems ugly to have code that is only required during testing and never after. Please correct me if I'm wrong.
Finally I decided that since adding a boot parameter is trivial that hackers could easily add one to test if they wanted to test a specific cache. Otherwise we just test 'patched kernel' vs 'unpatched kernel'. Again, please correct me if I'm wrong.
So, that said, please feel free to voice your opinion as strongly as you wish. I am super appreciative of the time you have already taken to look at these patches. I hope I have made the best technical decision, and I am totally open to being told I'm wrong :)
thanks,
Tobin.
Re: [RFC PATCH v5 16/16] dcache: Add CONFIG_DCACHE_SMO
Quoted 97 lines · Tobin C. Harding
Quoted 61 lines · Roman Gushchin
Quoted 60 lines · Tobin C. Harding
Quoted 33 lines · Roman Gushchin
Quoted 8 lines · Tobin C. Harding
Quoted 7 lines · Roman Gushchin
Quoted 6 lines · Tobin C. Harding
In an attempt to make the SMO patchset as non-invasive as possible add a config option
CONFIG_DCACHE_SMO(under "Memory Management options") for enabling SMO for the DCACHE. Whithout this option dcache constructor is used but no other code is built in, with this option enabled slab mobility is enabled and the isolate/migrate functions are built in.Quoted 8 lines
Quoted 5 lines
Quoted 2 lines
Add
CONFIG_DCACHE_SMOto guard the partial shrinking of the dcache via Slab Movable Objects infrastructure.Hm, isn't it better to make it a static branch? Or basically anything that allows switching on the fly?
If that is wanted, turning SMO on and off per cache, we can probably do this in the SMO code in SLUB.
Not necessarily per cache, but without recompiling the kernel.
Quoted 11 lines
Quoted 4 lines
It seems that the cost of just building it in shouldn't be that high. And the question if the defragmentation worth the trouble is so much easier to answer if it's possible to turn it on and off without rebooting.
If the question is 'is defragmentation worth the trouble for the dcache', I'm not sure having SMO turned off helps answer that question. If one doesn't shrink the dentry cache there should be very little overhead in having SMO enabled. So if one wants to explore this question then they can turn on the config option. Please correct me if I'm wrong.
The problem with a config option is that it's hard to switch over.
Quoted 8 lines
So just to test your changes in production a new kernel should be built, tested and rolled out to a representative set of machines (which can be measured in thousands of machines). Then if results are questionable, it should be rolled back.
What you're actually guarding is the
kmem_cache_setup_mobility()call, which can be perfectly avoided using a boot option, for example. Turning it on and off completely dynamic isn't that hard too.Hi Roman,
I've added a boot parameter to SLUB so that admins can enable/disable SMO at boot time system wide. Then for each object that implements SMO (currently XArray and dcache) I've also added a boot parameter to enable/disable SMO for that cache specifically (these depend on SMO being enabled system wide).
All three boot parameters default to 'off', I've added a config option to default each to 'on'.
I've got a little more testing to do on another part of the set then the PATCH version is coming at you :)
This is more a courtesy email than a request for comment, but please feel free to shout if you don't like the method outlined above.
Quoted 7 lines
Quoted 5 lines
Fully dynamic config is not currently possible because currently the SMO implementation does not support disabling mobility for a cache once it is turned on, a bit of extra logic would need to be added and some state stored - I'm not sure it warrants it ATM but that can be easily added later if wanted. Maybe Christoph will give his opinion on this.
Perfect!
Hi Roman,
I'm about to post PATCH series. I have removed all the boot time config options in contrast to what I stated in this thread. I feel it requires some comment so as not to seem rude to you. Please feel free to re-raise these issues on the series if you feel it is a better place to do it than on this thread.
I still hear you re making testing easier if there are boot parameters. I don't have extensive experience testing on a large number of machines so I have no basis to contradict what you said.
It was suggested to me that having switches to turn SMO off implies the series is not ready. I am claiming that SMO _is_ ready and also that it has no negative effects (especially on the dcache). I therefore think this comment is pertinent.
So ... I re-did the boot parameters defaulting to 'on'. However I could then see no reason (outside of testing) to turn them off. It seems ugly to have code that is only required during testing and never after. Please correct me if I'm wrong.
Finally I decided that since adding a boot parameter is trivial that hackers could easily add one to test if they wanted to test a specific cache. Otherwise we just test 'patched kernel' vs 'unpatched kernel'. Again, please correct me if I'm wrong.
Quoted 4 lines
So, that said, please feel free to voice your opinion as strongly as you wish. I am super appreciative of the time you have already taken to look at these patches. I hope I have made the best technical decision, and I am totally open to being told I'm wrong :)
Hi Tobin!
No boot options looks totally fine to me. I just don't like new config options. No options at all is always the best.
Btw, thank you for this clarification!
I'll definitely try to look into the patchset on this week.
Thanks!