aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorKAMEZAWA Hiroyuki <kamzawa.hiroyu@jp.fujitsu.com>2009-04-02 19:57:35 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-04-02 22:04:55 -0400
commit14067bb3e24b96d92e22d19c18c0119edf5575e5 (patch)
tree54af97e899bf4253b170938f6711097824b7364f /mm
parent04046e1a0a34286382e913f8fc461440c21d88e8 (diff)
memcg: hierarchical stat
Clean up memory.stat file routine and show "total" hierarchical stat. This patch does - renamed get_all_zonestat to be get_local_zonestat. - remove old mem_cgroup_stat_desc, which is only for per-cpu stat. - add mcs_stat to cover both of per-cpu/per-lru stat. - add "total" stat of hierarchy (*) - add a callback system to scan all memcg under a root. == "total" is added. [kamezawa@localhost ~]$ cat /opt/cgroup/xxx/memory.stat cache 0 rss 0 pgpgin 0 pgpgout 0 inactive_anon 0 active_anon 0 inactive_file 0 active_file 0 unevictable 0 hierarchical_memory_limit 50331648 hierarchical_memsw_limit 9223372036854775807 total_cache 65536 total_rss 192512 total_pgpgin 218 total_pgpgout 155 total_inactive_anon 0 total_active_anon 135168 total_inactive_file 61440 total_active_file 4096 total_unevictable 0 == (*) maybe the user can do calc hierarchical stat by his own program in userland but if it can be written in clean way, it's worth to be shown, I think. Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Cc: Paul Menage <menage@google.com> Cc: Li Zefan <lizf@cn.fujitsu.com> Cc: Balbir Singh <balbir@in.ibm.com> Cc: Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp> Cc: David Rientjes <rientjes@google.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm')
-rw-r--r--mm/memcontrol.c160
1 files changed, 119 insertions, 41 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 61fd9590c135..33fc0302e29e 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -256,7 +256,7 @@ page_cgroup_zoneinfo(struct page_cgroup *pc)
256 return mem_cgroup_zoneinfo(mem, nid, zid); 256 return mem_cgroup_zoneinfo(mem, nid, zid);
257} 257}
258 258
259static unsigned long mem_cgroup_get_all_zonestat(struct mem_cgroup *mem, 259static unsigned long mem_cgroup_get_local_zonestat(struct mem_cgroup *mem,
260 enum lru_list idx) 260 enum lru_list idx)
261{ 261{
262 int nid, zid; 262 int nid, zid;
@@ -317,6 +317,42 @@ static bool mem_cgroup_is_obsolete(struct mem_cgroup *mem)
317 return css_is_removed(&mem->css); 317 return css_is_removed(&mem->css);
318} 318}
319 319
320
321/*
322 * Call callback function against all cgroup under hierarchy tree.
323 */
324static int mem_cgroup_walk_tree(struct mem_cgroup *root, void *data,
325 int (*func)(struct mem_cgroup *, void *))
326{
327 int found, ret, nextid;
328 struct cgroup_subsys_state *css;
329 struct mem_cgroup *mem;
330
331 if (!root->use_hierarchy)
332 return (*func)(root, data);
333
334 nextid = 1;
335 do {
336 ret = 0;
337 mem = NULL;
338
339 rcu_read_lock();
340 css = css_get_next(&mem_cgroup_subsys, nextid, &root->css,
341 &found);
342 if (css && css_tryget(css))
343 mem = container_of(css, struct mem_cgroup, css);
344 rcu_read_unlock();
345
346 if (mem) {
347 ret = (*func)(mem, data);
348 css_put(&mem->css);
349 }
350 nextid = found + 1;
351 } while (!ret && css);
352
353 return ret;
354}
355
320/* 356/*
321 * Following LRU functions are allowed to be used without PCG_LOCK. 357 * Following LRU functions are allowed to be used without PCG_LOCK.
322 * Operations are called by routine of global LRU independently from memcg. 358 * Operations are called by routine of global LRU independently from memcg.
@@ -510,8 +546,8 @@ static int calc_inactive_ratio(struct mem_cgroup *memcg, unsigned long *present_
510 unsigned long gb; 546 unsigned long gb;
511 unsigned long inactive_ratio; 547 unsigned long inactive_ratio;
512 548
513 inactive = mem_cgroup_get_all_zonestat(memcg, LRU_INACTIVE_ANON); 549 inactive = mem_cgroup_get_local_zonestat(memcg, LRU_INACTIVE_ANON);
514 active = mem_cgroup_get_all_zonestat(memcg, LRU_ACTIVE_ANON); 550 active = mem_cgroup_get_local_zonestat(memcg, LRU_ACTIVE_ANON);
515 551
516 gb = (inactive + active) >> (30 - PAGE_SHIFT); 552 gb = (inactive + active) >> (30 - PAGE_SHIFT);
517 if (gb) 553 if (gb)
@@ -1838,54 +1874,90 @@ static int mem_cgroup_reset(struct cgroup *cont, unsigned int event)
1838 return 0; 1874 return 0;
1839} 1875}
1840 1876
1841static const struct mem_cgroup_stat_desc { 1877
1842 const char *msg; 1878/* For read statistics */
1843 u64 unit; 1879enum {
1844} mem_cgroup_stat_desc[] = { 1880 MCS_CACHE,
1845 [MEM_CGROUP_STAT_CACHE] = { "cache", PAGE_SIZE, }, 1881 MCS_RSS,
1846 [MEM_CGROUP_STAT_RSS] = { "rss", PAGE_SIZE, }, 1882 MCS_PGPGIN,
1847 [MEM_CGROUP_STAT_PGPGIN_COUNT] = {"pgpgin", 1, }, 1883 MCS_PGPGOUT,
1848 [MEM_CGROUP_STAT_PGPGOUT_COUNT] = {"pgpgout", 1, }, 1884 MCS_INACTIVE_ANON,
1885 MCS_ACTIVE_ANON,
1886 MCS_INACTIVE_FILE,
1887 MCS_ACTIVE_FILE,
1888 MCS_UNEVICTABLE,
1889 NR_MCS_STAT,
1890};
1891
1892struct mcs_total_stat {
1893 s64 stat[NR_MCS_STAT];
1849}; 1894};
1850 1895
1896struct {
1897 char *local_name;
1898 char *total_name;
1899} memcg_stat_strings[NR_MCS_STAT] = {
1900 {"cache", "total_cache"},
1901 {"rss", "total_rss"},
1902 {"pgpgin", "total_pgpgin"},
1903 {"pgpgout", "total_pgpgout"},
1904 {"inactive_anon", "total_inactive_anon"},
1905 {"active_anon", "total_active_anon"},
1906 {"inactive_file", "total_inactive_file"},
1907 {"active_file", "total_active_file"},
1908 {"unevictable", "total_unevictable"}
1909};
1910
1911
1912static int mem_cgroup_get_local_stat(struct mem_cgroup *mem, void *data)
1913{
1914 struct mcs_total_stat *s = data;
1915 s64 val;
1916
1917 /* per cpu stat */
1918 val = mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_CACHE);
1919 s->stat[MCS_CACHE] += val * PAGE_SIZE;
1920 val = mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_RSS);
1921 s->stat[MCS_RSS] += val * PAGE_SIZE;
1922 val = mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_PGPGIN_COUNT);
1923 s->stat[MCS_PGPGIN] += val;
1924 val = mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_PGPGOUT_COUNT);
1925 s->stat[MCS_PGPGOUT] += val;
1926
1927 /* per zone stat */
1928 val = mem_cgroup_get_local_zonestat(mem, LRU_INACTIVE_ANON);
1929 s->stat[MCS_INACTIVE_ANON] += val * PAGE_SIZE;
1930 val = mem_cgroup_get_local_zonestat(mem, LRU_ACTIVE_ANON);
1931 s->stat[MCS_ACTIVE_ANON] += val * PAGE_SIZE;
1932 val = mem_cgroup_get_local_zonestat(mem, LRU_INACTIVE_FILE);
1933 s->stat[MCS_INACTIVE_FILE] += val * PAGE_SIZE;
1934 val = mem_cgroup_get_local_zonestat(mem, LRU_ACTIVE_FILE);
1935 s->stat[MCS_ACTIVE_FILE] += val * PAGE_SIZE;
1936 val = mem_cgroup_get_local_zonestat(mem, LRU_UNEVICTABLE);
1937 s->stat[MCS_UNEVICTABLE] += val * PAGE_SIZE;
1938 return 0;
1939}
1940
1941static void
1942mem_cgroup_get_total_stat(struct mem_cgroup *mem, struct mcs_total_stat *s)
1943{
1944 mem_cgroup_walk_tree(mem, s, mem_cgroup_get_local_stat);
1945}
1946
1851static int mem_control_stat_show(struct cgroup *cont, struct cftype *cft, 1947static int mem_control_stat_show(struct cgroup *cont, struct cftype *cft,
1852 struct cgroup_map_cb *cb) 1948 struct cgroup_map_cb *cb)
1853{ 1949{
1854 struct mem_cgroup *mem_cont = mem_cgroup_from_cont(cont); 1950 struct mem_cgroup *mem_cont = mem_cgroup_from_cont(cont);
1855 struct mem_cgroup_stat *stat = &mem_cont->stat; 1951 struct mcs_total_stat mystat;
1856 int i; 1952 int i;
1857 1953
1858 for (i = 0; i < ARRAY_SIZE(stat->cpustat[0].count); i++) { 1954 memset(&mystat, 0, sizeof(mystat));
1859 s64 val; 1955 mem_cgroup_get_local_stat(mem_cont, &mystat);
1860 1956
1861 val = mem_cgroup_read_stat(stat, i); 1957 for (i = 0; i < NR_MCS_STAT; i++)
1862 val *= mem_cgroup_stat_desc[i].unit; 1958 cb->fill(cb, memcg_stat_strings[i].local_name, mystat.stat[i]);
1863 cb->fill(cb, mem_cgroup_stat_desc[i].msg, val);
1864 }
1865 /* showing # of active pages */
1866 {
1867 unsigned long active_anon, inactive_anon;
1868 unsigned long active_file, inactive_file;
1869 unsigned long unevictable;
1870
1871 inactive_anon = mem_cgroup_get_all_zonestat(mem_cont,
1872 LRU_INACTIVE_ANON);
1873 active_anon = mem_cgroup_get_all_zonestat(mem_cont,
1874 LRU_ACTIVE_ANON);
1875 inactive_file = mem_cgroup_get_all_zonestat(mem_cont,
1876 LRU_INACTIVE_FILE);
1877 active_file = mem_cgroup_get_all_zonestat(mem_cont,
1878 LRU_ACTIVE_FILE);
1879 unevictable = mem_cgroup_get_all_zonestat(mem_cont,
1880 LRU_UNEVICTABLE);
1881
1882 cb->fill(cb, "active_anon", (active_anon) * PAGE_SIZE);
1883 cb->fill(cb, "inactive_anon", (inactive_anon) * PAGE_SIZE);
1884 cb->fill(cb, "active_file", (active_file) * PAGE_SIZE);
1885 cb->fill(cb, "inactive_file", (inactive_file) * PAGE_SIZE);
1886 cb->fill(cb, "unevictable", unevictable * PAGE_SIZE);
1887 1959
1888 } 1960 /* Hierarchical information */
1889 { 1961 {
1890 unsigned long long limit, memsw_limit; 1962 unsigned long long limit, memsw_limit;
1891 memcg_get_hierarchical_limit(mem_cont, &limit, &memsw_limit); 1963 memcg_get_hierarchical_limit(mem_cont, &limit, &memsw_limit);
@@ -1894,6 +1966,12 @@ static int mem_control_stat_show(struct cgroup *cont, struct cftype *cft,
1894 cb->fill(cb, "hierarchical_memsw_limit", memsw_limit); 1966 cb->fill(cb, "hierarchical_memsw_limit", memsw_limit);
1895 } 1967 }
1896 1968
1969 memset(&mystat, 0, sizeof(mystat));
1970 mem_cgroup_get_total_stat(mem_cont, &mystat);
1971 for (i = 0; i < NR_MCS_STAT; i++)
1972 cb->fill(cb, memcg_stat_strings[i].total_name, mystat.stat[i]);
1973
1974
1897#ifdef CONFIG_DEBUG_VM 1975#ifdef CONFIG_DEBUG_VM
1898 cb->fill(cb, "inactive_ratio", calc_inactive_ratio(mem_cont, NULL)); 1976 cb->fill(cb, "inactive_ratio", calc_inactive_ratio(mem_cont, NULL));
1899 1977