Commit 749c54151a6e5b229e4ae067dbc651e54b161fbc

Authored by Glauber Costa
Committed by Linus Torvalds
1 parent 2293315293

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 */
... ... @@ -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 };
... ... @@ -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  
... ... @@ -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 /*