Skip to content

cpu alloc / cpu ops v3: Optimize per cpu access

Christoph Lameter linux-arch lkml 1 version In review

Get series with b4
b4 am [email protected]

Versions newest first

  1. v1 Latest41 patches 118 repliesIn review

Patches in v1 No applies recorded yet

#Subject and filesSizeRepliesApplied
1/41cpu_alloc: Increase percpu area size to 128kinclude/asm-ia64/page.h+1 -14 replies
2/41cpu alloc: The allocatorinclude/linux/percpu.h include/linux/vmstat.h mm/Kconfig +3 more+222 -223 replies
3/41cpu alloc: Use cpu allocator instead of the builtin modules per cpu allocatorarch/powerpc/kernel/setup_64.c arch/sparc64/kernel/smp.c arch/x86/kernel/setup.c +6 more+28 -1935 replies
4/41cpu ops: Core piece for generic atomic per cpu operationsinclude/linux/percpu.h+135 -035 replies
5/41cpu alloc: Percpu_counter conversionlib/percpu_counter.c+10 -122 replies
6/41cpu alloc: crash_notes conversionarch/ia64/kernel/crash.c drivers/base/cpu.c kernel/kexec.c+4 -40 replies
7/41cpu alloc: Workqueue conversionkernel/workqueue.c+21 -190 replies
8/41cpu alloc: ACPI cstate handling conversionarch/x86/kernel/acpi/cstate.c arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c drivers/acpi/processor_perflib.c+11 -90 replies
9/41cpu alloc: Genhd statistics conversioninclude/linux/genhd.h+25 -880 replies
10/41cpu alloc: blktrace conversionblock/blktrace.c+10 -140 replies
11/41cpu alloc: SRCU cpu alloc conversionkernel/rcutorture.c kernel/srcu.c+10 -140 replies
12/41cpu alloc: XFS counter conversion.fs/xfs/xfs_mount.c+8 -160 replies
13/41cpu alloc: NFS statisticsfs/nfs/iostat.h fs/nfs/super.c+12 -170 replies
14/41cpu alloc: Neigbour statisticsinclude/net/neighbour.h net/core/neighbour.c+7 -110 replies
15/41cpu_alloc: Convert ip route statisticsnet/ipv4/ip_input.c net/ipv4/route.c+4 -30 replies
16/41cpu alloc: Tcp statistics conversionnet/ipv4/tcp.c+5 -50 replies
17/41cpu alloc: Convert scratches to cpu allocnet/ipv4/ipcomp.c net/ipv6/ipcomp6.c+26 -260 replies
18/41cpu alloc: Dmaengine conversiondrivers/dma/dmaengine.c include/linux/dmaengine.h+20 -340 replies
19/41cpu alloc: Convert loopback statisticsdrivers/net/loopback.c+7 -80 replies
20/41cpu alloc: Veth conversiondrivers/net/veth.c+9 -140 replies
21/41cpu alloc: Chelsio statistics conversiondrivers/net/chelsio/sge.c+8 -110 replies
22/41cpu alloc: Convert network sockets inuse counternet/core/sock.c+4 -50 replies
23/41cpu alloc: Use it for infinibanddrivers/infiniband/hw/ehca/ehca_irq.c+11 -110 replies
24/41cpu alloc: Use in the crypto subsystem.crypto/async_tx/async_tx.c+9 -100 replies
25/41cpu alloc: scheduler: Convert cpuusage to cpu_alloc.kernel/sched.c+5 -50 replies
26/41cpu alloc: Convert mib handling to cpu allocinclude/net/ip.h include/net/snmp.h net/dccp/proto.c +5 more+47 -572 replies
27/41cpu alloc: Remove the allocpercpu functionalityinclude/linux/percpu.h mm/Makefile mm/allocpercpu.c+0 -2221 reply
28/41Module handling: Use CPU_xx ops to dynamically allocate countersinclude/linux/module.h kernel/module.c+16 -180 replies
29/41x86_64: Use CPU ops for nmi alert counterarch/x86/kernel/nmi_64.c+4 -40 replies
30/41Remove local_t supportDocumentation/local_ops.txt arch/frv/kernel/local.h include/asm-alpha/local.h +24 more+3 -15450 replies
31/41VM statistics: Use CPU opsinclude/linux/vmstat.h+4 -60 replies
32/41cpu alloc: Use in slubinclude/linux/slub_def.h mm/slub.c+34 -1650 replies
33/41cpu alloc: Remove slub fieldsinclude/linux/slub_def.h mm/slub.c+11 -300 replies
34/41cpu alloc: Page allocator conversionarch/x86/kernel/setup.c include/linux/gfp.h include/linux/mm.h +4 more+93 -1210 replies
35/41Support for CPU opsarch/ia64/Kconfig arch/ia64/kernel/perfmon.c arch/ia64/kernel/setup.c +6 more+138 -202 replies
36/41Zero based percpu: Infrastructure to rebase the per cpu area to zeroinclude/asm-generic/percpu.h include/asm-generic/sections.h include/asm-generic/vmlinux.lds.h +2 more+44 -30 replies
37/41x86_64: Fold pda into per cpu areaarch/x86/Kconfig arch/x86/kernel/setup.c arch/x86/kernel/smpboot.c +2 more+33 -280 replies
38/41x86: Extend percpu ops to 64 bitinclude/asm-x86/percpu.h+78 -50 replies
39/41x86: Replace cpu_pda() using percpu logic and get rid of _cpu_pda()arch/x86/kernel/head64.c arch/x86/kernel/irq_64.c arch/x86/kernel/nmi_64.c +6 more+35 -620 replies
40/41x86: Replace xxx_pda() operations with x86_xx_percpu().arch/x86/kernel/apic_64.c arch/x86/kernel/cpu/mcheck/mce_amd_64.c arch/x86/kernel/cpu/mcheck/mce_intel_64.c +12 more+37 -1240 replies
41/41x86_64: Support for cpu opsarch/x86/Kconfig include/asm-x86/percpu.h+35 -00 replies

