diff options
author | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2017-03-14 15:42:30 -0400 |
---|---|---|
committer | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2017-04-18 14:38:20 -0400 |
commit | f2425b4efb0c69e77c0b9666b605ae4a1ecaae47 (patch) | |
tree | 01bf661bcaba584f013e151a10099b250425a21b | |
parent | 8660b7d8a545227fd9ee80508aa82528ea9947d7 (diff) |
srcu: Move combining-tree definitions for SRCU's benefit
This commit moves the C preprocessor code that defines the default shape
of the rcu_node combining tree to a new include/linux/rcu_node_tree.h
file as a first step towards enabling SRCU to create its own combining
tree, which in turn enables SRCU to implement per-CPU callback handling,
thus avoiding contention on the lock currently guarding the single list
of callbacks. Note that users of SRCU still need to know the size of
the srcu_struct structure, hence include/linux rather than kernel/rcu.
This commit is code-movement only.
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
-rw-r--r-- | include/linux/rcu_node_tree.h | 102 | ||||
-rw-r--r-- | kernel/rcu/tree.h | 71 |
2 files changed, 103 insertions, 70 deletions
diff --git a/include/linux/rcu_node_tree.h b/include/linux/rcu_node_tree.h new file mode 100644 index 000000000000..b7eb97096b1c --- /dev/null +++ b/include/linux/rcu_node_tree.h | |||
@@ -0,0 +1,102 @@ | |||
1 | /* | ||
2 | * RCU node combining tree definitions. These are used to compute | ||
3 | * global attributes while avoiding common-case global contention. A key | ||
4 | * property that these computations rely on is a tournament-style approach | ||
5 | * where only one of the tasks contending a lower level in the tree need | ||
6 | * advance to the next higher level. If properly configured, this allows | ||
7 | * unlimited scalability while maintaining a constant level of contention | ||
8 | * on the root node. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, you can access it online at | ||
22 | * http://www.gnu.org/licenses/gpl-2.0.html. | ||
23 | * | ||
24 | * Copyright IBM Corporation, 2017 | ||
25 | * | ||
26 | * Author: Paul E. McKenney <paulmck@linux.vnet.ibm.com> | ||
27 | */ | ||
28 | |||
29 | #ifndef __LINUX_RCU_NODE_TREE_H | ||
30 | #define __LINUX_RCU_NODE_TREE_H | ||
31 | |||
32 | /* | ||
33 | * Define shape of hierarchy based on NR_CPUS, CONFIG_RCU_FANOUT, and | ||
34 | * CONFIG_RCU_FANOUT_LEAF. | ||
35 | * In theory, it should be possible to add more levels straightforwardly. | ||
36 | * In practice, this did work well going from three levels to four. | ||
37 | * Of course, your mileage may vary. | ||
38 | */ | ||
39 | |||
40 | #ifdef CONFIG_RCU_FANOUT | ||
41 | #define RCU_FANOUT CONFIG_RCU_FANOUT | ||
42 | #else /* #ifdef CONFIG_RCU_FANOUT */ | ||
43 | # ifdef CONFIG_64BIT | ||
44 | # define RCU_FANOUT 64 | ||
45 | # else | ||
46 | # define RCU_FANOUT 32 | ||
47 | # endif | ||
48 | #endif /* #else #ifdef CONFIG_RCU_FANOUT */ | ||
49 | |||
50 | #ifdef CONFIG_RCU_FANOUT_LEAF | ||
51 | #define RCU_FANOUT_LEAF CONFIG_RCU_FANOUT_LEAF | ||
52 | #else /* #ifdef CONFIG_RCU_FANOUT_LEAF */ | ||
53 | #define RCU_FANOUT_LEAF 16 | ||
54 | #endif /* #else #ifdef CONFIG_RCU_FANOUT_LEAF */ | ||
55 | |||
56 | #define RCU_FANOUT_1 (RCU_FANOUT_LEAF) | ||
57 | #define RCU_FANOUT_2 (RCU_FANOUT_1 * RCU_FANOUT) | ||
58 | #define RCU_FANOUT_3 (RCU_FANOUT_2 * RCU_FANOUT) | ||
59 | #define RCU_FANOUT_4 (RCU_FANOUT_3 * RCU_FANOUT) | ||
60 | |||
61 | #if NR_CPUS <= RCU_FANOUT_1 | ||
62 | # define RCU_NUM_LVLS 1 | ||
63 | # define NUM_RCU_LVL_0 1 | ||
64 | # define NUM_RCU_NODES NUM_RCU_LVL_0 | ||
65 | # define NUM_RCU_LVL_INIT { NUM_RCU_LVL_0 } | ||
66 | # define RCU_NODE_NAME_INIT { "rcu_node_0" } | ||
67 | # define RCU_FQS_NAME_INIT { "rcu_node_fqs_0" } | ||
68 | #elif NR_CPUS <= RCU_FANOUT_2 | ||
69 | # define RCU_NUM_LVLS 2 | ||
70 | # define NUM_RCU_LVL_0 1 | ||
71 | # define NUM_RCU_LVL_1 DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_1) | ||
72 | # define NUM_RCU_NODES (NUM_RCU_LVL_0 + NUM_RCU_LVL_1) | ||
73 | # define NUM_RCU_LVL_INIT { NUM_RCU_LVL_0, NUM_RCU_LVL_1 } | ||
74 | # define RCU_NODE_NAME_INIT { "rcu_node_0", "rcu_node_1" } | ||
75 | # define RCU_FQS_NAME_INIT { "rcu_node_fqs_0", "rcu_node_fqs_1" } | ||
76 | #elif NR_CPUS <= RCU_FANOUT_3 | ||
77 | # define RCU_NUM_LVLS 3 | ||
78 | # define NUM_RCU_LVL_0 1 | ||
79 | # define NUM_RCU_LVL_1 DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_2) | ||
80 | # define NUM_RCU_LVL_2 DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_1) | ||
81 | # define NUM_RCU_NODES (NUM_RCU_LVL_0 + NUM_RCU_LVL_1 + NUM_RCU_LVL_2) | ||
82 | # define NUM_RCU_LVL_INIT { NUM_RCU_LVL_0, NUM_RCU_LVL_1, NUM_RCU_LVL_2 } | ||
83 | # define RCU_NODE_NAME_INIT { "rcu_node_0", "rcu_node_1", "rcu_node_2" } | ||
84 | # define RCU_FQS_NAME_INIT { "rcu_node_fqs_0", "rcu_node_fqs_1", "rcu_node_fqs_2" } | ||
85 | #elif NR_CPUS <= RCU_FANOUT_4 | ||
86 | # define RCU_NUM_LVLS 4 | ||
87 | # define NUM_RCU_LVL_0 1 | ||
88 | # define NUM_RCU_LVL_1 DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_3) | ||
89 | # define NUM_RCU_LVL_2 DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_2) | ||
90 | # define NUM_RCU_LVL_3 DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_1) | ||
91 | # define NUM_RCU_NODES (NUM_RCU_LVL_0 + NUM_RCU_LVL_1 + NUM_RCU_LVL_2 + NUM_RCU_LVL_3) | ||
92 | # define NUM_RCU_LVL_INIT { NUM_RCU_LVL_0, NUM_RCU_LVL_1, NUM_RCU_LVL_2, NUM_RCU_LVL_3 } | ||
93 | # define RCU_NODE_NAME_INIT { "rcu_node_0", "rcu_node_1", "rcu_node_2", "rcu_node_3" } | ||
94 | # define RCU_FQS_NAME_INIT { "rcu_node_fqs_0", "rcu_node_fqs_1", "rcu_node_fqs_2", "rcu_node_fqs_3" } | ||
95 | #else | ||
96 | # error "CONFIG_RCU_FANOUT insufficient for NR_CPUS" | ||
97 | #endif /* #if (NR_CPUS) <= RCU_FANOUT_1 */ | ||
98 | |||
99 | extern int rcu_num_lvls; | ||
100 | extern int rcu_num_nodes; | ||
101 | |||
102 | #endif /* __LINUX_RCU_NODE_TREE_H */ | ||
diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h index 4f62651588ea..1bec3958d44f 100644 --- a/kernel/rcu/tree.h +++ b/kernel/rcu/tree.h | |||
@@ -31,76 +31,7 @@ | |||
31 | #include <linux/swait.h> | 31 | #include <linux/swait.h> |
32 | #include <linux/stop_machine.h> | 32 | #include <linux/stop_machine.h> |
33 | #include <linux/rcu_segcblist.h> | 33 | #include <linux/rcu_segcblist.h> |
34 | 34 | #include <linux/rcu_node_tree.h> | |
35 | /* | ||
36 | * Define shape of hierarchy based on NR_CPUS, CONFIG_RCU_FANOUT, and | ||
37 | * CONFIG_RCU_FANOUT_LEAF. | ||
38 | * In theory, it should be possible to add more levels straightforwardly. | ||
39 | * In practice, this did work well going from three levels to four. | ||
40 | * Of course, your mileage may vary. | ||
41 | */ | ||
42 | |||
43 | #ifdef CONFIG_RCU_FANOUT | ||
44 | #define RCU_FANOUT CONFIG_RCU_FANOUT | ||
45 | #else /* #ifdef CONFIG_RCU_FANOUT */ | ||
46 | # ifdef CONFIG_64BIT | ||
47 | # define RCU_FANOUT 64 | ||
48 | # else | ||
49 | # define RCU_FANOUT 32 | ||
50 | # endif | ||
51 | #endif /* #else #ifdef CONFIG_RCU_FANOUT */ | ||
52 | |||
53 | #ifdef CONFIG_RCU_FANOUT_LEAF | ||
54 | #define RCU_FANOUT_LEAF CONFIG_RCU_FANOUT_LEAF | ||
55 | #else /* #ifdef CONFIG_RCU_FANOUT_LEAF */ | ||
56 | #define RCU_FANOUT_LEAF 16 | ||
57 | #endif /* #else #ifdef CONFIG_RCU_FANOUT_LEAF */ | ||
58 | |||
59 | #define RCU_FANOUT_1 (RCU_FANOUT_LEAF) | ||
60 | #define RCU_FANOUT_2 (RCU_FANOUT_1 * RCU_FANOUT) | ||
61 | #define RCU_FANOUT_3 (RCU_FANOUT_2 * RCU_FANOUT) | ||
62 | #define RCU_FANOUT_4 (RCU_FANOUT_3 * RCU_FANOUT) | ||
63 | |||
64 | #if NR_CPUS <= RCU_FANOUT_1 | ||
65 | # define RCU_NUM_LVLS 1 | ||
66 | # define NUM_RCU_LVL_0 1 | ||
67 | # define NUM_RCU_NODES NUM_RCU_LVL_0 | ||
68 | # define NUM_RCU_LVL_INIT { NUM_RCU_LVL_0 } | ||
69 | # define RCU_NODE_NAME_INIT { "rcu_node_0" } | ||
70 | # define RCU_FQS_NAME_INIT { "rcu_node_fqs_0" } | ||
71 | #elif NR_CPUS <= RCU_FANOUT_2 | ||
72 | # define RCU_NUM_LVLS 2 | ||
73 | # define NUM_RCU_LVL_0 1 | ||
74 | # define NUM_RCU_LVL_1 DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_1) | ||
75 | # define NUM_RCU_NODES (NUM_RCU_LVL_0 + NUM_RCU_LVL_1) | ||
76 | # define NUM_RCU_LVL_INIT { NUM_RCU_LVL_0, NUM_RCU_LVL_1 } | ||
77 | # define RCU_NODE_NAME_INIT { "rcu_node_0", "rcu_node_1" } | ||
78 | # define RCU_FQS_NAME_INIT { "rcu_node_fqs_0", "rcu_node_fqs_1" } | ||
79 | #elif NR_CPUS <= RCU_FANOUT_3 | ||
80 | # define RCU_NUM_LVLS 3 | ||
81 | # define NUM_RCU_LVL_0 1 | ||
82 | # define NUM_RCU_LVL_1 DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_2) | ||
83 | # define NUM_RCU_LVL_2 DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_1) | ||
84 | # define NUM_RCU_NODES (NUM_RCU_LVL_0 + NUM_RCU_LVL_1 + NUM_RCU_LVL_2) | ||
85 | # define NUM_RCU_LVL_INIT { NUM_RCU_LVL_0, NUM_RCU_LVL_1, NUM_RCU_LVL_2 } | ||
86 | # define RCU_NODE_NAME_INIT { "rcu_node_0", "rcu_node_1", "rcu_node_2" } | ||
87 | # define RCU_FQS_NAME_INIT { "rcu_node_fqs_0", "rcu_node_fqs_1", "rcu_node_fqs_2" } | ||
88 | #elif NR_CPUS <= RCU_FANOUT_4 | ||
89 | # define RCU_NUM_LVLS 4 | ||
90 | # define NUM_RCU_LVL_0 1 | ||
91 | # define NUM_RCU_LVL_1 DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_3) | ||
92 | # define NUM_RCU_LVL_2 DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_2) | ||
93 | # define NUM_RCU_LVL_3 DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_1) | ||
94 | # define NUM_RCU_NODES (NUM_RCU_LVL_0 + NUM_RCU_LVL_1 + NUM_RCU_LVL_2 + NUM_RCU_LVL_3) | ||
95 | # define NUM_RCU_LVL_INIT { NUM_RCU_LVL_0, NUM_RCU_LVL_1, NUM_RCU_LVL_2, NUM_RCU_LVL_3 } | ||
96 | # define RCU_NODE_NAME_INIT { "rcu_node_0", "rcu_node_1", "rcu_node_2", "rcu_node_3" } | ||
97 | # define RCU_FQS_NAME_INIT { "rcu_node_fqs_0", "rcu_node_fqs_1", "rcu_node_fqs_2", "rcu_node_fqs_3" } | ||
98 | #else | ||
99 | # error "CONFIG_RCU_FANOUT insufficient for NR_CPUS" | ||
100 | #endif /* #if (NR_CPUS) <= RCU_FANOUT_1 */ | ||
101 | |||
102 | extern int rcu_num_lvls; | ||
103 | extern int rcu_num_nodes; | ||
104 | 35 | ||
105 | /* | 36 | /* |
106 | * Dynticks per-CPU state. | 37 | * Dynticks per-CPU state. |