Commit e9f8974f2f559b00c87ccfba67bca3903f913d50

Authored by Johannes Weiner
Committed by Linus Torvalds
1 parent 7ec99d6213

memcg: break out event counters from other stats

For increasing and decreasing per-cpu cgroup usage counters it makes sense
to use signed types, as single per-cpu values might go negative during
updates.  But this is not the case for only-ever-increasing event
counters.

All the counters have been signed 64-bit so far, which was enough to count
events even with the sign bit wasted.

This patch:
- divides s64 counters into signed usage counters and unsigned
  monotonically increasing event counters.
- converts unsigned event counters into 'unsigned long' rather than
  'u64'.  This matches the type used by the /proc/vmstat event counters.

The next patch narrows the signed usage counters type (on 32-bit CPUs,
that is).

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>

Showing 1 changed file with 37 additions and 12 deletions Side-by-side Diff

... ... @@ -93,19 +93,22 @@
93 93 MEM_CGROUP_STAT_CACHE, /* # of pages charged as cache */
94 94 MEM_CGROUP_STAT_RSS, /* # of pages charged as anon rss */
95 95 MEM_CGROUP_STAT_FILE_MAPPED, /* # of pages charged as file rss */
96   - MEM_CGROUP_STAT_PGPGIN_COUNT, /* # of pages paged in */
97   - MEM_CGROUP_STAT_PGPGOUT_COUNT, /* # of pages paged out */
98 96 MEM_CGROUP_STAT_SWAPOUT, /* # of pages, swapped out */
99 97 MEM_CGROUP_STAT_DATA, /* end of data requires synchronization */
100   - /* incremented at every pagein/pageout */
101   - MEM_CGROUP_EVENTS = MEM_CGROUP_STAT_DATA,
102 98 MEM_CGROUP_ON_MOVE, /* someone is moving account between groups */
103   -
104 99 MEM_CGROUP_STAT_NSTATS,
105 100 };
106 101  
  102 +enum mem_cgroup_events_index {
  103 + MEM_CGROUP_EVENTS_PGPGIN, /* # of pages paged in */
  104 + MEM_CGROUP_EVENTS_PGPGOUT, /* # of pages paged out */
  105 + MEM_CGROUP_EVENTS_COUNT, /* # of pages paged in/out */
  106 + MEM_CGROUP_EVENTS_NSTATS,
  107 +};
  108 +
107 109 struct mem_cgroup_stat_cpu {
108 110 s64 count[MEM_CGROUP_STAT_NSTATS];
  111 + unsigned long events[MEM_CGROUP_EVENTS_NSTATS];
109 112 };
110 113  
111 114 /*
... ... @@ -577,6 +580,22 @@
577 580 this_cpu_add(mem->stat->count[MEM_CGROUP_STAT_SWAPOUT], val);
578 581 }
579 582  
  583 +static unsigned long mem_cgroup_read_events(struct mem_cgroup *mem,
  584 + enum mem_cgroup_events_index idx)
  585 +{
  586 + unsigned long val = 0;
  587 + int cpu;
  588 +
  589 + for_each_online_cpu(cpu)
  590 + val += per_cpu(mem->stat->events[idx], cpu);
  591 +#ifdef CONFIG_HOTPLUG_CPU
  592 + spin_lock(&mem->pcp_counter_lock);
  593 + val += mem->nocpu_base.events[idx];
  594 + spin_unlock(&mem->pcp_counter_lock);
  595 +#endif
  596 + return val;
  597 +}
  598 +
580 599 static void mem_cgroup_charge_statistics(struct mem_cgroup *mem,
581 600 bool file, int nr_pages)
582 601 {
583 602  
584 603  
... ... @@ -589,13 +608,13 @@
589 608  
590 609 /* pagein of a big page is an event. So, ignore page size */
591 610 if (nr_pages > 0)
592   - __this_cpu_inc(mem->stat->count[MEM_CGROUP_STAT_PGPGIN_COUNT]);
  611 + __this_cpu_inc(mem->stat->events[MEM_CGROUP_EVENTS_PGPGIN]);
593 612 else {
594   - __this_cpu_inc(mem->stat->count[MEM_CGROUP_STAT_PGPGOUT_COUNT]);
  613 + __this_cpu_inc(mem->stat->events[MEM_CGROUP_EVENTS_PGPGOUT]);
595 614 nr_pages = -nr_pages; /* for event */
596 615 }
597 616  
598   - __this_cpu_add(mem->stat->count[MEM_CGROUP_EVENTS], nr_pages);
  617 + __this_cpu_add(mem->stat->events[MEM_CGROUP_EVENTS_COUNT], nr_pages);
599 618  
600 619 preempt_enable();
601 620 }
602 621  
... ... @@ -617,9 +636,9 @@
617 636  
618 637 static bool __memcg_event_check(struct mem_cgroup *mem, int event_mask_shift)
619 638 {
620   - s64 val;
  639 + unsigned long val;
621 640  
622   - val = this_cpu_read(mem->stat->count[MEM_CGROUP_EVENTS]);
  641 + val = this_cpu_read(mem->stat->events[MEM_CGROUP_EVENTS_COUNT]);
623 642  
624 643 return !(val & ((1 << event_mask_shift) - 1));
625 644 }
... ... @@ -1773,6 +1792,12 @@
1773 1792 per_cpu(mem->stat->count[i], cpu) = 0;
1774 1793 mem->nocpu_base.count[i] += x;
1775 1794 }
  1795 + for (i = 0; i < MEM_CGROUP_EVENTS_NSTATS; i++) {
  1796 + unsigned long x = per_cpu(mem->stat->events[i], cpu);
  1797 +
  1798 + per_cpu(mem->stat->events[i], cpu) = 0;
  1799 + mem->nocpu_base.events[i] += x;
  1800 + }
1776 1801 /* need to clear ON_MOVE value, works as a kind of lock. */
1777 1802 per_cpu(mem->stat->count[MEM_CGROUP_ON_MOVE], cpu) = 0;
1778 1803 spin_unlock(&mem->pcp_counter_lock);
1779 1804  
... ... @@ -3725,9 +3750,9 @@
3725 3750 s->stat[MCS_RSS] += val * PAGE_SIZE;
3726 3751 val = mem_cgroup_read_stat(mem, MEM_CGROUP_STAT_FILE_MAPPED);
3727 3752 s->stat[MCS_FILE_MAPPED] += val * PAGE_SIZE;
3728   - val = mem_cgroup_read_stat(mem, MEM_CGROUP_STAT_PGPGIN_COUNT);
  3753 + val = mem_cgroup_read_events(mem, MEM_CGROUP_EVENTS_PGPGIN);
3729 3754 s->stat[MCS_PGPGIN] += val;
3730   - val = mem_cgroup_read_stat(mem, MEM_CGROUP_STAT_PGPGOUT_COUNT);
  3755 + val = mem_cgroup_read_events(mem, MEM_CGROUP_EVENTS_PGPGOUT);
3731 3756 s->stat[MCS_PGPGOUT] += val;
3732 3757 if (do_swap_account) {
3733 3758 val = mem_cgroup_read_stat(mem, MEM_CGROUP_STAT_SWAPOUT);