Blame view

mm/percpu-stats.c 5.66 KB
30a5b5367   Dennis Zhou   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   Dennis Zhou (Facebook)   percpu: change th...
21
22
  	seq_printf(m, "  %-20s: %12lld
  ", X, (long long int)Y)
30a5b5367   Dennis Zhou   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   Dennis Zhou (Facebook)   percpu: replace a...
33
   * Iterates over all chunks to find the max nr_alloc entries.
30a5b5367   Dennis Zhou   percpu: expose st...
34
   */
40064aeca   Dennis Zhou (Facebook)   percpu: replace a...
35
  static int find_max_nr_alloc(void)
30a5b5367   Dennis Zhou   percpu: expose st...
36
37
  {
  	struct pcpu_chunk *chunk;
40064aeca   Dennis Zhou (Facebook)   percpu: replace a...
38
  	int slot, max_nr_alloc;
30a5b5367   Dennis Zhou   percpu: expose st...
39

40064aeca   Dennis Zhou (Facebook)   percpu: replace a...
40
  	max_nr_alloc = 0;
30a5b5367   Dennis Zhou   percpu: expose st...
41
42
  	for (slot = 0; slot < pcpu_nr_slots; slot++)
  		list_for_each_entry(chunk, &pcpu_slot[slot], list)
40064aeca   Dennis Zhou (Facebook)   percpu: replace a...
43
  			max_nr_alloc = max(max_nr_alloc, chunk->nr_alloc);
30a5b5367   Dennis Zhou   percpu: expose st...
44

40064aeca   Dennis Zhou (Facebook)   percpu: replace a...
45
  	return max_nr_alloc;
30a5b5367   Dennis Zhou   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   Dennis Zhou (Facebook)   percpu: replace a...
51
52
   *
   * All statistics are in bytes unless stated otherwise.
30a5b5367   Dennis Zhou   percpu: expose st...
53
54
   */
  static void chunk_map_stats(struct seq_file *m, struct pcpu_chunk *chunk,
cd6a884d0   Dennis Zhou (Facebook)   percpu: pcpu-stat...
55
  			    int *buffer)
30a5b5367   Dennis Zhou   percpu: expose st...
56
  {
40064aeca   Dennis Zhou (Facebook)   percpu: replace a...
57
  	int i, last_alloc, as_len, start, end;
30a5b5367   Dennis Zhou   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   Dennis Zhou   percpu: expose st...
64

40064aeca   Dennis Zhou (Facebook)   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   Dennis Zhou   percpu: fix start...
77
  	start = chunk->start_offset / PCPU_MIN_ALLOC_SIZE;
40064aeca   Dennis Zhou (Facebook)   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   Dennis Zhou   percpu: expose st...
97
  		}
40064aeca   Dennis Zhou (Facebook)   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   Dennis Zhou   percpu: expose st...
109

40064aeca   Dennis Zhou (Facebook)   percpu: replace a...
110
  		/* iterate through the unallocated fragments */
30a5b5367   Dennis Zhou   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   Dennis Zhou (Facebook)   percpu: introduce...
123
  	P("empty_pop_pages", chunk->nr_empty_pop_pages);
86b442fbc   Dennis Zhou (Facebook)   percpu: add first...
124
  	P("first_bit", chunk->first_bit);
40064aeca   Dennis Zhou (Facebook)   percpu: replace a...
125
126
  	P("free_bytes", chunk->free_bytes);
  	P("contig_bytes", chunk->contig_bits * PCPU_MIN_ALLOC_SIZE);
30a5b5367   Dennis Zhou   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   Dennis Zhou (Facebook)   percpu: replace a...
139
  	int slot, max_nr_alloc;
cd6a884d0   Dennis Zhou (Facebook)   percpu: pcpu-stat...
140
  	int *buffer;
30a5b5367   Dennis Zhou   percpu: expose st...
141
142
143
  
  alloc_buffer:
  	spin_lock_irq(&pcpu_lock);
40064aeca   Dennis Zhou (Facebook)   percpu: replace a...
144
  	max_nr_alloc = find_max_nr_alloc();
30a5b5367   Dennis Zhou   percpu: expose st...
145
  	spin_unlock_irq(&pcpu_lock);
40064aeca   Dennis Zhou (Facebook)   percpu: replace a...
146
  	/* there can be at most this many free and allocated fragments */
42bc47b35   Kees Cook   treewide: Use arr...
147
  	buffer = vmalloc(array_size(sizeof(int), (2 * max_nr_alloc + 1)));
30a5b5367   Dennis Zhou   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   Dennis Zhou (Facebook)   percpu: replace a...
154
  	if (max_nr_alloc < find_max_nr_alloc()) {
30a5b5367   Dennis Zhou   percpu: expose st...
155
156
157
158
159
160
  		spin_unlock_irq(&pcpu_lock);
  		vfree(buffer);
  		goto alloc_buffer;
  	}
  
  #define PL(X) \
02459164a   Dennis Zhou (Facebook)   percpu: change th...
161
162
  	seq_printf(m, "  %-20s: %12lld
  ", #X, (long long int)pcpu_stats_ai.X)
30a5b5367   Dennis Zhou   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   Dennis Zhou (Facebook)   percpu: change th...
183
184
  	seq_printf(m, "  %-20s: %12llu
  ", #X, (unsigned long long)pcpu_stats.X)
30a5b5367   Dennis Zhou   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   Dennis Zhou (Facebook)   percpu: expose pc...
199
  	P("empty_pop_pages", pcpu_nr_empty_pop_pages);
30a5b5367   Dennis Zhou   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   Andy Shevchenko   mm: reuse DEFINE_...
240
  DEFINE_SHOW_ATTRIBUTE(percpu_stats);
30a5b5367   Dennis Zhou   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);