diff options
author | Ying Han <yinghan@google.com> | 2011-05-26 19:25:37 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-26 20:12:36 -0400 |
commit | 406eb0c9ba765eb066406fd5ce9d5e2b169a4d5a (patch) | |
tree | 71805cc1bcf4b1a4e7eb58a726d2ba21d913ba1a /mm/memcontrol.c | |
parent | 1bac180bd29e03989f50054af97b53b8d37a364a (diff) |
memcg: add memory.numastat api for numa statistics
The new API exports numa_maps per-memcg basis. This is a piece of useful
information where it exports per-memcg page distribution across real numa
nodes.
One of the usecases is evaluating application performance by combining
this information w/ the cpu allocation to the application.
The output of the memory.numastat tries to follow w/ simiar format of
numa_maps like:
total=<total pages> N0=<node 0 pages> N1=<node 1 pages> ...
file=<total file pages> N0=<node 0 pages> N1=<node 1 pages> ...
anon=<total anon pages> N0=<node 0 pages> N1=<node 1 pages> ...
unevictable=<total anon pages> N0=<node 0 pages> N1=<node 1 pages> ...
And we have per-node:
total = file + anon + unevictable
$ cat /dev/cgroup/memory/memory.numa_stat
total=250020 N0=87620 N1=52367 N2=45298 N3=64735
file=225232 N0=83402 N1=46160 N2=40522 N3=55148
anon=21053 N0=3424 N1=6207 N2=4776 N3=6646
unevictable=3735 N0=794 N1=0 N2=0 N3=2941
Signed-off-by: Ying Han <yinghan@google.com>
Cc: Balbir Singh <balbir@in.ibm.com>
Cc: Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp>
Acked-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Acked-by: Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp>
Cc: Minchan Kim <minchan.kim@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/memcontrol.c')
-rw-r--r-- | mm/memcontrol.c | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index cc48a6854f7e..4021fcd71b60 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
@@ -1089,6 +1089,93 @@ unsigned long mem_cgroup_zone_nr_lru_pages(struct mem_cgroup *memcg, | |||
1089 | return MEM_CGROUP_ZSTAT(mz, lru); | 1089 | return MEM_CGROUP_ZSTAT(mz, lru); |
1090 | } | 1090 | } |
1091 | 1091 | ||
1092 | #ifdef CONFIG_NUMA | ||
1093 | static unsigned long mem_cgroup_node_nr_file_lru_pages(struct mem_cgroup *memcg, | ||
1094 | int nid) | ||
1095 | { | ||
1096 | unsigned long ret; | ||
1097 | |||
1098 | ret = mem_cgroup_get_zonestat_node(memcg, nid, LRU_INACTIVE_FILE) + | ||
1099 | mem_cgroup_get_zonestat_node(memcg, nid, LRU_ACTIVE_FILE); | ||
1100 | |||
1101 | return ret; | ||
1102 | } | ||
1103 | |||
1104 | static unsigned long mem_cgroup_nr_file_lru_pages(struct mem_cgroup *memcg) | ||
1105 | { | ||
1106 | u64 total = 0; | ||
1107 | int nid; | ||
1108 | |||
1109 | for_each_node_state(nid, N_HIGH_MEMORY) | ||
1110 | total += mem_cgroup_node_nr_file_lru_pages(memcg, nid); | ||
1111 | |||
1112 | return total; | ||
1113 | } | ||
1114 | |||
1115 | static unsigned long mem_cgroup_node_nr_anon_lru_pages(struct mem_cgroup *memcg, | ||
1116 | int nid) | ||
1117 | { | ||
1118 | unsigned long ret; | ||
1119 | |||
1120 | ret = mem_cgroup_get_zonestat_node(memcg, nid, LRU_INACTIVE_ANON) + | ||
1121 | mem_cgroup_get_zonestat_node(memcg, nid, LRU_ACTIVE_ANON); | ||
1122 | |||
1123 | return ret; | ||
1124 | } | ||
1125 | |||
1126 | static unsigned long mem_cgroup_nr_anon_lru_pages(struct mem_cgroup *memcg) | ||
1127 | { | ||
1128 | u64 total = 0; | ||
1129 | int nid; | ||
1130 | |||
1131 | for_each_node_state(nid, N_HIGH_MEMORY) | ||
1132 | total += mem_cgroup_node_nr_anon_lru_pages(memcg, nid); | ||
1133 | |||
1134 | return total; | ||
1135 | } | ||
1136 | |||
1137 | static unsigned long | ||
1138 | mem_cgroup_node_nr_unevictable_lru_pages(struct mem_cgroup *memcg, int nid) | ||
1139 | { | ||
1140 | return mem_cgroup_get_zonestat_node(memcg, nid, LRU_UNEVICTABLE); | ||
1141 | } | ||
1142 | |||
1143 | static unsigned long | ||
1144 | mem_cgroup_nr_unevictable_lru_pages(struct mem_cgroup *memcg) | ||
1145 | { | ||
1146 | u64 total = 0; | ||
1147 | int nid; | ||
1148 | |||
1149 | for_each_node_state(nid, N_HIGH_MEMORY) | ||
1150 | total += mem_cgroup_node_nr_unevictable_lru_pages(memcg, nid); | ||
1151 | |||
1152 | return total; | ||
1153 | } | ||
1154 | |||
1155 | static unsigned long mem_cgroup_node_nr_lru_pages(struct mem_cgroup *memcg, | ||
1156 | int nid) | ||
1157 | { | ||
1158 | enum lru_list l; | ||
1159 | u64 total = 0; | ||
1160 | |||
1161 | for_each_lru(l) | ||
1162 | total += mem_cgroup_get_zonestat_node(memcg, nid, l); | ||
1163 | |||
1164 | return total; | ||
1165 | } | ||
1166 | |||
1167 | static unsigned long mem_cgroup_nr_lru_pages(struct mem_cgroup *memcg) | ||
1168 | { | ||
1169 | u64 total = 0; | ||
1170 | int nid; | ||
1171 | |||
1172 | for_each_node_state(nid, N_HIGH_MEMORY) | ||
1173 | total += mem_cgroup_node_nr_lru_pages(memcg, nid); | ||
1174 | |||
1175 | return total; | ||
1176 | } | ||
1177 | #endif /* CONFIG_NUMA */ | ||
1178 | |||
1092 | struct zone_reclaim_stat *mem_cgroup_get_reclaim_stat(struct mem_cgroup *memcg, | 1179 | struct zone_reclaim_stat *mem_cgroup_get_reclaim_stat(struct mem_cgroup *memcg, |
1093 | struct zone *zone) | 1180 | struct zone *zone) |
1094 | { | 1181 | { |
@@ -3944,6 +4031,51 @@ mem_cgroup_get_total_stat(struct mem_cgroup *mem, struct mcs_total_stat *s) | |||
3944 | mem_cgroup_get_local_stat(iter, s); | 4031 | mem_cgroup_get_local_stat(iter, s); |
3945 | } | 4032 | } |
3946 | 4033 | ||
4034 | #ifdef CONFIG_NUMA | ||
4035 | static int mem_control_numa_stat_show(struct seq_file *m, void *arg) | ||
4036 | { | ||
4037 | int nid; | ||
4038 | unsigned long total_nr, file_nr, anon_nr, unevictable_nr; | ||
4039 | unsigned long node_nr; | ||
4040 | struct cgroup *cont = m->private; | ||
4041 | struct mem_cgroup *mem_cont = mem_cgroup_from_cont(cont); | ||
4042 | |||
4043 | total_nr = mem_cgroup_nr_lru_pages(mem_cont); | ||
4044 | seq_printf(m, "total=%lu", total_nr); | ||
4045 | for_each_node_state(nid, N_HIGH_MEMORY) { | ||
4046 | node_nr = mem_cgroup_node_nr_lru_pages(mem_cont, nid); | ||
4047 | seq_printf(m, " N%d=%lu", nid, node_nr); | ||
4048 | } | ||
4049 | seq_putc(m, '\n'); | ||
4050 | |||
4051 | file_nr = mem_cgroup_nr_file_lru_pages(mem_cont); | ||
4052 | seq_printf(m, "file=%lu", file_nr); | ||
4053 | for_each_node_state(nid, N_HIGH_MEMORY) { | ||
4054 | node_nr = mem_cgroup_node_nr_file_lru_pages(mem_cont, nid); | ||
4055 | seq_printf(m, " N%d=%lu", nid, node_nr); | ||
4056 | } | ||
4057 | seq_putc(m, '\n'); | ||
4058 | |||
4059 | anon_nr = mem_cgroup_nr_anon_lru_pages(mem_cont); | ||
4060 | seq_printf(m, "anon=%lu", anon_nr); | ||
4061 | for_each_node_state(nid, N_HIGH_MEMORY) { | ||
4062 | node_nr = mem_cgroup_node_nr_anon_lru_pages(mem_cont, nid); | ||
4063 | seq_printf(m, " N%d=%lu", nid, node_nr); | ||
4064 | } | ||
4065 | seq_putc(m, '\n'); | ||
4066 | |||
4067 | unevictable_nr = mem_cgroup_nr_unevictable_lru_pages(mem_cont); | ||
4068 | seq_printf(m, "unevictable=%lu", unevictable_nr); | ||
4069 | for_each_node_state(nid, N_HIGH_MEMORY) { | ||
4070 | node_nr = mem_cgroup_node_nr_unevictable_lru_pages(mem_cont, | ||
4071 | nid); | ||
4072 | seq_printf(m, " N%d=%lu", nid, node_nr); | ||
4073 | } | ||
4074 | seq_putc(m, '\n'); | ||
4075 | return 0; | ||
4076 | } | ||
4077 | #endif /* CONFIG_NUMA */ | ||
4078 | |||
3947 | static int mem_control_stat_show(struct cgroup *cont, struct cftype *cft, | 4079 | static int mem_control_stat_show(struct cgroup *cont, struct cftype *cft, |
3948 | struct cgroup_map_cb *cb) | 4080 | struct cgroup_map_cb *cb) |
3949 | { | 4081 | { |
@@ -3954,6 +4086,7 @@ static int mem_control_stat_show(struct cgroup *cont, struct cftype *cft, | |||
3954 | memset(&mystat, 0, sizeof(mystat)); | 4086 | memset(&mystat, 0, sizeof(mystat)); |
3955 | mem_cgroup_get_local_stat(mem_cont, &mystat); | 4087 | mem_cgroup_get_local_stat(mem_cont, &mystat); |
3956 | 4088 | ||
4089 | |||
3957 | for (i = 0; i < NR_MCS_STAT; i++) { | 4090 | for (i = 0; i < NR_MCS_STAT; i++) { |
3958 | if (i == MCS_SWAP && !do_swap_account) | 4091 | if (i == MCS_SWAP && !do_swap_account) |
3959 | continue; | 4092 | continue; |
@@ -4377,6 +4510,22 @@ static int mem_cgroup_oom_control_write(struct cgroup *cgrp, | |||
4377 | return 0; | 4510 | return 0; |
4378 | } | 4511 | } |
4379 | 4512 | ||
4513 | #ifdef CONFIG_NUMA | ||
4514 | static const struct file_operations mem_control_numa_stat_file_operations = { | ||
4515 | .read = seq_read, | ||
4516 | .llseek = seq_lseek, | ||
4517 | .release = single_release, | ||
4518 | }; | ||
4519 | |||
4520 | static int mem_control_numa_stat_open(struct inode *unused, struct file *file) | ||
4521 | { | ||
4522 | struct cgroup *cont = file->f_dentry->d_parent->d_fsdata; | ||
4523 | |||
4524 | file->f_op = &mem_control_numa_stat_file_operations; | ||
4525 | return single_open(file, mem_control_numa_stat_show, cont); | ||
4526 | } | ||
4527 | #endif /* CONFIG_NUMA */ | ||
4528 | |||
4380 | static struct cftype mem_cgroup_files[] = { | 4529 | static struct cftype mem_cgroup_files[] = { |
4381 | { | 4530 | { |
4382 | .name = "usage_in_bytes", | 4531 | .name = "usage_in_bytes", |
@@ -4440,6 +4589,12 @@ static struct cftype mem_cgroup_files[] = { | |||
4440 | .unregister_event = mem_cgroup_oom_unregister_event, | 4589 | .unregister_event = mem_cgroup_oom_unregister_event, |
4441 | .private = MEMFILE_PRIVATE(_OOM_TYPE, OOM_CONTROL), | 4590 | .private = MEMFILE_PRIVATE(_OOM_TYPE, OOM_CONTROL), |
4442 | }, | 4591 | }, |
4592 | #ifdef CONFIG_NUMA | ||
4593 | { | ||
4594 | .name = "numa_stat", | ||
4595 | .open = mem_control_numa_stat_open, | ||
4596 | }, | ||
4597 | #endif | ||
4443 | }; | 4598 | }; |
4444 | 4599 | ||
4445 | #ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP | 4600 | #ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP |