Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

/proc/meminfo: add percpu populated pages count

Currently, percpu memory only exposes allocation and utilization
information via debugfs. This more or less is only really useful for
understanding the fragmentation and allocation information at a per-chunk
level with a few global counters. This is also gated behind a config.
BPF and cgroup, for example, have seen an increase in use causing
increased use of percpu memory. Let's make it easier for someone to
identify how much memory is being used.

This patch adds the "Percpu" stat to meminfo to more easily look up how
much percpu memory is in use. This number includes the cost for all
allocated backing pages and not just insight at the per a unit, per chunk
level. Metadata is excluded. I think excluding metadata is fair because
the backing memory scales with the numbere of cpus and can quickly
outweigh the metadata. It also makes this calculation light.

Link: http://lkml.kernel.org/r/20180807184723.74919-1-dennisszhou@gmail.com
Signed-off-by: Dennis Zhou <dennisszhou@gmail.com>
Acked-by: Tejun Heo <tj@kernel.org>
Acked-by: Roman Gushchin <guro@fb.com>
Reviewed-by: Andrew Morton <akpm@linux-foundation.org>
Acked-by: David Rientjes <rientjes@google.com>
Acked-by: Vlastimil Babka <vbabka@suse.cz>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Christoph Lameter <cl@linux.com>
Cc: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Dennis Zhou (Facebook) and committed by
Linus Torvalds
7e8a6304 3d8b38eb

+36
+3
Documentation/filesystems/proc.txt
··· 870 870 VmallocTotal: 112216 kB 871 871 VmallocUsed: 428 kB 872 872 VmallocChunk: 111088 kB 873 + Percpu: 62080 kB 873 874 HardwareCorrupted: 0 kB 874 875 AnonHugePages: 49152 kB 875 876 ShmemHugePages: 0 kB ··· 963 962 VmallocTotal: total size of vmalloc memory area 964 963 VmallocUsed: amount of vmalloc area which is used 965 964 VmallocChunk: largest contiguous block of vmalloc area which is free 965 + Percpu: Memory allocated to the percpu allocator used to back percpu 966 + allocations. This stat excludes the cost of metadata. 966 967 967 968 .............................................................................. 968 969
+2
fs/proc/meminfo.c
··· 7 7 #include <linux/mman.h> 8 8 #include <linux/mmzone.h> 9 9 #include <linux/proc_fs.h> 10 + #include <linux/percpu.h> 10 11 #include <linux/quicklist.h> 11 12 #include <linux/seq_file.h> 12 13 #include <linux/swap.h> ··· 122 121 (unsigned long)VMALLOC_TOTAL >> 10); 123 122 show_val_kb(m, "VmallocUsed: ", 0ul); 124 123 show_val_kb(m, "VmallocChunk: ", 0ul); 124 + show_val_kb(m, "Percpu: ", pcpu_nr_pages()); 125 125 126 126 #ifdef CONFIG_MEMORY_FAILURE 127 127 seq_printf(m, "HardwareCorrupted: %5lu kB\n",
+2
include/linux/percpu.h
··· 149 149 (typeof(type) __percpu *)__alloc_percpu(sizeof(type), \ 150 150 __alignof__(type)) 151 151 152 + extern unsigned long pcpu_nr_pages(void); 153 + 152 154 #endif /* __LINUX_PERCPU_H */
+29
mm/percpu.c
··· 170 170 int pcpu_nr_empty_pop_pages; 171 171 172 172 /* 173 + * The number of populated pages in use by the allocator, protected by 174 + * pcpu_lock. This number is kept per a unit per chunk (i.e. when a page gets 175 + * allocated/deallocated, it is allocated/deallocated in all units of a chunk 176 + * and increments/decrements this count by 1). 177 + */ 178 + static unsigned long pcpu_nr_populated; 179 + 180 + /* 173 181 * Balance work is used to populate or destroy chunks asynchronously. We 174 182 * try to keep the number of populated free pages between 175 183 * PCPU_EMPTY_POP_PAGES_LOW and HIGH for atomic allocations and at most one ··· 1240 1232 1241 1233 bitmap_set(chunk->populated, page_start, nr); 1242 1234 chunk->nr_populated += nr; 1235 + pcpu_nr_populated += nr; 1243 1236 1244 1237 if (!for_alloc) { 1245 1238 chunk->nr_empty_pop_pages += nr; ··· 1269 1260 chunk->nr_populated -= nr; 1270 1261 chunk->nr_empty_pop_pages -= nr; 1271 1262 pcpu_nr_empty_pop_pages -= nr; 1263 + pcpu_nr_populated -= nr; 1272 1264 } 1273 1265 1274 1266 /* ··· 2186 2176 pcpu_nr_empty_pop_pages = pcpu_first_chunk->nr_empty_pop_pages; 2187 2177 pcpu_chunk_relocate(pcpu_first_chunk, -1); 2188 2178 2179 + /* include all regions of the first chunk */ 2180 + pcpu_nr_populated += PFN_DOWN(size_sum); 2181 + 2189 2182 pcpu_stats_chunk_alloc(); 2190 2183 trace_percpu_create_chunk(base_addr); 2191 2184 ··· 2757 2744 } 2758 2745 2759 2746 #endif /* CONFIG_SMP */ 2747 + 2748 + /* 2749 + * pcpu_nr_pages - calculate total number of populated backing pages 2750 + * 2751 + * This reflects the number of pages populated to back chunks. Metadata is 2752 + * excluded in the number exposed in meminfo as the number of backing pages 2753 + * scales with the number of cpus and can quickly outweigh the memory used for 2754 + * metadata. It also keeps this calculation nice and simple. 2755 + * 2756 + * RETURNS: 2757 + * Total number of populated backing pages in use by the allocator. 2758 + */ 2759 + unsigned long pcpu_nr_pages(void) 2760 + { 2761 + return pcpu_nr_populated * pcpu_nr_units; 2762 + } 2760 2763 2761 2764 /* 2762 2765 * Percpu allocator is initialized early during boot when neither slab or