diff options
author | Sha Zhengju <handai.szj@taobao.com> | 2013-02-22 19:32:05 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-23 20:50:08 -0500 |
commit | 58cf188ed649b6570dfdc9c62156cdf396c2e395 (patch) | |
tree | 673857c75b2db02433335a5e605a439e61d023d5 /mm/memcontrol.c | |
parent | df8557982fb3fa0a1e638cd1bf7b7092a202fa32 (diff) |
memcg, oom: provide more precise dump info while memcg oom happening
Currently when a memcg oom is happening the oom dump messages is still
global state and provides few useful info for users. This patch prints
more pointed memcg page statistics for memcg-oom and take hierarchy into
consideration:
Based on Michal's advice, we take hierarchy into consideration: supppose
we trigger an OOM on A's limit
root_memcg
|
A (use_hierachy=1)
/ \
B C
|
D
then the printed info will be:
Memory cgroup stats for /A:...
Memory cgroup stats for /A/B:...
Memory cgroup stats for /A/C:...
Memory cgroup stats for /A/B/D:...
Following are samples of oom output:
(1) Before change:
mal-80 invoked oom-killer:gfp_mask=0xd0, order=0, oom_score_adj=0
mal-80 cpuset=/ mems_allowed=0
Pid: 2976, comm: mal-80 Not tainted 3.7.0+ #10
Call Trace:
[<ffffffff8167fbfb>] dump_header+0x83/0x1ca
..... (call trace)
[<ffffffff8168a818>] page_fault+0x28/0x30
<<<<<<<<<<<<<<<<<<<<< memcg specific information
Task in /A/B/D killed as a result of limit of /A
memory: usage 101376kB, limit 101376kB, failcnt 57
memory+swap: usage 101376kB, limit 101376kB, failcnt 0
kmem: usage 0kB, limit 9007199254740991kB, failcnt 0
<<<<<<<<<<<<<<<<<<<<< print per cpu pageset stat
Mem-Info:
Node 0 DMA per-cpu:
CPU 0: hi: 0, btch: 1 usd: 0
......
CPU 3: hi: 0, btch: 1 usd: 0
Node 0 DMA32 per-cpu:
CPU 0: hi: 186, btch: 31 usd: 173
......
CPU 3: hi: 186, btch: 31 usd: 130
<<<<<<<<<<<<<<<<<<<<< print global page state
active_anon:92963 inactive_anon:40777 isolated_anon:0
active_file:33027 inactive_file:51718 isolated_file:0
unevictable:0 dirty:3 writeback:0 unstable:0
free:729995 slab_reclaimable:6897 slab_unreclaimable:6263
mapped:20278 shmem:35971 pagetables:5885 bounce:0
free_cma:0
<<<<<<<<<<<<<<<<<<<<< print per zone page state
Node 0 DMA free:15836kB ... all_unreclaimable? no
lowmem_reserve[]: 0 3175 3899 3899
Node 0 DMA32 free:2888564kB ... all_unrelaimable? no
lowmem_reserve[]: 0 0 724 724
lowmem_reserve[]: 0 0 0 0
Node 0 DMA: 1*4kB (U) ... 3*4096kB (M) = 15836kB
Node 0 DMA32: 41*4kB (UM) ... 702*4096kB (MR) = 2888316kB
120710 total pagecache pages
0 pages in swap cache
<<<<<<<<<<<<<<<<<<<<< print global swap cache stat
Swap cache stats: add 0, delete 0, find 0/0
Free swap = 499708kB
Total swap = 499708kB
1040368 pages RAM
58678 pages reserved
169065 pages shared
173632 pages non-shared
[ pid ] uid tgid total_vm rss nr_ptes swapents oom_score_adj name
[ 2693] 0 2693 6005 1324 17 0 0 god
[ 2754] 0 2754 6003 1320 16 0 0 god
[ 2811] 0 2811 5992 1304 18 0 0 god
[ 2874] 0 2874 6005 1323 18 0 0 god
[ 2935] 0 2935 8720 7742 21 0 0 mal-30
[ 2976] 0 2976 21520 17577 42 0 0 mal-80
Memory cgroup out of memory: Kill process 2976 (mal-80) score 665 or sacrifice child
Killed process 2976 (mal-80) total-vm:86080kB, anon-rss:69964kB, file-rss:344kB
We can see that messages dumped by show_free_areas() are longsome and can
provide so limited info for memcg that just happen oom.
(2) After change
mal-80 invoked oom-killer: gfp_mask=0xd0, order=0, oom_score_adj=0
mal-80 cpuset=/ mems_allowed=0
Pid: 2704, comm: mal-80 Not tainted 3.7.0+ #10
Call Trace:
[<ffffffff8167fd0b>] dump_header+0x83/0x1d1
.......(call trace)
[<ffffffff8168a918>] page_fault+0x28/0x30
Task in /A/B/D killed as a result of limit of /A
<<<<<<<<<<<<<<<<<<<<< memcg specific information
memory: usage 102400kB, limit 102400kB, failcnt 140
memory+swap: usage 102400kB, limit 102400kB, failcnt 0
kmem: usage 0kB, limit 9007199254740991kB, failcnt 0
Memory cgroup stats for /A: cache:32KB rss:30984KB mapped_file:0KB swap:0KB inactive_anon:6912KB active_anon:24072KB inactive_file:32KB active_file:0KB unevictable:0KB
Memory cgroup stats for /A/B: cache:0KB rss:0KB mapped_file:0KB swap:0KB inactive_anon:0KB active_anon:0KB inactive_file:0KB active_file:0KB unevictable:0KB
Memory cgroup stats for /A/C: cache:0KB rss:0KB mapped_file:0KB swap:0KB inactive_anon:0KB active_anon:0KB inactive_file:0KB active_file:0KB unevictable:0KB
Memory cgroup stats for /A/B/D: cache:32KB rss:71352KB mapped_file:0KB swap:0KB inactive_anon:6656KB active_anon:64696KB inactive_file:16KB active_file:16KB unevictable:0KB
[ pid ] uid tgid total_vm rss nr_ptes swapents oom_score_adj name
[ 2260] 0 2260 6006 1325 18 0 0 god
[ 2383] 0 2383 6003 1319 17 0 0 god
[ 2503] 0 2503 6004 1321 18 0 0 god
[ 2622] 0 2622 6004 1321 16 0 0 god
[ 2695] 0 2695 8720 7741 22 0 0 mal-30
[ 2704] 0 2704 21520 17839 43 0 0 mal-80
Memory cgroup out of memory: Kill process 2704 (mal-80) score 669 or sacrifice child
Killed process 2704 (mal-80) total-vm:86080kB, anon-rss:71016kB, file-rss:340kB
This version provides more pointed info for memcg in "Memory cgroup stats
for XXX" section.
Signed-off-by: Sha Zhengju <handai.szj@taobao.com>
Acked-by: Michal Hocko <mhocko@suse.cz>
Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Acked-by: 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/memcontrol.c')
-rw-r--r-- | mm/memcontrol.c | 47 |
1 files changed, 37 insertions, 10 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index fbb60b103e64..07bf3ec13a07 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
@@ -120,6 +120,14 @@ static const char * const mem_cgroup_events_names[] = { | |||
120 | "pgmajfault", | 120 | "pgmajfault", |
121 | }; | 121 | }; |
122 | 122 | ||
123 | static const char * const mem_cgroup_lru_names[] = { | ||
124 | "inactive_anon", | ||
125 | "active_anon", | ||
126 | "inactive_file", | ||
127 | "active_file", | ||
128 | "unevictable", | ||
129 | }; | ||
130 | |||
123 | /* | 131 | /* |
124 | * Per memcg event counter is incremented at every pagein/pageout. With THP, | 132 | * Per memcg event counter is incremented at every pagein/pageout. With THP, |
125 | * it will be incremated by the number of pages. This counter is used for | 133 | * it will be incremated by the number of pages. This counter is used for |
@@ -1524,8 +1532,9 @@ static void move_unlock_mem_cgroup(struct mem_cgroup *memcg, | |||
1524 | spin_unlock_irqrestore(&memcg->move_lock, *flags); | 1532 | spin_unlock_irqrestore(&memcg->move_lock, *flags); |
1525 | } | 1533 | } |
1526 | 1534 | ||
1535 | #define K(x) ((x) << (PAGE_SHIFT-10)) | ||
1527 | /** | 1536 | /** |
1528 | * mem_cgroup_print_oom_info: Called from OOM with tasklist_lock held in read mode. | 1537 | * mem_cgroup_print_oom_info: Print OOM information relevant to memory controller. |
1529 | * @memcg: The memory cgroup that went over limit | 1538 | * @memcg: The memory cgroup that went over limit |
1530 | * @p: Task that is going to be killed | 1539 | * @p: Task that is going to be killed |
1531 | * | 1540 | * |
@@ -1543,8 +1552,10 @@ void mem_cgroup_print_oom_info(struct mem_cgroup *memcg, struct task_struct *p) | |||
1543 | */ | 1552 | */ |
1544 | static char memcg_name[PATH_MAX]; | 1553 | static char memcg_name[PATH_MAX]; |
1545 | int ret; | 1554 | int ret; |
1555 | struct mem_cgroup *iter; | ||
1556 | unsigned int i; | ||
1546 | 1557 | ||
1547 | if (!memcg || !p) | 1558 | if (!p) |
1548 | return; | 1559 | return; |
1549 | 1560 | ||
1550 | rcu_read_lock(); | 1561 | rcu_read_lock(); |
@@ -1592,6 +1603,30 @@ done: | |||
1592 | res_counter_read_u64(&memcg->kmem, RES_USAGE) >> 10, | 1603 | res_counter_read_u64(&memcg->kmem, RES_USAGE) >> 10, |
1593 | res_counter_read_u64(&memcg->kmem, RES_LIMIT) >> 10, | 1604 | res_counter_read_u64(&memcg->kmem, RES_LIMIT) >> 10, |
1594 | res_counter_read_u64(&memcg->kmem, RES_FAILCNT)); | 1605 | res_counter_read_u64(&memcg->kmem, RES_FAILCNT)); |
1606 | |||
1607 | for_each_mem_cgroup_tree(iter, memcg) { | ||
1608 | pr_info("Memory cgroup stats"); | ||
1609 | |||
1610 | rcu_read_lock(); | ||
1611 | ret = cgroup_path(iter->css.cgroup, memcg_name, PATH_MAX); | ||
1612 | if (!ret) | ||
1613 | pr_cont(" for %s", memcg_name); | ||
1614 | rcu_read_unlock(); | ||
1615 | pr_cont(":"); | ||
1616 | |||
1617 | for (i = 0; i < MEM_CGROUP_STAT_NSTATS; i++) { | ||
1618 | if (i == MEM_CGROUP_STAT_SWAP && !do_swap_account) | ||
1619 | continue; | ||
1620 | pr_cont(" %s:%ldKB", mem_cgroup_stat_names[i], | ||
1621 | K(mem_cgroup_read_stat(iter, i))); | ||
1622 | } | ||
1623 | |||
1624 | for (i = 0; i < NR_LRU_LISTS; i++) | ||
1625 | pr_cont(" %s:%luKB", mem_cgroup_lru_names[i], | ||
1626 | K(mem_cgroup_nr_lru_pages(iter, BIT(i)))); | ||
1627 | |||
1628 | pr_cont("\n"); | ||
1629 | } | ||
1595 | } | 1630 | } |
1596 | 1631 | ||
1597 | /* | 1632 | /* |
@@ -5214,14 +5249,6 @@ static int memcg_numa_stat_show(struct cgroup *cont, struct cftype *cft, | |||
5214 | } | 5249 | } |
5215 | #endif /* CONFIG_NUMA */ | 5250 | #endif /* CONFIG_NUMA */ |
5216 | 5251 | ||
5217 | static const char * const mem_cgroup_lru_names[] = { | ||
5218 | "inactive_anon", | ||
5219 | "active_anon", | ||
5220 | "inactive_file", | ||
5221 | "active_file", | ||
5222 | "unevictable", | ||
5223 | }; | ||
5224 | |||
5225 | static inline void mem_cgroup_lru_names_not_uptodate(void) | 5252 | static inline void mem_cgroup_lru_names_not_uptodate(void) |
5226 | { | 5253 | { |
5227 | BUILD_BUG_ON(ARRAY_SIZE(mem_cgroup_lru_names) != NR_LRU_LISTS); | 5254 | BUILD_BUG_ON(ARRAY_SIZE(mem_cgroup_lru_names) != NR_LRU_LISTS); |