aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul E. McKenney <paulmck@linux.vnet.ibm.com>2017-03-14 15:42:30 -0400
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>2017-04-18 14:38:20 -0400
commitf2425b4efb0c69e77c0b9666b605ae4a1ecaae47 (patch)
tree01bf661bcaba584f013e151a10099b250425a21b
parent8660b7d8a545227fd9ee80508aa82528ea9947d7 (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.h102
-rw-r--r--kernel/rcu/tree.h71
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
99extern int rcu_num_lvls;
100extern 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
102extern int rcu_num_lvls;
103extern int rcu_num_nodes;
104 35
105/* 36/*
106 * Dynticks per-CPU state. 37 * Dynticks per-CPU state.