aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGlauber Costa <glommer@parallels.com>2012-12-18 17:23:01 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2012-12-18 18:02:14 -0500
commit749c54151a6e5b229e4ae067dbc651e54b161fbc (patch)
tree8d2d858e76e44d1bbf64439c189a57c18c8e60ae
parent22933152934f30de6f05b600c03f8a08f853a8d2 (diff)
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>
-rw-r--r--include/linux/memcontrol.h8
-rw-r--r--include/linux/slab.h4
-rw-r--r--mm/memcontrol.c30
-rw-r--r--mm/slab.h27
-rw-r--r--mm/slab_common.c44
5 files changed, 108 insertions, 5 deletions
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index e119f3ef793c..8dc7c746b44f 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -420,6 +420,11 @@ static inline void sock_release_memcg(struct sock *sk)
420 420
421#ifdef CONFIG_MEMCG_KMEM 421#ifdef CONFIG_MEMCG_KMEM
422extern struct static_key memcg_kmem_enabled_key; 422extern struct static_key memcg_kmem_enabled_key;
423
424extern 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
423static inline bool memcg_kmem_enabled(void) 428static inline bool memcg_kmem_enabled(void)
424{ 429{
425 return static_key_false(&memcg_kmem_enabled_key); 430 return static_key_false(&memcg_kmem_enabled_key);
@@ -557,6 +562,9 @@ memcg_kmem_get_cache(struct kmem_cache *cachep, gfp_t gfp)
557 return __memcg_kmem_get_cache(cachep, gfp); 562 return __memcg_kmem_get_cache(cachep, gfp);
558} 563}
559#else 564#else
565#define for_each_memcg_cache_index(_idx) \
566 for (; NULL; )
567
560static inline bool memcg_kmem_enabled(void) 568static inline bool memcg_kmem_enabled(void)
561{ 569{
562 return false; 570 return false;
diff --git a/include/linux/slab.h b/include/linux/slab.h
index 869efb8d2377..b9278663f22a 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -220,6 +220,10 @@ struct memcg_cache_params {
220 220
221int memcg_update_all_caches(int num_memcgs); 221int memcg_update_all_caches(int num_memcgs);
222 222
223struct seq_file;
224int cache_show(struct kmem_cache *s, struct seq_file *m);
225void print_slabinfo_header(struct seq_file *m);
226
223/* 227/*
224 * Common kmalloc functions provided by all allocators 228 * Common kmalloc functions provided by all allocators
225 */ 229 */
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 7633e0d429e0..a32d83c2e353 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -572,7 +572,8 @@ static void disarm_sock_keys(struct mem_cgroup *memcg)
572 * increase it. 572 * increase it.
573 */ 573 */
574static DEFINE_IDA(kmem_limited_groups); 574static DEFINE_IDA(kmem_limited_groups);
575static int memcg_limited_groups_array_size; 575int memcg_limited_groups_array_size;
576
576/* 577/*
577 * MIN_SIZE is different than 1, because we would like to avoid going through 578 * MIN_SIZE is different than 1, because we would like to avoid going through
578 * the alloc/free process all the time. In a small machine, 4 kmem-limited 579 * the alloc/free process all the time. In a small machine, 4 kmem-limited
@@ -2794,6 +2795,27 @@ static struct kmem_cache *memcg_params_to_cache(struct memcg_cache_params *p)
2794 return cachep->memcg_params->memcg_caches[memcg_cache_id(p->memcg)]; 2795 return cachep->memcg_params->memcg_caches[memcg_cache_id(p->memcg)];
2795} 2796}
2796 2797
2798#ifdef CONFIG_SLABINFO
2799static 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
2797static int memcg_charge_kmem(struct mem_cgroup *memcg, gfp_t gfp, u64 size) 2819static int memcg_charge_kmem(struct mem_cgroup *memcg, gfp_t gfp, u64 size)
2798{ 2820{
2799 struct res_counter *fail_res; 2821 struct res_counter *fail_res;
@@ -5822,6 +5844,12 @@ static struct cftype mem_cgroup_files[] = {
5822 .trigger = mem_cgroup_reset, 5844 .trigger = mem_cgroup_reset,
5823 .read = mem_cgroup_read, 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#endif 5853#endif
5826 { }, /* terminate */ 5854 { }, /* terminate */
5827}; 5855};
diff --git a/mm/slab.h b/mm/slab.h
index 43d8a38b534f..ec5dae1c8e75 100644
--- a/mm/slab.h
+++ b/mm/slab.h
@@ -138,6 +138,23 @@ static inline bool slab_equal_or_root(struct kmem_cache *s,
138 return (p == s) || 138 return (p == s) ||
139 (s->memcg_params && (p == s->memcg_params->root_cache)); 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 */
147static 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
154static inline struct kmem_cache *cache_from_memcg(struct kmem_cache *s, int idx)
155{
156 return s->memcg_params->memcg_caches[idx];
157}
141#else 158#else
142static inline bool is_root_cache(struct kmem_cache *s) 159static inline bool is_root_cache(struct kmem_cache *s)
143{ 160{
@@ -163,6 +180,16 @@ static inline bool slab_equal_or_root(struct kmem_cache *s,
163{ 180{
164 return true; 181 return true;
165} 182}
183
184static inline const char *cache_name(struct kmem_cache *s)
185{
186 return s->name;
187}
188
189static inline struct kmem_cache *cache_from_memcg(struct kmem_cache *s, int idx)
190{
191 return NULL;
192}
166#endif 193#endif
167 194
168static inline struct kmem_cache *cache_from_obj(struct kmem_cache *s, void *x) 195static inline struct kmem_cache *cache_from_obj(struct kmem_cache *s, void *x)
diff --git a/mm/slab_common.c b/mm/slab_common.c
index 080a43804bf1..081f1b8d9a7b 100644
--- a/mm/slab_common.c
+++ b/mm/slab_common.c
@@ -322,7 +322,7 @@ struct kmem_cache *__init create_kmalloc_cache(const char *name, size_t size,
322 322
323 323
324#ifdef CONFIG_SLABINFO 324#ifdef CONFIG_SLABINFO
325static void print_slabinfo_header(struct seq_file *m) 325void print_slabinfo_header(struct seq_file *m)
326{ 326{
327 /* 327 /*
328 * Output format version, so at least we can change it 328 * Output format version, so at least we can change it
@@ -366,16 +366,43 @@ static void s_stop(struct seq_file *m, void *p)
366 mutex_unlock(&slab_mutex); 366 mutex_unlock(&slab_mutex);
367} 367}
368 368
369static int s_show(struct seq_file *m, void *p) 369static void
370memcg_accumulate_slabinfo(struct kmem_cache *s, struct slabinfo *info)
371{
372 struct kmem_cache *c;
373 struct slabinfo sinfo;
374 int i;
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
395int cache_show(struct kmem_cache *s, struct seq_file *m)
370{ 396{
371 struct kmem_cache *s = list_entry(p, struct kmem_cache, list);
372 struct slabinfo sinfo; 397 struct slabinfo sinfo;
373 398
374 memset(&sinfo, 0, sizeof(sinfo)); 399 memset(&sinfo, 0, sizeof(sinfo));
375 get_slabinfo(s, &sinfo); 400 get_slabinfo(s, &sinfo);
376 401
402 memcg_accumulate_slabinfo(s, &sinfo);
403
377 seq_printf(m, "%-17s %6lu %6lu %6u %4u %4d", 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 sinfo.objects_per_slab, (1 << sinfo.cache_order)); 406 sinfo.objects_per_slab, (1 << sinfo.cache_order));
380 407
381 seq_printf(m, " : tunables %4u %4u %4u", 408 seq_printf(m, " : tunables %4u %4u %4u",
@@ -387,6 +414,15 @@ static int s_show(struct seq_file *m, void *p)
387 return 0; 414 return 0;
388} 415}
389 416
417static 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);
424}
425
390/* 426/*
391 * slabinfo_op - iterator that generates /proc/slabinfo 427 * slabinfo_op - iterator that generates /proc/slabinfo
392 * 428 *