rcu: Cleanup RCU tree initialization
v3 cover rcu: Cleanup RCU tree initialization
Hello Paul,
This is 3rd attempt to make RCU tree initialization bit more clear and optimize memory footprint of data associated with the tree.
Changes since v2:
- patch 1 fixed to avoid a panic in case rcu_fanout_leaf
is out of bounds;
Changes since v1:
- patch 3 fixed to accomodate nr_cpus=1, otherwise rcu_num_lvls
would yield zero, which is wrong;
The series is against "linux-rcu" tree "rcu/dev" branch
Thanks!
Alexander Gordeev (9):
rcu: Panic if RCU tree can not accommodate all CPUs
rcu: Remove superfluous local variable in rcu_init_geometry()
rcu: Cleanup rcu_init_geometry() code and arithmetics
rcu: Simplify rcu_init_geometry() capacity arithmetics
rcu: Limit rcu_state::levelcnt[] to RCU_NUM_LVLS items
rcu: Limit rcu_capacity[] size to RCU_NUM_LVLS items
rcu: Remove unnecessary fields from rcu_state structure
rcu: Limit count of static data to the number of RCU levels
rcu: Simplify arithmetic to calculate number of RCU nodes
kernel/rcu/tree.c | 109 +++++++++++++++++++++-------------------------- kernel/rcu/tree.h | 33 +++++++------- kernel/rcu/tree_plugin.h | 4 +- 3 files changed, 67 insertions(+), 79 deletions(-)
Signature · 1 line
1.8.3.1
PATCH v3 1/9 rcu: Panic if RCU tree can not accommodate all CPUs
Currently a condition when RCU tree is unable to accommodate the configured number of CPUs is not permitted and causes a fall back to compile-time values. However, the code has no means to exceed the RCU tree capacity neither at compile-time nor in run-time. Therefore, if the condition is met in run- time then it indicates a serios problem elsewhere and should be handled with a panic.
--- kernel/rcu/tree.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-)
kernel/rcu/tree.c +17 -12
@@ -4107,6 +4107,19 @@ static void __init rcu_init_geometry(void) rcu_fanout_leaf, nr_cpu_ids);/* +* The boot-time rcu_fanout_leaf parameter is only permitted +* to increase the leaf-level fanout, not decrease it. Of course, +* the leaf-level fanout cannot exceed the number of bits in +* the rcu_node masks. Complain and fall back to the compile- +* time values if these limits are exceeded. +*/ +if (rcu_fanout_leaf <RCU_FANOUT_LEAF || + rcu_fanout_leaf >sizeof (unsigned long ) *8 ) { +WARN_ON (1 ); +return ; + } + +/* * Compute number of nodes that can be handled an rcu_node tree * with the given number of levels. Setting rcu_capacity[0] makes * some of the arithmetic easier.
@@ -4117,19 +4130,11 @@ static void __init rcu_init_geometry(void) rcu_capacity[i] = rcu_capacity[i -1 ] *RCU_FANOUT ;/* -* The boot-time rcu_fanout_leaf parameter is only permitted -* to increase the leaf-level fanout, not decrease it. Of course, -* the leaf-level fanout cannot exceed the number of bits in -* the rcu_node masks. Finally, the tree must be able to accommodate -* the configured number of CPUs. Complain and fall back to the -* compile-time values if these limits are exceeded. +* The tree must be able to accommodate the configured number of CPUs. +* If this limit is exceeded than we have a serious problem elsewhere. */ -if (rcu_fanout_leaf <RCU_FANOUT_LEAF || - rcu_fanout_leaf >sizeof (unsigned long ) *8 || - n > rcu_capacity[MAX_RCU_LVLS ]) { -WARN_ON (1 ); -return ; - } +if (n > rcu_capacity[MAX_RCU_LVLS ]) +panic ("rcu_init_geometry: rcu_capacity[] is too small" );/* Calculate the number of rcu_nodes at each level of the tree. */ for (i =1 ; i <=MAX_RCU_LVLS ; i++)
Signature · 1 line
1.8.3.1
PATCH v3 2/9 rcu: Remove superfluous local variable in rcu_init_geometry()
In reply to Alexander GordeevLocal variable 'n' mimics 'nr_cpu_ids' while the both are used within one function. There is no reason for 'n' to exist whatsoever.
--- kernel/rcu/tree.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
kernel/rcu/tree.c +7 -7
@@ -4083,7 +4083,6 @@ static void __init rcu_init_geometry(void)ulong d;int i;int j; -int n = nr_cpu_ids;int rcu_capacity[MAX_RCU_LVLS +1 ];/*
@@ -4133,15 +4132,16 @@ static void __init rcu_init_geometry(void)* The tree must be able to accommodate the configured number of CPUs. * If this limit is exceeded than we have a serious problem elsewhere. */ -if (n > rcu_capacity[MAX_RCU_LVLS ]) +if (nr_cpu_ids > rcu_capacity[MAX_RCU_LVLS ])panic ("rcu_init_geometry: rcu_capacity[] is too small" );/* Calculate the number of rcu_nodes at each level of the tree. */ for (i =1 ; i <=MAX_RCU_LVLS ; i++) -if (n <= rcu_capacity[i]) { -for (j =0 ; j <= i; j++) - num_rcu_lvl[j] = -DIV_ROUND_UP (n, rcu_capacity[i - j]); +if (nr_cpu_ids <= rcu_capacity[i]) { +for (j =0 ; j <= i; j++) { +int cap = rcu_capacity[i - j]; + num_rcu_lvl[j] =DIV_ROUND_UP (nr_cpu_ids, cap); + } rcu_num_lvls = i;for (j = i +1 ; j <=MAX_RCU_LVLS ; j++) num_rcu_lvl[j] =0 ;
@@ -4152,7 +4152,7 @@ static void __init rcu_init_geometry(void) rcu_num_nodes =0 ;for (i =0 ; i <=MAX_RCU_LVLS ; i++) rcu_num_nodes += num_rcu_lvl[i]; - rcu_num_nodes -= n; + rcu_num_nodes -= nr_cpu_ids; }/*
Signature · 1 line
1.8.3.1
PATCH v3 3/9 rcu: Cleanup rcu_init_geometry() code and arithmetics
In reply to Alexander GordeevThis update simplifies rcu_init_geometry() code flow and makes calculation of the total number of rcu_node structures more easy to read.
The update relies on the fact num_rcu_lvl[] is never accessed beyond rcu_num_lvls index by the rest of the code. Therefore, there is no need initialize the whole num_rcu_lvl[].
--- kernel/rcu/tree.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-)
kernel/rcu/tree.c +10 -14
@@ -4082,7 +4082,6 @@ static void __init rcu_init_geometry(void) {ulong d;int i; -int j;int rcu_capacity[MAX_RCU_LVLS +1 ];/*
@@ -4135,24 +4134,21 @@ static void __init rcu_init_geometry(void)if (nr_cpu_ids > rcu_capacity[MAX_RCU_LVLS ])panic ("rcu_init_geometry: rcu_capacity[] is too small" ); +/* Calculate the number of levels in the tree. */ +for (i =1 ; nr_cpu_ids > rcu_capacity[i]; i++) { + } + rcu_num_lvls = i; +/* Calculate the number of rcu_nodes at each level of the tree. */ -for (i =1 ; i <=MAX_RCU_LVLS ; i++) -if (nr_cpu_ids <= rcu_capacity[i]) { -for (j =0 ; j <= i; j++) { -int cap = rcu_capacity[i - j]; - num_rcu_lvl[j] =DIV_ROUND_UP (nr_cpu_ids, cap); - } - rcu_num_lvls = i; -for (j = i +1 ; j <=MAX_RCU_LVLS ; j++) - num_rcu_lvl[j] =0 ; -break ; - } +for (i =0 ; i < rcu_num_lvls; i++) { +int cap = rcu_capacity[rcu_num_lvls - i]; + num_rcu_lvl[i] =DIV_ROUND_UP (nr_cpu_ids, cap); + }/* Calculate the total number of rcu_node structures. */ rcu_num_nodes =0 ; -for (i =0 ; i <=MAX_RCU_LVLS ; i++) +for (i =0 ; i < rcu_num_lvls; i++) rcu_num_nodes += num_rcu_lvl[i]; - rcu_num_nodes -= nr_cpu_ids; }/*
Signature · 1 line
1.8.3.1
PATCH v3 4/9 rcu: Simplify rcu_init_geometry() capacity arithmetics
In reply to Alexander GordeevCurrent code suggests that introducing the extra level to rcu_capacity[] array makes some of the arithmetic easier. Well, in fact it appears rather confusing and unnecessary.
--- kernel/rcu/tree.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-)
kernel/rcu/tree.c +8 -10
@@ -4082,7 +4082,7 @@ static void __init rcu_init_geometry(void) {ulong d;int i; -int rcu_capacity[MAX_RCU_LVLS +1 ]; +int rcu_capacity[MAX_RCU_LVLS ];/* * Initialize any unspecified boot parameters.
@@ -4119,29 +4119,27 @@ static void __init rcu_init_geometry(void)/* * Compute number of nodes that can be handled an rcu_node tree -* with the given number of levels. Setting rcu_capacity[0] makes -* some of the arithmetic easier. +* with the given number of levels. */ - rcu_capacity[0 ] =1 ; - rcu_capacity[1 ] = rcu_fanout_leaf; -for (i =2 ; i <=MAX_RCU_LVLS ; i++) + rcu_capacity[0 ] = rcu_fanout_leaf; +for (i =1 ; i <MAX_RCU_LVLS ; i++) rcu_capacity[i] = rcu_capacity[i -1 ] *RCU_FANOUT ;/* * The tree must be able to accommodate the configured number of CPUs. * If this limit is exceeded than we have a serious problem elsewhere. */ -if (nr_cpu_ids > rcu_capacity[MAX_RCU_LVLS ]) +if (nr_cpu_ids > rcu_capacity[MAX_RCU_LVLS -1 ])panic ("rcu_init_geometry: rcu_capacity[] is too small" );/* Calculate the number of levels in the tree. */ -for (i =1 ; nr_cpu_ids > rcu_capacity[i]; i++) { +for (i =0 ; nr_cpu_ids > rcu_capacity[i]; i++) { } - rcu_num_lvls = i; + rcu_num_lvls = i +1 ;/* Calculate the number of rcu_nodes at each level of the tree. */ for (i =0 ; i < rcu_num_lvls; i++) { -int cap = rcu_capacity[rcu_num_lvls - i]; +int cap = rcu_capacity[(rcu_num_lvls -1 ) - i]; num_rcu_lvl[i] =DIV_ROUND_UP (nr_cpu_ids, cap); }
Signature · 1 line
1.8.3.1
PATCH v3 5/9 rcu: Limit rcu_state::levelcnt[] to RCU_NUM_LVLS items
In reply to Alexander GordeevVariable rcu_num_lvls is limited by RCU_NUM_LVLS macro. In turn, rcu_state::levelcnt[] array is never accessed beyond rcu_num_lvls. Thus, rcu_state::levelcnt[] is safe to limit to RCU_NUM_LVLS items.
Since rcu_num_lvls could be changed during boot (as result of rcutree.rcu_fanout_leaf kernel parameter update) one might assume a new value could overflow the value of RCU_NUM_LVLS. However, that is not the case, since leaf-level fanout is only permitted to increase, resulting in rcu_num_lvls possibly to decrease.
--- kernel/rcu/tree.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/rcu/tree.h +1 -1
@@ -443,7 +443,7 @@ do { \struct rcu_state {struct rcu_node node[NUM_RCU_NODES ];/* Hierarchy. */ struct rcu_node *level[RCU_NUM_LVLS ];/* Hierarchy levels. */ -u32 levelcnt[MAX_RCU_LVLS +1 ];/* # nodes in each level. */ +u32 levelcnt[RCU_NUM_LVLS ];/* # nodes in each level. */ u8 levelspread[RCU_NUM_LVLS ];/* kids/node in each level. */ u8 flavor_mask;/* bit in flavor mask. */ struct rcu_data __percpu *rda;/* pointer of percu rcu_data. */
Signature · 1 line
1.8.3.1
PATCH v3 6/9 rcu: Limit rcu_capacity[] size to RCU_NUM_LVLS items
In reply to Alexander GordeevNumber of items in rcu_capacity[] array is defined by macro MAX_RCU_LVLS. However, that array is never accessed beyond RCU_NUM_LVLS index. Therefore, we can limit the array to RCU_NUM_LVLS items and eliminate MAX_RCU_LVLS. As result, in most cases the memory is conserved.
--- kernel/rcu/tree.c | 12 ++++++------ kernel/rcu/tree.h | 2 -- 2 files changed, 6 insertions(+), 8 deletions(-)
kernel/rcu/tree.c +6 -6
@@ -3998,19 +3998,19 @@ static void __init rcu_init_one(struct rcu_state *rsp,"rcu_node_0" ,"rcu_node_1" ,"rcu_node_2" , - "rcu_node_3" }; /* Match MAX_RCU_LVLS */ + "rcu_node_3" };static const char *const fqs[] = {"rcu_node_fqs_0" ,"rcu_node_fqs_1" ,"rcu_node_fqs_2" , -"rcu_node_fqs_3" };/* Match MAX_RCU_LVLS */ +"rcu_node_fqs_3" };static u8 fl_mask =0x1 ;int cpustride =1 ;int i;int j;struct rcu_node *rnp; -BUILD_BUG_ON (MAX_RCU_LVLS >ARRAY_SIZE (buf));/* Fix buf[] init! */ +BUILD_BUG_ON (RCU_NUM_LVLS >ARRAY_SIZE (buf));/* Fix buf[] init! */ /* Silence gcc 4.8 false positive about array index out of range. */ if (rcu_num_lvls <=0 || rcu_num_lvls >RCU_NUM_LVLS )
@@ -4082,7 +4082,7 @@ static void __init rcu_init_geometry(void) {ulong d;int i; -int rcu_capacity[MAX_RCU_LVLS ]; +int rcu_capacity[RCU_NUM_LVLS ];/* * Initialize any unspecified boot parameters.
@@ -4122,14 +4122,14 @@ static void __init rcu_init_geometry(void)* with the given number of levels. */ rcu_capacity[0 ] = rcu_fanout_leaf; -for (i =1 ; i <MAX_RCU_LVLS ; i++) +for (i =1 ; i <RCU_NUM_LVLS ; i++) rcu_capacity[i] = rcu_capacity[i -1 ] *RCU_FANOUT ;/* * The tree must be able to accommodate the configured number of CPUs. * If this limit is exceeded than we have a serious problem elsewhere. */ -if (nr_cpu_ids > rcu_capacity[MAX_RCU_LVLS -1 ]) +if (nr_cpu_ids > rcu_capacity[RCU_NUM_LVLS -1 ])panic ("rcu_init_geometry: rcu_capacity[] is too small" );/* Calculate the number of levels in the tree. */
kernel/rcu/tree.h +0 -2
@@ -36,8 +36,6 @@* Of course, your mileage may vary. */ -#define MAX_RCU_LVLS 4 -#ifdef CONFIG_RCU_FANOUT #define RCU_FANOUT CONFIG_RCU_FANOUT#else /* #ifdef CONFIG_RCU_FANOUT */
Signature · 1 line
1.8.3.1
PATCH v3 7/9 rcu: Remove unnecessary fields from rcu_state structure
In reply to Alexander GordeevMembers rcu_state::levelcnt[] and rcu_state::levelspread[] are only used at init. There is no reason to keep them afterwards.
--- kernel/rcu/tree.c | 27 +++++++++++++++------------ kernel/rcu/tree.h | 2 -- 2 files changed, 15 insertions(+), 14 deletions(-)
kernel/rcu/tree.c +15 -12
@@ -3967,22 +3967,22 @@ void rcu_scheduler_starting(void)* Compute the per-level fanout, either using the exact fanout specified * or balancing the tree, depending on the rcu_fanout_exact boot parameter. */ -static void __init rcu_init_levelspread (struct rcu_state *rsp) +static void __init rcu_init_levelspread (int *levelspread,const int *levelcnt) {int i;if (rcu_fanout_exact) { - rsp->levelspread[rcu_num_lvls -1 ] = rcu_fanout_leaf; + levelspread[rcu_num_lvls -1 ] = rcu_fanout_leaf;for (i = rcu_num_lvls -2 ; i >=0 ; i--) - rsp->levelspread[i] =RCU_FANOUT ; + levelspread[i] =RCU_FANOUT ; }else {int ccur;int cprv; cprv = nr_cpu_ids;for (i = rcu_num_lvls -1 ; i >=0 ; i--) { - ccur = rsp->levelcnt[i]; - rsp->levelspread[i] = (cprv + ccur -1 ) / ccur; + ccur = levelcnt[i]; + levelspread[i] = (cprv + ccur -1 ) / ccur; cprv = ccur; } }
@@ -4005,6 +4005,9 @@ static void __init rcu_init_one(struct rcu_state *rsp,"rcu_node_fqs_2" , "rcu_node_fqs_3" };static u8 fl_mask =0x1 ; + +int levelcnt[RCU_NUM_LVLS ];/* # nodes in each level. */ +int levelspread[RCU_NUM_LVLS ];/* kids/node in each level. */ int cpustride =1 ;int i;int j;
@@ -4019,19 +4022,19 @@ static void __init rcu_init_one(struct rcu_state *rsp,/* Initialize the level-tracking arrays. */ for (i =0 ; i < rcu_num_lvls; i++) - rsp->levelcnt[i] = num_rcu_lvl[i]; + levelcnt[i] = num_rcu_lvl[i];for (i =1 ; i < rcu_num_lvls; i++) - rsp->level[i] = rsp->level[i -1 ] + rsp->levelcnt[i -1 ]; -rcu_init_levelspread (rsp); + rsp->level[i] = rsp->level[i -1 ] + levelcnt[i -1 ]; +rcu_init_levelspread (levelspread, levelcnt); rsp->flavor_mask = fl_mask; fl_mask <<=1 ;/* Initialize the elements themselves, starting from the leaves. */ for (i = rcu_num_lvls -1 ; i >=0 ; i--) { - cpustride *= rsp->levelspread[i]; + cpustride *= levelspread[i]; rnp = rsp->level[i]; -for (j =0 ; j < rsp->levelcnt[i]; j++, rnp++) { +for (j =0 ; j < levelcnt[i]; j++, rnp++) {raw_spin_lock_init (&rnp->lock);lockdep_set_class_and_name (&rnp->lock, &rcu_node_class[i], buf[i]);
@@ -4051,10 +4054,10 @@ static void __init rcu_init_one(struct rcu_state *rsp, rnp->grpmask =0 ; rnp->parent =NULL ; }else { - rnp->grpnum = j % rsp->levelspread[i -1 ]; + rnp->grpnum = j % levelspread[i -1 ]; rnp->grpmask =1UL << rnp->grpnum; rnp->parent = rsp->level[i -1 ] + - j / rsp->levelspread[i -1 ]; + j / levelspread[i -1 ]; } rnp->level = i;INIT_LIST_HEAD (&rnp->blkd_tasks);
kernel/rcu/tree.h +0 -2
@@ -441,8 +441,6 @@ do { \struct rcu_state {struct rcu_node node[NUM_RCU_NODES ];/* Hierarchy. */ struct rcu_node *level[RCU_NUM_LVLS ];/* Hierarchy levels. */ -u32 levelcnt[RCU_NUM_LVLS ];/* # nodes in each level. */ -u8 levelspread[RCU_NUM_LVLS ];/* kids/node in each level. */ u8 flavor_mask;/* bit in flavor mask. */ struct rcu_data __percpu *rda;/* pointer of percu rcu_data. */ void (*call)(struct rcu_head *head, /* call_rcu() flavor. */
Signature · 1 line
1.8.3.1
PATCH v3 8/9 rcu: Limit count of static data to the number of RCU levels
In reply to Alexander GordeevAlthough a number of RCU levels may be less than the current maximum of four, some static data associated with each level are allocated for all four levels. As result, the extra data never get accessed and just wast memory. This update limits count of allocated items to the number of used RCU levels.
--- kernel/rcu/tree.c | 21 ++++----------------- kernel/rcu/tree.h | 12 ++++++++++++ 2 files changed, 16 insertions(+), 17 deletions(-)
kernel/rcu/tree.c +4 -17
@@ -124,13 +124,8 @@ module_param(rcu_fanout_exact, bool, 0444);static int rcu_fanout_leaf =RCU_FANOUT_LEAF ;module_param (rcu_fanout_leaf, int,0444 );int rcu_num_lvls__read_mostly =RCU_NUM_LVLS ; -static int num_rcu_lvl[] = {/* Number of rcu_nodes at specified level. */ -NUM_RCU_LVL_0 , -NUM_RCU_LVL_1 , -NUM_RCU_LVL_2 , -NUM_RCU_LVL_3 , -NUM_RCU_LVL_4 , -}; +/* Number of rcu_nodes at specified level. */ +static int num_rcu_lvl[] =NUM_RCU_LVL_INIT ;int rcu_num_nodes__read_mostly =NUM_RCU_NODES ;/* Total # rcu_nodes in use. */ /*
@@ -3994,16 +3989,8 @@ static void __init rcu_init_levelspread(int *levelspread, const int *levelcnt)static void __init rcu_init_one (struct rcu_state *rsp,struct rcu_data __percpu *rda) { -static const char *const buf[] = { -"rcu_node_0" , -"rcu_node_1" , -"rcu_node_2" , -"rcu_node_3" }; -static const char *const fqs[] = { -"rcu_node_fqs_0" , -"rcu_node_fqs_1" , -"rcu_node_fqs_2" , -"rcu_node_fqs_3" }; +static const char *const buf[] =RCU_NODE_NAME_INIT ; +static const char *const fqs[] =RCU_FQS_NAME_INIT ;static u8 fl_mask =0x1 ;int levelcnt[RCU_NUM_LVLS ];/* # nodes in each level. */
kernel/rcu/tree.h +12 -0
@@ -68,6 +68,9 @@# define NUM_RCU_LVL_2 0# define NUM_RCU_LVL_3 0# define NUM_RCU_LVL_4 0 +# define NUM_RCU_LVL_INIT { NUM_RCU_LVL_0 } +# define RCU_NODE_NAME_INIT { "rcu_node_0" } +# define RCU_FQS_NAME_INIT { "rcu_node_fqs_0" }#elif NR_CPUS <=RCU_FANOUT_2 # define RCU_NUM_LVLS 2# define NUM_RCU_LVL_0 1
@@ -75,6 +78,9 @@# define NUM_RCU_LVL_2 (NR_CPUS)# define NUM_RCU_LVL_3 0# define NUM_RCU_LVL_4 0 +# define NUM_RCU_LVL_INIT { NUM_RCU_LVL_0, NUM_RCU_LVL_1 } +# define RCU_NODE_NAME_INIT { "rcu_node_0", "rcu_node_1" } +# define RCU_FQS_NAME_INIT { "rcu_node_fqs_0", "rcu_node_fqs_1" }#elif NR_CPUS <=RCU_FANOUT_3 # define RCU_NUM_LVLS 3# define NUM_RCU_LVL_0 1
@@ -82,6 +88,9 @@# define NUM_RCU_LVL_2 DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_1)# define NUM_RCU_LVL_3 (NR_CPUS)# define NUM_RCU_LVL_4 0 +# define NUM_RCU_LVL_INIT { NUM_RCU_LVL_0, NUM_RCU_LVL_1, NUM_RCU_LVL_2 } +# define RCU_NODE_NAME_INIT { "rcu_node_0", "rcu_node_1", "rcu_node_2" } +# define RCU_FQS_NAME_INIT { "rcu_node_fqs_0", "rcu_node_fqs_1", "rcu_node_fqs_2" }#elif NR_CPUS <=RCU_FANOUT_4 # define RCU_NUM_LVLS 4# define NUM_RCU_LVL_0 1
@@ -89,6 +98,9 @@# define NUM_RCU_LVL_2 DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_2)# define NUM_RCU_LVL_3 DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_1)# define NUM_RCU_LVL_4 (NR_CPUS) +# define NUM_RCU_LVL_INIT { NUM_RCU_LVL_0, NUM_RCU_LVL_1, NUM_RCU_LVL_2, NUM_RCU_LVL_3 } +# define RCU_NODE_NAME_INIT { "rcu_node_0", "rcu_node_1", "rcu_node_2", "rcu_node_3" } +# define RCU_FQS_NAME_INIT { "rcu_node_fqs_0", "rcu_node_fqs_1", "rcu_node_fqs_2", "rcu_node_fqs_3" }#else # error "CONFIG_RCU_FANOUT insufficient for NR_CPUS"#endif /* #if (NR_CPUS) <= RCU_FANOUT_1 */
Signature · 1 line
1.8.3.1
PATCH v3 9/9 rcu: Simplify arithmetic to calculate number of RCU nodes
In reply to Alexander GordeevThis update makes arithmetic to calculate number of RCU nodes more straight and easy to read.
--- kernel/rcu/tree.h | 17 ++++------------- kernel/rcu/tree_plugin.h | 4 ++-- 2 files changed, 6 insertions(+), 15 deletions(-)
kernel/rcu/tree.h +4 -13
@@ -64,10 +64,7 @@#if NR_CPUS <=RCU_FANOUT_1 # define RCU_NUM_LVLS 1# define NUM_RCU_LVL_0 1 -# define NUM_RCU_LVL_1 (NR_CPUS) -# define NUM_RCU_LVL_2 0 -# define NUM_RCU_LVL_3 0 -# define NUM_RCU_LVL_4 0 +# define NUM_RCU_NODES NUM_RCU_LVL_0# define NUM_RCU_LVL_INIT { NUM_RCU_LVL_0 }# define RCU_NODE_NAME_INIT { "rcu_node_0" }# define RCU_FQS_NAME_INIT { "rcu_node_fqs_0" }
@@ -75,9 +72,7 @@# define RCU_NUM_LVLS 2# define NUM_RCU_LVL_0 1# define NUM_RCU_LVL_1 DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_1) -# define NUM_RCU_LVL_2 (NR_CPUS) -# define NUM_RCU_LVL_3 0 -# define NUM_RCU_LVL_4 0 +# define NUM_RCU_NODES (NUM_RCU_LVL_0 + NUM_RCU_LVL_1)# define NUM_RCU_LVL_INIT { NUM_RCU_LVL_0, NUM_RCU_LVL_1 }# define RCU_NODE_NAME_INIT { "rcu_node_0", "rcu_node_1" }# define RCU_FQS_NAME_INIT { "rcu_node_fqs_0", "rcu_node_fqs_1" }
@@ -86,8 +81,7 @@# define NUM_RCU_LVL_0 1# define NUM_RCU_LVL_1 DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_2)# define NUM_RCU_LVL_2 DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_1) -# define NUM_RCU_LVL_3 (NR_CPUS) -# define NUM_RCU_LVL_4 0 +# define NUM_RCU_NODES (NUM_RCU_LVL_0 + NUM_RCU_LVL_1 + NUM_RCU_LVL_2)# define NUM_RCU_LVL_INIT { NUM_RCU_LVL_0, NUM_RCU_LVL_1, NUM_RCU_LVL_2 }# define RCU_NODE_NAME_INIT { "rcu_node_0", "rcu_node_1", "rcu_node_2" }# define RCU_FQS_NAME_INIT { "rcu_node_fqs_0", "rcu_node_fqs_1", "rcu_node_fqs_2" }
@@ -97,7 +91,7 @@# define NUM_RCU_LVL_1 DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_3)# define NUM_RCU_LVL_2 DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_2)# define NUM_RCU_LVL_3 DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_1) -# define NUM_RCU_LVL_4 (NR_CPUS) +# define NUM_RCU_NODES (NUM_RCU_LVL_0 + NUM_RCU_LVL_1 + NUM_RCU_LVL_2 + NUM_RCU_LVL_3)# define NUM_RCU_LVL_INIT { NUM_RCU_LVL_0, NUM_RCU_LVL_1, NUM_RCU_LVL_2, NUM_RCU_LVL_3 }# define RCU_NODE_NAME_INIT { "rcu_node_0", "rcu_node_1", "rcu_node_2", "rcu_node_3" }# define RCU_FQS_NAME_INIT { "rcu_node_fqs_0", "rcu_node_fqs_1", "rcu_node_fqs_2", "rcu_node_fqs_3" }
@@ -105,9 +99,6 @@# error "CONFIG_RCU_FANOUT insufficient for NR_CPUS"#endif /* #if (NR_CPUS) <= RCU_FANOUT_1 */ -#define RCU_SUM (NUM_RCU_LVL_0 + NUM_RCU_LVL_1 + NUM_RCU_LVL_2 + NUM_RCU_LVL_3 + NUM_RCU_LVL_4) -#define NUM_RCU_NODES (RCU_SUM - NR_CPUS) -extern int rcu_num_lvls;extern int rcu_num_nodes;
kernel/rcu/tree_plugin.h +2 -2
@@ -84,8 +84,8 @@ static void __init rcu_bootup_announce_oddness(void)pr_info ("\tRCU torture testing starts during boot.\n" );if (IS_ENABLED (CONFIG_RCU_CPU_STALL_INFO ))pr_info ("\tAdditional per-CPU info printed with stalls.\n" ); -if (NUM_RCU_LVL_4 !=0 ) -pr_info ("\tFour-level hierarchy is enabled.\n" ); +if (RCU_NUM_LVLS >=4 ) +pr_info ("\tFour(or more)-level hierarchy is enabled.\n" );if (RCU_FANOUT_LEAF !=16 )pr_info ("\tBuild-time adjustment of leaf fanout to %d.\n" ,RCU_FANOUT_LEAF );
Signature · 1 line
1.8.3.1
Quoted 12 lines · Alexander Gordeev
Hello Paul,
This is 3rd attempt to make RCU tree initialization bit more clear and optimize memory footprint of data associated with the tree.
Changes since v2:
- patch 1 fixed to avoid a panic in casercu_fanout_leafis out of bounds;Changes since v1:
- patch 3 fixed to accomodate nr_cpus=1, otherwisercu_num_lvls
Quoted 8 lines
would yield zero, which is wrong;The series is against "linux-rcu" tree "rcu/dev" branch
Thanks!
Cc "Paul E. McKenney" <[email protected]>Cc Steven Rostedt <[email protected]>
Queued for testing, replacing the earlier series, thank you!
Thanx, Paul
Quoted 19 lines
Alexander Gordeev (9):
rcu: Panic if RCU tree can not accommodate all CPUs
rcu: Remove superfluous local variable inrcu_init_geometry()
rcu: Cleanuprcu_init_geometry()code and arithmetics
rcu: Simplifyrcu_init_geometry()capacity arithmetics
rcu: Limit rcu_state::levelcnt[] toRCU_NUM_LVLSitems
rcu: Limit rcu_capacity[] size toRCU_NUM_LVLSitems
rcu: Remove unnecessary fields fromrcu_statestructure
rcu: Limit count of static data to the number of RCU levels
rcu: Simplify arithmetic to calculate number of RCU nodeskernel/rcu/tree.c | 109 +++++++++++++++++++++-------------------------- kernel/rcu/tree.h | 33 +++++++------- kernel/rcu/tree_plugin.h | 4 +- 3 files changed, 67 insertions(+), 79 deletions(-)Signature · 1 line
1.8.3.1