aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
Diffstat (limited to 'mm')
-rw-r--r--mm/memcontrol.c88
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 */
105enum 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
109struct mem_cgroup_stat_cpu { 113struct 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 */
549static s64 mem_cgroup_read_stat(struct mem_cgroup *mem, 554static 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
567static s64 mem_cgroup_local_usage(struct mem_cgroup *mem) 572static 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
637static bool __memcg_event_check(struct mem_cgroup *mem, int event_mask_shift) 642static 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
652static 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)
650static void memcg_check_events(struct mem_cgroup *mem, struct page *page) 676static 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
3502static u64 mem_cgroup_get_recursive_idx_stat(struct mem_cgroup *mem, 3533static 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}