lkml.org 
[lkml]   [2017]   [Apr]   [17]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v2 tip/core/rcu 24/39] srcu: Move combining-tree definitions for SRCU's benefit
    Date
    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>
    ---
    include/linux/rcu_node_tree.h | 102 ++++++++++++++++++++++++++++++++++++++++++
    kernel/rcu/tree.h | 71 +----------------------------
    2 files changed, 103 insertions(+), 70 deletions(-)
    create mode 100644 include/linux/rcu_node_tree.h

    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 @@
    +/*
    + * RCU node combining tree definitions. These are used to compute
    + * global attributes while avoiding common-case global contention. A key
    + * property that these computations rely on is a tournament-style approach
    + * where only one of the tasks contending a lower level in the tree need
    + * advance to the next higher level. If properly configured, this allows
    + * unlimited scalability while maintaining a constant level of contention
    + * on the root node.
    + *
    + * This program is free software; you can redistribute it and/or modify
    + * it under the terms of the GNU General Public License as published by
    + * the Free Software Foundation; either version 2 of the License, or
    + * (at your option) any later version.
    + *
    + * This program is distributed in the hope that it will be useful,
    + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    + * GNU General Public License for more details.
    + *
    + * You should have received a copy of the GNU General Public License
    + * along with this program; if not, you can access it online at
    + * http://www.gnu.org/licenses/gpl-2.0.html.
    + *
    + * Copyright IBM Corporation, 2017
    + *
    + * Author: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
    + */
    +
    +#ifndef __LINUX_RCU_NODE_TREE_H
    +#define __LINUX_RCU_NODE_TREE_H
    +
    +/*
    + * Define shape of hierarchy based on NR_CPUS, CONFIG_RCU_FANOUT, and
    + * CONFIG_RCU_FANOUT_LEAF.
    + * In theory, it should be possible to add more levels straightforwardly.
    + * In practice, this did work well going from three levels to four.
    + * Of course, your mileage may vary.
    + */
    +
    +#ifdef CONFIG_RCU_FANOUT
    +#define RCU_FANOUT CONFIG_RCU_FANOUT
    +#else /* #ifdef CONFIG_RCU_FANOUT */
    +# ifdef CONFIG_64BIT
    +# define RCU_FANOUT 64
    +# else
    +# define RCU_FANOUT 32
    +# endif
    +#endif /* #else #ifdef CONFIG_RCU_FANOUT */
    +
    +#ifdef CONFIG_RCU_FANOUT_LEAF
    +#define RCU_FANOUT_LEAF CONFIG_RCU_FANOUT_LEAF
    +#else /* #ifdef CONFIG_RCU_FANOUT_LEAF */
    +#define RCU_FANOUT_LEAF 16
    +#endif /* #else #ifdef CONFIG_RCU_FANOUT_LEAF */
    +
    +#define RCU_FANOUT_1 (RCU_FANOUT_LEAF)
    +#define RCU_FANOUT_2 (RCU_FANOUT_1 * RCU_FANOUT)
    +#define RCU_FANOUT_3 (RCU_FANOUT_2 * RCU_FANOUT)
    +#define RCU_FANOUT_4 (RCU_FANOUT_3 * RCU_FANOUT)
    +
    +#if NR_CPUS <= RCU_FANOUT_1
    +# define RCU_NUM_LVLS 1
    +# define NUM_RCU_LVL_0 1
    +# 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" }
    +#elif NR_CPUS <= RCU_FANOUT_2
    +# 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_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" }
    +#elif NR_CPUS <= RCU_FANOUT_3
    +# define RCU_NUM_LVLS 3
    +# 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_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" }
    +#elif NR_CPUS <= RCU_FANOUT_4
    +# define RCU_NUM_LVLS 4
    +# define NUM_RCU_LVL_0 1
    +# 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_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" }
    +#else
    +# error "CONFIG_RCU_FANOUT insufficient for NR_CPUS"
    +#endif /* #if (NR_CPUS) <= RCU_FANOUT_1 */
    +
    +extern int rcu_num_lvls;
    +extern int rcu_num_nodes;
    +
    +#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 @@
    #include <linux/swait.h>
    #include <linux/stop_machine.h>
    #include <linux/rcu_segcblist.h>
    -
    -/*
    - * Define shape of hierarchy based on NR_CPUS, CONFIG_RCU_FANOUT, and
    - * CONFIG_RCU_FANOUT_LEAF.
    - * In theory, it should be possible to add more levels straightforwardly.
    - * In practice, this did work well going from three levels to four.
    - * Of course, your mileage may vary.
    - */
    -
    -#ifdef CONFIG_RCU_FANOUT
    -#define RCU_FANOUT CONFIG_RCU_FANOUT
    -#else /* #ifdef CONFIG_RCU_FANOUT */
    -# ifdef CONFIG_64BIT
    -# define RCU_FANOUT 64
    -# else
    -# define RCU_FANOUT 32
    -# endif
    -#endif /* #else #ifdef CONFIG_RCU_FANOUT */
    -
    -#ifdef CONFIG_RCU_FANOUT_LEAF
    -#define RCU_FANOUT_LEAF CONFIG_RCU_FANOUT_LEAF
    -#else /* #ifdef CONFIG_RCU_FANOUT_LEAF */
    -#define RCU_FANOUT_LEAF 16
    -#endif /* #else #ifdef CONFIG_RCU_FANOUT_LEAF */
    -
    -#define RCU_FANOUT_1 (RCU_FANOUT_LEAF)
    -#define RCU_FANOUT_2 (RCU_FANOUT_1 * RCU_FANOUT)
    -#define RCU_FANOUT_3 (RCU_FANOUT_2 * RCU_FANOUT)
    -#define RCU_FANOUT_4 (RCU_FANOUT_3 * RCU_FANOUT)
    -
    -#if NR_CPUS <= RCU_FANOUT_1
    -# define RCU_NUM_LVLS 1
    -# define NUM_RCU_LVL_0 1
    -# 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" }
    -#elif NR_CPUS <= RCU_FANOUT_2
    -# 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_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" }
    -#elif NR_CPUS <= RCU_FANOUT_3
    -# define RCU_NUM_LVLS 3
    -# 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_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" }
    -#elif NR_CPUS <= RCU_FANOUT_4
    -# define RCU_NUM_LVLS 4
    -# define NUM_RCU_LVL_0 1
    -# 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_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" }
    -#else
    -# error "CONFIG_RCU_FANOUT insufficient for NR_CPUS"
    -#endif /* #if (NR_CPUS) <= RCU_FANOUT_1 */
    -
    -extern int rcu_num_lvls;
    -extern int rcu_num_nodes;
    +#include <linux/rcu_node_tree.h>

    /*
    * Dynticks per-CPU state.
    --
    2.5.2
    \
     
     \ /
      Last update: 2017-04-18 01:51    [W:3.653 / U:0.244 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site