Blame view
mm/percpu-stats.c
5.66 KB
30a5b5367 percpu: expose st... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
/* * mm/percpu-debug.c * * Copyright (C) 2017 Facebook Inc. * Copyright (C) 2017 Dennis Zhou <dennisz@fb.com> * * This file is released under the GPLv2. * * Prints statistics about the percpu allocator and backing chunks. */ #include <linux/debugfs.h> #include <linux/list.h> #include <linux/percpu.h> #include <linux/seq_file.h> #include <linux/sort.h> #include <linux/vmalloc.h> #include "percpu-internal.h" #define P(X, Y) \ |
02459164a percpu: change th... |
21 22 |
seq_printf(m, " %-20s: %12lld ", X, (long long int)Y) |
30a5b5367 percpu: expose st... |
23 24 25 26 27 28 29 30 31 32 |
struct percpu_stats pcpu_stats; struct pcpu_alloc_info pcpu_stats_ai; static int cmpint(const void *a, const void *b) { return *(int *)a - *(int *)b; } /* |
40064aeca percpu: replace a... |
33 |
* Iterates over all chunks to find the max nr_alloc entries. |
30a5b5367 percpu: expose st... |
34 |
*/ |
40064aeca percpu: replace a... |
35 |
static int find_max_nr_alloc(void) |
30a5b5367 percpu: expose st... |
36 37 |
{ struct pcpu_chunk *chunk; |
40064aeca percpu: replace a... |
38 |
int slot, max_nr_alloc; |
30a5b5367 percpu: expose st... |
39 |
|
40064aeca percpu: replace a... |
40 |
max_nr_alloc = 0; |
30a5b5367 percpu: expose st... |
41 42 |
for (slot = 0; slot < pcpu_nr_slots; slot++) list_for_each_entry(chunk, &pcpu_slot[slot], list) |
40064aeca percpu: replace a... |
43 |
max_nr_alloc = max(max_nr_alloc, chunk->nr_alloc); |
30a5b5367 percpu: expose st... |
44 |
|
40064aeca percpu: replace a... |
45 |
return max_nr_alloc; |
30a5b5367 percpu: expose st... |
46 47 48 49 50 |
} /* * Prints out chunk state. Fragmentation is considered between * the beginning of the chunk to the last allocation. |
40064aeca percpu: replace a... |
51 52 |
* * All statistics are in bytes unless stated otherwise. |
30a5b5367 percpu: expose st... |
53 54 |
*/ static void chunk_map_stats(struct seq_file *m, struct pcpu_chunk *chunk, |
cd6a884d0 percpu: pcpu-stat... |
55 |
int *buffer) |
30a5b5367 percpu: expose st... |
56 |
{ |
40064aeca percpu: replace a... |
57 |
int i, last_alloc, as_len, start, end; |
30a5b5367 percpu: expose st... |
58 59 60 61 62 63 |
int *alloc_sizes, *p; /* statistics */ int sum_frag = 0, max_frag = 0; int cur_min_alloc = 0, cur_med_alloc = 0, cur_max_alloc = 0; alloc_sizes = buffer; |
30a5b5367 percpu: expose st... |
64 |
|
40064aeca percpu: replace a... |
65 66 67 68 69 70 71 72 73 74 75 76 |
/* * find_last_bit returns the start value if nothing found. * Therefore, we must determine if it is a failure of find_last_bit * and set the appropriate value. */ last_alloc = find_last_bit(chunk->alloc_map, pcpu_chunk_map_bits(chunk) - chunk->end_offset / PCPU_MIN_ALLOC_SIZE - 1); last_alloc = test_bit(last_alloc, chunk->alloc_map) ? last_alloc + 1 : 0; as_len = 0; |
2e08d20d7 percpu: fix start... |
77 |
start = chunk->start_offset / PCPU_MIN_ALLOC_SIZE; |
40064aeca percpu: replace a... |
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
/* * If a bit is set in the allocation map, the bound_map identifies * where the allocation ends. If the allocation is not set, the * bound_map does not identify free areas as it is only kept accurate * on allocation, not free. * * Positive values are allocations and negative values are free * fragments. */ while (start < last_alloc) { if (test_bit(start, chunk->alloc_map)) { end = find_next_bit(chunk->bound_map, last_alloc, start + 1); alloc_sizes[as_len] = 1; } else { end = find_next_bit(chunk->alloc_map, last_alloc, start + 1); alloc_sizes[as_len] = -1; |
30a5b5367 percpu: expose st... |
97 |
} |
40064aeca percpu: replace a... |
98 99 100 101 102 103 104 105 106 107 108 |
alloc_sizes[as_len++] *= (end - start) * PCPU_MIN_ALLOC_SIZE; start = end; } /* * The negative values are free fragments and thus sorting gives the * free fragments at the beginning in largest first order. */ if (as_len > 0) { sort(alloc_sizes, as_len, sizeof(int), cmpint, NULL); |
30a5b5367 percpu: expose st... |
109 |
|
40064aeca percpu: replace a... |
110 |
/* iterate through the unallocated fragments */ |
30a5b5367 percpu: expose st... |
111 112 113 114 115 116 117 118 119 120 121 122 |
for (i = 0, p = alloc_sizes; *p < 0 && i < as_len; i++, p++) { sum_frag -= *p; max_frag = max(max_frag, -1 * (*p)); } cur_min_alloc = alloc_sizes[i]; cur_med_alloc = alloc_sizes[(i + as_len - 1) / 2]; cur_max_alloc = alloc_sizes[as_len - 1]; } P("nr_alloc", chunk->nr_alloc); P("max_alloc_size", chunk->max_alloc_size); |
0cecf50cf percpu: introduce... |
123 |
P("empty_pop_pages", chunk->nr_empty_pop_pages); |
86b442fbc percpu: add first... |
124 |
P("first_bit", chunk->first_bit); |
40064aeca percpu: replace a... |
125 126 |
P("free_bytes", chunk->free_bytes); P("contig_bytes", chunk->contig_bits * PCPU_MIN_ALLOC_SIZE); |
30a5b5367 percpu: expose st... |
127 128 129 130 131 132 133 134 135 136 137 138 |
P("sum_frag", sum_frag); P("max_frag", max_frag); P("cur_min_alloc", cur_min_alloc); P("cur_med_alloc", cur_med_alloc); P("cur_max_alloc", cur_max_alloc); seq_putc(m, ' '); } static int percpu_stats_show(struct seq_file *m, void *v) { struct pcpu_chunk *chunk; |
40064aeca percpu: replace a... |
139 |
int slot, max_nr_alloc; |
cd6a884d0 percpu: pcpu-stat... |
140 |
int *buffer; |
30a5b5367 percpu: expose st... |
141 142 143 |
alloc_buffer: spin_lock_irq(&pcpu_lock); |
40064aeca percpu: replace a... |
144 |
max_nr_alloc = find_max_nr_alloc(); |
30a5b5367 percpu: expose st... |
145 |
spin_unlock_irq(&pcpu_lock); |
40064aeca percpu: replace a... |
146 |
/* there can be at most this many free and allocated fragments */ |
42bc47b35 treewide: Use arr... |
147 |
buffer = vmalloc(array_size(sizeof(int), (2 * max_nr_alloc + 1))); |
30a5b5367 percpu: expose st... |
148 149 150 151 152 153 |
if (!buffer) return -ENOMEM; spin_lock_irq(&pcpu_lock); /* if the buffer allocated earlier is too small */ |
40064aeca percpu: replace a... |
154 |
if (max_nr_alloc < find_max_nr_alloc()) { |
30a5b5367 percpu: expose st... |
155 156 157 158 159 160 |
spin_unlock_irq(&pcpu_lock); vfree(buffer); goto alloc_buffer; } #define PL(X) \ |
02459164a percpu: change th... |
161 162 |
seq_printf(m, " %-20s: %12lld ", #X, (long long int)pcpu_stats_ai.X) |
30a5b5367 percpu: expose st... |
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
seq_printf(m, "Percpu Memory Statistics " "Allocation Info: " "---------------------------------------- "); PL(unit_size); PL(static_size); PL(reserved_size); PL(dyn_size); PL(atom_size); PL(alloc_size); seq_putc(m, ' '); #undef PL #define PU(X) \ |
02459164a percpu: change th... |
183 184 |
seq_printf(m, " %-20s: %12llu ", #X, (unsigned long long)pcpu_stats.X) |
30a5b5367 percpu: expose st... |
185 186 187 188 189 190 191 192 193 194 195 196 197 198 |
seq_printf(m, "Global Stats: " "---------------------------------------- "); PU(nr_alloc); PU(nr_dealloc); PU(nr_cur_alloc); PU(nr_max_alloc); PU(nr_chunks); PU(nr_max_chunks); PU(min_alloc_size); PU(max_alloc_size); |
6b9b6f399 percpu: expose pc... |
199 |
P("empty_pop_pages", pcpu_nr_empty_pop_pages); |
30a5b5367 percpu: expose st... |
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 |
seq_putc(m, ' '); #undef PU seq_printf(m, "Per Chunk Stats: " "---------------------------------------- "); if (pcpu_reserved_chunk) { seq_puts(m, "Chunk: <- Reserved Chunk "); chunk_map_stats(m, pcpu_reserved_chunk, buffer); } for (slot = 0; slot < pcpu_nr_slots; slot++) { list_for_each_entry(chunk, &pcpu_slot[slot], list) { if (chunk == pcpu_first_chunk) { seq_puts(m, "Chunk: <- First Chunk "); chunk_map_stats(m, chunk, buffer); } else { seq_puts(m, "Chunk: "); chunk_map_stats(m, chunk, buffer); } } } spin_unlock_irq(&pcpu_lock); vfree(buffer); return 0; } |
5ad350936 mm: reuse DEFINE_... |
240 |
DEFINE_SHOW_ATTRIBUTE(percpu_stats); |
30a5b5367 percpu: expose st... |
241 242 243 244 245 246 247 248 249 250 |
static int __init init_percpu_stats_debugfs(void) { debugfs_create_file("percpu_stats", 0444, NULL, NULL, &percpu_stats_fops); return 0; } late_initcall(init_percpu_stats_debugfs); |