Anton noticed (http://www.spinics.net/lists/linux-mm/msg67489.html) that
on ppc LPARs with memoryless nodes, a large amount of memory was
consumed by slabs and was marked unreclaimable. He tracked it down to
slab deactivations in the SLUB core when we allocate remotely, leading
to poor efficiency always when memoryless nodes are present.
After much discussion, Joonsoo provided a few patches that help
significantly. They don't resolve the problem altogether:
- memory hotplug still needs testing, that is when a memoryless node
becomes memory-ful, we want to dtrt
- there are other reasons for going off-node than memoryless nodes,
e.g., fully exhausted local nodes
Neither case is resolved with this series, but I don't think that should
block their acceptance, as they can be explored/resolved with follow-on
patches.
The series consists of:
[1/4] topology: add support for node_to_mem_node() to determine the fallback node
[2/4] slub: fallback to node_to_mem_node() node if allocating on memoryless node
- Joonsoo's patches to cache the nearest node with memory for each
NUMA node
[3/4] Partial revert of 81c98869faa5 (""kthread: ensure locality of task_struct allocations")
- At Tejun's request, keep the knowledge of memoryless node fallback to
the allocator core.
[4/4] powerpc: reorder per-cpu NUMA information's initialization
- Fix what appears to be a bug with when the NUMA topology information
is stored in the powerpc initialization code.
arch/powerpc/kernel/smp.c | 12 ++++++------
arch/powerpc/mm/numa.c | 13 ++++++++++---
include/linux/topology.h | 17 +++++++++++++++++
kernel/kthread.c | 2 +-
mm/page_alloc.c | 1 +
mm/slub.c | 24 ++++++++++++++++++------
6 files changed, 53 insertions(+), 16 deletions(-)
From: Joonsoo Kim <redacted>
We need to determine the fallback node in slub allocator if the
allocation target node is memoryless node. Without it, the SLUB wrongly
select the node which has no memory and can't use a partial slab,
because of node mismatch. Introduced function, node_to_mem_node(X), will
return a node Y with memory that has the nearest distance. If X is
memoryless node, it will return nearest distance node, but, if X is
normal node, it will return itself.
We will use this function in following patch to determine the fallback
node.
Signed-off-by: Joonsoo Kim <redacted>
Signed-off-by: Nishanth Aravamudan <redacted>
Cc: David Rientjes <rientjes@google.com>
Cc: Han Pingtian <redacted>
Cc: Pekka Enberg <penberg@kernel.org>
Cc: Paul Mackerras <redacted>
Cc: Anton Blanchard <redacted>
Cc: Matt Mackall <redacted>
Cc: Christoph Lameter <redacted>
Cc: Wanpeng Li <redacted>
Cc: Tejun Heo <tj@kernel.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Linux Memory Management List <redacted>
Cc: linuxppc-dev@lists.ozlabs.org
---
v2 -> v3 (Nishanth):
Fix declaration and definition of _node_numa_mem_.
s/node_numa_mem/node_to_mem_node/ as suggested by David Rientjes.
From: Joonsoo Kim <redacted>
Update the SLUB code to search for partial slabs on the nearest node
with memory in the presence of memoryless nodes. Additionally, do not
consider it to be an ALLOC_NODE_MISMATCH (and deactivate the slab) when
a memoryless-node specified allocation goes off-node.
Signed-off-by: Joonsoo Kim <redacted>
Signed-off-by: Nishanth Aravamudan <redacted>
---
v1 -> v2 (Nishanth):
Add commit message
Clean-up conditions in get_partial()
After discussions with Tejun, we don't want to spread the use of
cpu_to_mem() (and thus knowledge of allocators/NUMA topology details)
into callers, but would rather ensure the callees correctly handle
memoryless nodes. With the previous patches ("topology: add support for
node_to_mem_node() to determine the fallback node" and "slub: fallback
to node_to_mem_node() node if allocating on memoryless node") adding and
using node_to_mem_node(), we can safely undo part of the change to the
kthread logic from 81c98869faa5 ("kthread: ensure locality of
task_struct allocations").
Signed-off-by: Nishanth Aravamudan <redacted>
There is an issue currently where NUMA information is used on powerpc
(and possibly ia64) before it has been read from the device-tree, which
leads to large slab consumption with CONFIG_SLUB and memoryless nodes.
NUMA powerpc non-boot CPU's cpu_to_node/cpu_to_mem is only accurate
after start_secondary(), similar to ia64, which is invoked via
smp_init().
Commit 6ee0578b4daae ("workqueue: mark init_workqueues() as
early_initcall()") made init_workqueues() be invoked via
do_pre_smp_initcalls(), which is obviously before the secondary
processors are online.
Additionally, the following commits changed init_workqueues() to use
cpu_to_node to determine the node to use for kthread_create_on_node:
bce903809ab3f ("workqueue: add wq_numa_tbl_len and
wq_numa_possible_cpumask[]")
f3f90ad469342 ("workqueue: determine NUMA node of workers accourding to
the allowed cpumask")
Therefore, when init_workqueues() runs, it sees all CPUs as being on
Node 0. On LPARs or KVM guests where Node 0 is memoryless, this leads to
a high number of slab deactivations
(http://www.spinics.net/lists/linux-mm/msg67489.html).
While testing memoryless nodes on PowerKVM guests with a fix to the
workqueue logic to use cpu_to_mem() instead of cpu_to_node(), with a
guest topology:
available: 2 nodes (0-1)
node 0 cpus: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 2
node 0 size: 0 MB
node 0 free: 0 MB
node 1 cpus: 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
node 1 size: 16336 MB
node 1 free: 15329 MB
node distances:
node 0 1
0: 10 40
1: 40 10
the slab consumption decreases from:
Slab: 932416 kB
SUnreclaim: 902336 kB
to
Slab: 395264 kB
SUnreclaim: 359424 kB
And we see a corresponding increase in the slab efficiency from:
slab mem objs slabs
used active active
------------------------------------------------------------
kmalloc-16384 337 MB 11.28% 100.00%
task_struct 288 MB 9.93% 100.00%
to:
slab mem objs slabs
used active active
------------------------------------------------------------
kmalloc-16384 37 MB 100.00% 100.00%
task_struct 31 MB 100.00% 100.00%
Powerpc didn't support memoryless nodes until recently (64bb80d87f01
"powerpc/numa: Enable CONFIG_HAVE_MEMORYLESS_NODES" and 8c272261194d
"powerpc/numa: Enable USE_PERCPU_NUMA_NODE_ID"). Those commits also
helped improve memory consumption with these kind of environments.
Signed-off-by: Nishanth Aravamudan <redacted>
---
Ben & others, one area I'm still unsure of is if calling the NUMA
callback for all CPUs is desired. I don't know how else to get the NUMA
topology into the array easily, but I didn't test in an environment with
hotpluggable CPUs, so I'm not sure if it will lead to errors there (are
there device-tree entries for the topology of CPUs that will be plugged
in? I assume not, actually, so maybe we should keep the logic in
start_secondary so that those CPUs that are hotplugged later get the
right topology data?
From: Christoph Lameter <hidden> Date: 2014-08-14 14:35:42
On Wed, 13 Aug 2014, Nishanth Aravamudan wrote:
quoted hunk
+++ b/include/linux/topology.h
@@ -119,11 +119,20 @@ static inline int numa_node_id(void)*Usetheaccessorfunctionsset_numa_mem(),numa_mem_id()andcpu_to_mem().*/DECLARE_PER_CPU(int,_numa_mem_);+externint_node_numa_mem_[MAX_NUMNODES];
Why are these variables starting with an _ ?
Maybe _numa_mem was defined that way because it is typically not defined.
We dont do this in other situations.
On 14.08.2014 [09:35:37 -0500], Christoph Lameter wrote:
On Wed, 13 Aug 2014, Nishanth Aravamudan wrote:
quoted
+++ b/include/linux/topology.h
@@ -119,11 +119,20 @@ static inline int numa_node_id(void)*Usetheaccessorfunctionsset_numa_mem(),numa_mem_id()andcpu_to_mem().*/DECLARE_PER_CPU(int,_numa_mem_);+externint_node_numa_mem_[MAX_NUMNODES];
Why are these variables starting with an _ ?
Maybe _numa_mem was defined that way because it is typically not defined.
We dont do this in other situations.
That's how it was in Joonsoo's patch and I was trying to minimize the
changes from his version (beyond making it compile). I can of course
update it to not have a prefixing _ if that's preferred.
Thanks,
Nish
On 13.08.2014 [17:13:01 -0700], Nishanth Aravamudan wrote:
Anton noticed (http://www.spinics.net/lists/linux-mm/msg67489.html) that
on ppc LPARs with memoryless nodes, a large amount of memory was
consumed by slabs and was marked unreclaimable. He tracked it down to
slab deactivations in the SLUB core when we allocate remotely, leading
to poor efficiency always when memoryless nodes are present.
After much discussion, Joonsoo provided a few patches that help
significantly. They don't resolve the problem altogether:
- memory hotplug still needs testing, that is when a memoryless node
becomes memory-ful, we want to dtrt
- there are other reasons for going off-node than memoryless nodes,
e.g., fully exhausted local nodes
Neither case is resolved with this series, but I don't think that should
block their acceptance, as they can be explored/resolved with follow-on
patches.
The series consists of:
[1/4] topology: add support for node_to_mem_node() to determine the fallback node
[2/4] slub: fallback to node_to_mem_node() node if allocating on memoryless node
- Joonsoo's patches to cache the nearest node with memory for each
NUMA node
[3/4] Partial revert of 81c98869faa5 (""kthread: ensure locality of task_struct allocations")
- At Tejun's request, keep the knowledge of memoryless node fallback to
the allocator core.
[4/4] powerpc: reorder per-cpu NUMA information's initialization
- Fix what appears to be a bug with when the NUMA topology information
is stored in the powerpc initialization code.
Andrew & others,
I know kernel summit is going on, so I'll be patient, but was just
curious if anyone had any further comments other than Christoph's on the
naming.
Thanks,
Nish
Hi Christoph,
On 14.08.2014 [13:06:56 -0700], Nishanth Aravamudan wrote:
On 14.08.2014 [09:35:37 -0500], Christoph Lameter wrote:
quoted
On Wed, 13 Aug 2014, Nishanth Aravamudan wrote:
quoted
+++ b/include/linux/topology.h
@@ -119,11 +119,20 @@ static inline int numa_node_id(void)*Usetheaccessorfunctionsset_numa_mem(),numa_mem_id()andcpu_to_mem().*/DECLARE_PER_CPU(int,_numa_mem_);+externint_node_numa_mem_[MAX_NUMNODES];
Why are these variables starting with an _ ?
Maybe _numa_mem was defined that way because it is typically not defined.
We dont do this in other situations.
That's how it was in Joonsoo's patch and I was trying to minimize the
changes from his version (beyond making it compile). I can of course
update it to not have a prefixing _ if that's preferred.
Upon reflection, did you mean all of these variables? Would you rather I
submitted a follow-on patch that removed the prefix _? Note that
_node_numa_mem_ is also not defined if !MEMORYLESS_NODES.
-Nish