Commit 749c54151a6e5b229e4ae067dbc651e54b161fbc
Committed by
Linus Torvalds
1 parent
2293315293
Exists in
master
and in
20 other branches
memcg: aggregate memcg cache values in slabinfo
When we create caches in memcgs, we need to display their usage information somewhere. We'll adopt a scheme similar to /proc/meminfo, with aggregate totals shown in the global file, and per-group information stored in the group itself. For the time being, only reads are allowed in the per-group cache. Signed-off-by: Glauber Costa <glommer@parallels.com> Cc: Christoph Lameter <cl@linux.com> Cc: David Rientjes <rientjes@google.com> Cc: Frederic Weisbecker <fweisbec@redhat.com> Cc: Greg Thelen <gthelen@google.com> Cc: Johannes Weiner <hannes@cmpxchg.org> Cc: JoonSoo Kim <js1304@gmail.com> Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Cc: Mel Gorman <mel@csn.ul.ie> Cc: Michal Hocko <mhocko@suse.cz> Cc: Pekka Enberg <penberg@cs.helsinki.fi> Cc: Rik van Riel <riel@redhat.com> Cc: Suleiman Souhlal <suleiman@google.com> Cc: Tejun Heo <tj@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 5 changed files with 108 additions and 5 deletions Side-by-side Diff
include/linux/memcontrol.h
... | ... | @@ -420,6 +420,11 @@ |
420 | 420 | |
421 | 421 | #ifdef CONFIG_MEMCG_KMEM |
422 | 422 | extern struct static_key memcg_kmem_enabled_key; |
423 | + | |
424 | +extern int memcg_limited_groups_array_size; | |
425 | +#define for_each_memcg_cache_index(_idx) \ | |
426 | + for ((_idx) = 0; i < memcg_limited_groups_array_size; (_idx)++) | |
427 | + | |
423 | 428 | static inline bool memcg_kmem_enabled(void) |
424 | 429 | { |
425 | 430 | return static_key_false(&memcg_kmem_enabled_key); |
... | ... | @@ -557,6 +562,9 @@ |
557 | 562 | return __memcg_kmem_get_cache(cachep, gfp); |
558 | 563 | } |
559 | 564 | #else |
565 | +#define for_each_memcg_cache_index(_idx) \ | |
566 | + for (; NULL; ) | |
567 | + | |
560 | 568 | static inline bool memcg_kmem_enabled(void) |
561 | 569 | { |
562 | 570 | return false; |
include/linux/slab.h
... | ... | @@ -220,6 +220,10 @@ |
220 | 220 | |
221 | 221 | int memcg_update_all_caches(int num_memcgs); |
222 | 222 | |
223 | +struct seq_file; | |
224 | +int cache_show(struct kmem_cache *s, struct seq_file *m); | |
225 | +void print_slabinfo_header(struct seq_file *m); | |
226 | + | |
223 | 227 | /* |
224 | 228 | * Common kmalloc functions provided by all allocators |
225 | 229 | */ |
mm/memcontrol.c
... | ... | @@ -572,7 +572,8 @@ |
572 | 572 | * increase it. |
573 | 573 | */ |
574 | 574 | static DEFINE_IDA(kmem_limited_groups); |
575 | -static int memcg_limited_groups_array_size; | |
575 | +int memcg_limited_groups_array_size; | |
576 | + | |
576 | 577 | /* |
577 | 578 | * MIN_SIZE is different than 1, because we would like to avoid going through |
578 | 579 | * the alloc/free process all the time. In a small machine, 4 kmem-limited |
... | ... | @@ -2794,6 +2795,27 @@ |
2794 | 2795 | return cachep->memcg_params->memcg_caches[memcg_cache_id(p->memcg)]; |
2795 | 2796 | } |
2796 | 2797 | |
2798 | +#ifdef CONFIG_SLABINFO | |
2799 | +static int mem_cgroup_slabinfo_read(struct cgroup *cont, struct cftype *cft, | |
2800 | + struct seq_file *m) | |
2801 | +{ | |
2802 | + struct mem_cgroup *memcg = mem_cgroup_from_cont(cont); | |
2803 | + struct memcg_cache_params *params; | |
2804 | + | |
2805 | + if (!memcg_can_account_kmem(memcg)) | |
2806 | + return -EIO; | |
2807 | + | |
2808 | + print_slabinfo_header(m); | |
2809 | + | |
2810 | + mutex_lock(&memcg->slab_caches_mutex); | |
2811 | + list_for_each_entry(params, &memcg->memcg_slab_caches, list) | |
2812 | + cache_show(memcg_params_to_cache(params), m); | |
2813 | + mutex_unlock(&memcg->slab_caches_mutex); | |
2814 | + | |
2815 | + return 0; | |
2816 | +} | |
2817 | +#endif | |
2818 | + | |
2797 | 2819 | static int memcg_charge_kmem(struct mem_cgroup *memcg, gfp_t gfp, u64 size) |
2798 | 2820 | { |
2799 | 2821 | struct res_counter *fail_res; |
... | ... | @@ -5822,6 +5844,12 @@ |
5822 | 5844 | .trigger = mem_cgroup_reset, |
5823 | 5845 | .read = mem_cgroup_read, |
5824 | 5846 | }, |
5847 | +#ifdef CONFIG_SLABINFO | |
5848 | + { | |
5849 | + .name = "kmem.slabinfo", | |
5850 | + .read_seq_string = mem_cgroup_slabinfo_read, | |
5851 | + }, | |
5852 | +#endif | |
5825 | 5853 | #endif |
5826 | 5854 | { }, /* terminate */ |
5827 | 5855 | }; |
mm/slab.h
... | ... | @@ -138,6 +138,23 @@ |
138 | 138 | return (p == s) || |
139 | 139 | (s->memcg_params && (p == s->memcg_params->root_cache)); |
140 | 140 | } |
141 | + | |
142 | +/* | |
143 | + * We use suffixes to the name in memcg because we can't have caches | |
144 | + * created in the system with the same name. But when we print them | |
145 | + * locally, better refer to them with the base name | |
146 | + */ | |
147 | +static inline const char *cache_name(struct kmem_cache *s) | |
148 | +{ | |
149 | + if (!is_root_cache(s)) | |
150 | + return s->memcg_params->root_cache->name; | |
151 | + return s->name; | |
152 | +} | |
153 | + | |
154 | +static inline struct kmem_cache *cache_from_memcg(struct kmem_cache *s, int idx) | |
155 | +{ | |
156 | + return s->memcg_params->memcg_caches[idx]; | |
157 | +} | |
141 | 158 | #else |
142 | 159 | static inline bool is_root_cache(struct kmem_cache *s) |
143 | 160 | { |
... | ... | @@ -162,6 +179,16 @@ |
162 | 179 | struct kmem_cache *p) |
163 | 180 | { |
164 | 181 | return true; |
182 | +} | |
183 | + | |
184 | +static inline const char *cache_name(struct kmem_cache *s) | |
185 | +{ | |
186 | + return s->name; | |
187 | +} | |
188 | + | |
189 | +static inline struct kmem_cache *cache_from_memcg(struct kmem_cache *s, int idx) | |
190 | +{ | |
191 | + return NULL; | |
165 | 192 | } |
166 | 193 | #endif |
167 | 194 |
mm/slab_common.c
... | ... | @@ -322,7 +322,7 @@ |
322 | 322 | |
323 | 323 | |
324 | 324 | #ifdef CONFIG_SLABINFO |
325 | -static void print_slabinfo_header(struct seq_file *m) | |
325 | +void print_slabinfo_header(struct seq_file *m) | |
326 | 326 | { |
327 | 327 | /* |
328 | 328 | * Output format version, so at least we can change it |
329 | 329 | |
330 | 330 | |
331 | 331 | |
332 | 332 | |
333 | 333 | |
... | ... | @@ -366,16 +366,43 @@ |
366 | 366 | mutex_unlock(&slab_mutex); |
367 | 367 | } |
368 | 368 | |
369 | -static int s_show(struct seq_file *m, void *p) | |
369 | +static void | |
370 | +memcg_accumulate_slabinfo(struct kmem_cache *s, struct slabinfo *info) | |
370 | 371 | { |
371 | - struct kmem_cache *s = list_entry(p, struct kmem_cache, list); | |
372 | + struct kmem_cache *c; | |
372 | 373 | struct slabinfo sinfo; |
374 | + int i; | |
373 | 375 | |
376 | + if (!is_root_cache(s)) | |
377 | + return; | |
378 | + | |
379 | + for_each_memcg_cache_index(i) { | |
380 | + c = cache_from_memcg(s, i); | |
381 | + if (!c) | |
382 | + continue; | |
383 | + | |
384 | + memset(&sinfo, 0, sizeof(sinfo)); | |
385 | + get_slabinfo(c, &sinfo); | |
386 | + | |
387 | + info->active_slabs += sinfo.active_slabs; | |
388 | + info->num_slabs += sinfo.num_slabs; | |
389 | + info->shared_avail += sinfo.shared_avail; | |
390 | + info->active_objs += sinfo.active_objs; | |
391 | + info->num_objs += sinfo.num_objs; | |
392 | + } | |
393 | +} | |
394 | + | |
395 | +int cache_show(struct kmem_cache *s, struct seq_file *m) | |
396 | +{ | |
397 | + struct slabinfo sinfo; | |
398 | + | |
374 | 399 | memset(&sinfo, 0, sizeof(sinfo)); |
375 | 400 | get_slabinfo(s, &sinfo); |
376 | 401 | |
402 | + memcg_accumulate_slabinfo(s, &sinfo); | |
403 | + | |
377 | 404 | seq_printf(m, "%-17s %6lu %6lu %6u %4u %4d", |
378 | - s->name, sinfo.active_objs, sinfo.num_objs, s->size, | |
405 | + cache_name(s), sinfo.active_objs, sinfo.num_objs, s->size, | |
379 | 406 | sinfo.objects_per_slab, (1 << sinfo.cache_order)); |
380 | 407 | |
381 | 408 | seq_printf(m, " : tunables %4u %4u %4u", |
... | ... | @@ -385,6 +412,15 @@ |
385 | 412 | slabinfo_show_stats(m, s); |
386 | 413 | seq_putc(m, '\n'); |
387 | 414 | return 0; |
415 | +} | |
416 | + | |
417 | +static int s_show(struct seq_file *m, void *p) | |
418 | +{ | |
419 | + struct kmem_cache *s = list_entry(p, struct kmem_cache, list); | |
420 | + | |
421 | + if (!is_root_cache(s)) | |
422 | + return 0; | |
423 | + return cache_show(s, m); | |
388 | 424 | } |
389 | 425 | |
390 | 426 | /* |