diff options
author | Johannes Weiner <hannes@cmpxchg.org> | 2011-03-23 19:42:38 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-23 22:46:31 -0400 |
commit | 7a159cc9d7987cdb4853f8711f5f89e01cfffe42 (patch) | |
tree | 027e8468d40bfdb51ad9694ec1d5256bb2fdb36f /mm/memcontrol.c | |
parent | e9f8974f2f559b00c87ccfba67bca3903f913d50 (diff) |
memcg: use native word page statistics counters
The statistic counters are in units of pages, there is no reason to make
them 64-bit wide on 32-bit machines.
Make them native words. Since they are signed, this leaves 31 bit on
32-bit machines, which can represent roughly 8TB assuming a page size of
4k.
[akpm@linux-foundation.org: coding-style fixes]
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Signed-off-by: Greg Thelen <gthelen@google.com>
Acked-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Acked-by: Balbir Singh <balbir@linux.vnet.ibm.com>
Cc: Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp>
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 | 88 |
1 files changed, 59 insertions, 29 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index d884f758c0e3..e5759b51f37e 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
@@ -73,15 +73,6 @@ static int really_do_swap_account __initdata = 0; | |||
73 | #define do_swap_account (0) | 73 | #define do_swap_account (0) |
74 | #endif | 74 | #endif |
75 | 75 | ||
76 | /* | ||
77 | * Per memcg event counter is incremented at every pagein/pageout. This counter | ||
78 | * is used for trigger some periodic events. This is straightforward and better | ||
79 | * than using jiffies etc. to handle periodic memcg event. | ||
80 | * | ||
81 | * These values will be used as !((event) & ((1 <<(thresh)) - 1)) | ||
82 | */ | ||
83 | #define THRESHOLDS_EVENTS_THRESH (7) /* once in 128 */ | ||
84 | #define SOFTLIMIT_EVENTS_THRESH (10) /* once in 1024 */ | ||
85 | 76 | ||
86 | /* | 77 | /* |
87 | * Statistics for memory cgroup. | 78 | * Statistics for memory cgroup. |
@@ -105,10 +96,24 @@ enum mem_cgroup_events_index { | |||
105 | MEM_CGROUP_EVENTS_COUNT, /* # of pages paged in/out */ | 96 | MEM_CGROUP_EVENTS_COUNT, /* # of pages paged in/out */ |
106 | MEM_CGROUP_EVENTS_NSTATS, | 97 | MEM_CGROUP_EVENTS_NSTATS, |
107 | }; | 98 | }; |
99 | /* | ||
100 | * Per memcg event counter is incremented at every pagein/pageout. With THP, | ||
101 | * it will be incremated by the number of pages. This counter is used for | ||
102 | * for trigger some periodic events. This is straightforward and better | ||
103 | * than using jiffies etc. to handle periodic memcg event. | ||
104 | */ | ||
105 | enum mem_cgroup_events_target { | ||
106 | MEM_CGROUP_TARGET_THRESH, | ||
107 | MEM_CGROUP_TARGET_SOFTLIMIT, | ||
108 | MEM_CGROUP_NTARGETS, | ||
109 | }; | ||
110 | #define THRESHOLDS_EVENTS_TARGET (128) | ||
111 | #define SOFTLIMIT_EVENTS_TARGET (1024) | ||
108 | 112 | ||
109 | struct mem_cgroup_stat_cpu { | 113 | struct mem_cgroup_stat_cpu { |
110 | s64 count[MEM_CGROUP_STAT_NSTATS]; | 114 | long count[MEM_CGROUP_STAT_NSTATS]; |
111 | unsigned long events[MEM_CGROUP_EVENTS_NSTATS]; | 115 | unsigned long events[MEM_CGROUP_EVENTS_NSTATS]; |
116 | unsigned long targets[MEM_CGROUP_NTARGETS]; | ||
112 | }; | 117 | }; |
113 | 118 | ||
114 | /* | 119 | /* |
@@ -546,11 +551,11 @@ mem_cgroup_largest_soft_limit_node(struct mem_cgroup_tree_per_zone *mctz) | |||
546 | * common workload, threashold and synchonization as vmstat[] should be | 551 | * common workload, threashold and synchonization as vmstat[] should be |
547 | * implemented. | 552 | * implemented. |
548 | */ | 553 | */ |
549 | static s64 mem_cgroup_read_stat(struct mem_cgroup *mem, | 554 | static long mem_cgroup_read_stat(struct mem_cgroup *mem, |
550 | enum mem_cgroup_stat_index idx) | 555 | enum mem_cgroup_stat_index idx) |
551 | { | 556 | { |
557 | long val = 0; | ||
552 | int cpu; | 558 | int cpu; |
553 | s64 val = 0; | ||
554 | 559 | ||
555 | get_online_cpus(); | 560 | get_online_cpus(); |
556 | for_each_online_cpu(cpu) | 561 | for_each_online_cpu(cpu) |
@@ -564,9 +569,9 @@ static s64 mem_cgroup_read_stat(struct mem_cgroup *mem, | |||
564 | return val; | 569 | return val; |
565 | } | 570 | } |
566 | 571 | ||
567 | static s64 mem_cgroup_local_usage(struct mem_cgroup *mem) | 572 | static long mem_cgroup_local_usage(struct mem_cgroup *mem) |
568 | { | 573 | { |
569 | s64 ret; | 574 | long ret; |
570 | 575 | ||
571 | ret = mem_cgroup_read_stat(mem, MEM_CGROUP_STAT_RSS); | 576 | ret = mem_cgroup_read_stat(mem, MEM_CGROUP_STAT_RSS); |
572 | ret += mem_cgroup_read_stat(mem, MEM_CGROUP_STAT_CACHE); | 577 | ret += mem_cgroup_read_stat(mem, MEM_CGROUP_STAT_CACHE); |
@@ -634,13 +639,34 @@ static unsigned long mem_cgroup_get_local_zonestat(struct mem_cgroup *mem, | |||
634 | return total; | 639 | return total; |
635 | } | 640 | } |
636 | 641 | ||
637 | static bool __memcg_event_check(struct mem_cgroup *mem, int event_mask_shift) | 642 | static bool __memcg_event_check(struct mem_cgroup *mem, int target) |
643 | { | ||
644 | unsigned long val, next; | ||
645 | |||
646 | val = this_cpu_read(mem->stat->events[MEM_CGROUP_EVENTS_COUNT]); | ||
647 | next = this_cpu_read(mem->stat->targets[target]); | ||
648 | /* from time_after() in jiffies.h */ | ||
649 | return ((long)next - (long)val < 0); | ||
650 | } | ||
651 | |||
652 | static void __mem_cgroup_target_update(struct mem_cgroup *mem, int target) | ||
638 | { | 653 | { |
639 | unsigned long val; | 654 | unsigned long val, next; |
640 | 655 | ||
641 | val = this_cpu_read(mem->stat->events[MEM_CGROUP_EVENTS_COUNT]); | 656 | val = this_cpu_read(mem->stat->events[MEM_CGROUP_EVENTS_COUNT]); |
642 | 657 | ||
643 | return !(val & ((1 << event_mask_shift) - 1)); | 658 | switch (target) { |
659 | case MEM_CGROUP_TARGET_THRESH: | ||
660 | next = val + THRESHOLDS_EVENTS_TARGET; | ||
661 | break; | ||
662 | case MEM_CGROUP_TARGET_SOFTLIMIT: | ||
663 | next = val + SOFTLIMIT_EVENTS_TARGET; | ||
664 | break; | ||
665 | default: | ||
666 | return; | ||
667 | } | ||
668 | |||
669 | this_cpu_write(mem->stat->targets[target], next); | ||
644 | } | 670 | } |
645 | 671 | ||
646 | /* | 672 | /* |
@@ -650,10 +676,15 @@ static bool __memcg_event_check(struct mem_cgroup *mem, int event_mask_shift) | |||
650 | static void memcg_check_events(struct mem_cgroup *mem, struct page *page) | 676 | static void memcg_check_events(struct mem_cgroup *mem, struct page *page) |
651 | { | 677 | { |
652 | /* threshold event is triggered in finer grain than soft limit */ | 678 | /* threshold event is triggered in finer grain than soft limit */ |
653 | if (unlikely(__memcg_event_check(mem, THRESHOLDS_EVENTS_THRESH))) { | 679 | if (unlikely(__memcg_event_check(mem, MEM_CGROUP_TARGET_THRESH))) { |
654 | mem_cgroup_threshold(mem); | 680 | mem_cgroup_threshold(mem); |
655 | if (unlikely(__memcg_event_check(mem, SOFTLIMIT_EVENTS_THRESH))) | 681 | __mem_cgroup_target_update(mem, MEM_CGROUP_TARGET_THRESH); |
682 | if (unlikely(__memcg_event_check(mem, | ||
683 | MEM_CGROUP_TARGET_SOFTLIMIT))){ | ||
656 | mem_cgroup_update_tree(mem, page); | 684 | mem_cgroup_update_tree(mem, page); |
685 | __mem_cgroup_target_update(mem, | ||
686 | MEM_CGROUP_TARGET_SOFTLIMIT); | ||
687 | } | ||
657 | } | 688 | } |
658 | } | 689 | } |
659 | 690 | ||
@@ -1787,7 +1818,7 @@ static void mem_cgroup_drain_pcp_counter(struct mem_cgroup *mem, int cpu) | |||
1787 | 1818 | ||
1788 | spin_lock(&mem->pcp_counter_lock); | 1819 | spin_lock(&mem->pcp_counter_lock); |
1789 | for (i = 0; i < MEM_CGROUP_STAT_DATA; i++) { | 1820 | for (i = 0; i < MEM_CGROUP_STAT_DATA; i++) { |
1790 | s64 x = per_cpu(mem->stat->count[i], cpu); | 1821 | long x = per_cpu(mem->stat->count[i], cpu); |
1791 | 1822 | ||
1792 | per_cpu(mem->stat->count[i], cpu) = 0; | 1823 | per_cpu(mem->stat->count[i], cpu) = 0; |
1793 | mem->nocpu_base.count[i] += x; | 1824 | mem->nocpu_base.count[i] += x; |
@@ -3499,13 +3530,13 @@ static int mem_cgroup_hierarchy_write(struct cgroup *cont, struct cftype *cft, | |||
3499 | } | 3530 | } |
3500 | 3531 | ||
3501 | 3532 | ||
3502 | static u64 mem_cgroup_get_recursive_idx_stat(struct mem_cgroup *mem, | 3533 | static unsigned long mem_cgroup_recursive_stat(struct mem_cgroup *mem, |
3503 | enum mem_cgroup_stat_index idx) | 3534 | enum mem_cgroup_stat_index idx) |
3504 | { | 3535 | { |
3505 | struct mem_cgroup *iter; | 3536 | struct mem_cgroup *iter; |
3506 | s64 val = 0; | 3537 | long val = 0; |
3507 | 3538 | ||
3508 | /* each per cpu's value can be minus.Then, use s64 */ | 3539 | /* Per-cpu values can be negative, use a signed accumulator */ |
3509 | for_each_mem_cgroup_tree(iter, mem) | 3540 | for_each_mem_cgroup_tree(iter, mem) |
3510 | val += mem_cgroup_read_stat(iter, idx); | 3541 | val += mem_cgroup_read_stat(iter, idx); |
3511 | 3542 | ||
@@ -3525,12 +3556,11 @@ static inline u64 mem_cgroup_usage(struct mem_cgroup *mem, bool swap) | |||
3525 | return res_counter_read_u64(&mem->memsw, RES_USAGE); | 3556 | return res_counter_read_u64(&mem->memsw, RES_USAGE); |
3526 | } | 3557 | } |
3527 | 3558 | ||
3528 | val = mem_cgroup_get_recursive_idx_stat(mem, MEM_CGROUP_STAT_CACHE); | 3559 | val = mem_cgroup_recursive_stat(mem, MEM_CGROUP_STAT_CACHE); |
3529 | val += mem_cgroup_get_recursive_idx_stat(mem, MEM_CGROUP_STAT_RSS); | 3560 | val += mem_cgroup_recursive_stat(mem, MEM_CGROUP_STAT_RSS); |
3530 | 3561 | ||
3531 | if (swap) | 3562 | if (swap) |
3532 | val += mem_cgroup_get_recursive_idx_stat(mem, | 3563 | val += mem_cgroup_recursive_stat(mem, MEM_CGROUP_STAT_SWAPOUT); |
3533 | MEM_CGROUP_STAT_SWAPOUT); | ||
3534 | 3564 | ||
3535 | return val << PAGE_SHIFT; | 3565 | return val << PAGE_SHIFT; |
3536 | } | 3566 | } |