Reviews trailers per patch

No Reviewed-by, Acked-by or Tested-by trailers for v1 yet.

Read the v1 thread

Cover letter [patch 00/41] cpu alloc / cpu ops v3: Optimize per cpu access

In various places the kernel maintains arrays of pointers indexed by processor numbers. These are used to locate objects that need to be used when executing on a specirfic processor. Both the slab allocator and the page allocator use these arrays and there the arrays are used in performance critical code. The allocpercpu functionality is a simple allocator to provide these arrays. However, there are certain drawbacks in using such arrays:

1. The arrays become huge for large systems and may be very sparsely populated (if they are dimensionied for NR_CPUS) on an architecture like IA64 that allows up to 4k cpus if a kernel is then booted on a machine that only supports 8 processors. We could nr_cpu_ids there but we would still have to allocate all possible processors up to the number of processor ids. cpu_alloc can deal with sparse cpu_maps.

2. The arrays cause surrounding variables to no longer fit into a single cacheline. The layout of core data structure is typically optimized so that variables frequently used together are placed in the same cacheline. Arrays of pointers move these variables far apart and destroy this effect.

3. A processor frequently follows only one pointer for its own use. Thus that cacheline with that pointer has to be kept in memory. The neighboring pointers are all to other processors that are rarely used. So a whole cacheline of 128 bytes may be consumed but only 8 bytes of information is constant use. It would be better to be able to place more information in this cacheline.

4. The lookup of the per cpu object is expensive and requires multiple memory accesses to:

A) smp_processor_id()
B) pointer to the base of the per cpu pointer array
C) pointer to the per cpu object in the pointer array
D) the per cpu object itself.

5. Each use of allocper requires its own per cpu array. On large system large arrays have to be allocated again and again.

6. Processor hotplug cannot effectively track the per cpu objects since the VM cannot find all memory that was allocated for a specific cpu. It is impossible to add or remove objects in a consistent way. Although the allocpercpu subsystem was extended to add that capability is not used since use would require adding cpu hotplug callbacks to each and every use of allocpercpu in the kernel.

The patchset here provides an cpu allocator that arranges data differently. Objects are placed tightly in linear areas reserved for each processor. The areas are of a fixed size so that address calculation can be used instead of a lookup. This means that

1. The VM knows where all the per cpu variables are and it could remove or add cpu areas as cpus come online or go offline.

2. There is only a single per cpu array that is used for the percpu area and all per cpu allocations.

3. The lookup of a per cpu object is easy and requires memory access to (worst case: architecture does not provide cpu ops):

A) per cpu offset from the per cpu pointer table (if its the current processor then there is usually some more efficient means of retrieving the offset)
B) cpu pointer to the object
C) the per cpu object itself.

4. Surrounding variables can be placed in the same cacheline. This allow f.e. in SLUB to avoid caching objects in per cpu structures since the kmem_cache structure is finally available without the need to access a cache cold cacheline.

5. A single pointer can be used regardless of the number of processors in the system.

The cpu allocator manages a fixed size data per cpu data area. The size can be configured as needed.

The current usage of the cpu area can be seen in the field

cpu_bytes

in /proc/vmstat

The patchset is agsinst 2.6.26-rc4.

There are two arch implementation of cpu ops provides.

1. x86. Another version of the zero based x86 patches exist by Mike.

2. IA64. Limited implementation since IA64 has no fast RMV ops. But we can avoid the addition of the my_cpu_offset in hotpaths.

This is a rather complex patchset and I am not sure how to merge it. Maybe it would be best to merge a piece at a time beginning with the basic infrastructure in the first few patches?