From mboxrd@z Thu Jan 1 00:00:00 1970 From: Greg Thelen Subject: [PATCH v4 06/11] memcg: add dirty page accounting infrastructure Date: Fri, 29 Oct 2010 00:09:09 -0700 Message-ID: <1288336154-23256-7-git-send-email-gthelen@google.com> References: <1288336154-23256-1-git-send-email-gthelen@google.com> Return-path: In-Reply-To: <1288336154-23256-1-git-send-email-gthelen@google.com> Sender: owner-linux-mm@kvack.org To: Andrew Morton Cc: linux-kernel@vger.kernel.org, linux-mm@kvack.org, containers@lists.osdl.org, Andrea Righi , Balbir Singh , KAMEZAWA Hiroyuki , Daisuke Nishimura , Minchan Kim , Ciju Rajan K , David Rientjes , Wu Fengguang , Greg Thelen List-Id: containers.vger.kernel.org Add memcg routines to track dirty, writeback, and unstable_NFS pages. These routines are not yet used by the kernel to count such pages. A later change adds kernel calls to these new routines. Signed-off-by: Greg Thelen Signed-off-by: Andrea Righi Acked-by: KAMEZAWA Hiroyuki Acked-by: Daisuke Nishimura --- Changelog since v1: - Renamed "nfs"/"total_nfs" to "nfs_unstable"/"total_nfs_unstable" in per cgroup memory.stat to match /proc/meminfo. - Rename (for clarity): - mem_cgroup_write_page_stat_item -> mem_cgroup_page_stat_item - mem_cgroup_read_page_stat_item -> mem_cgroup_nr_pages_item - Remove redundant comments. - Made mem_cgroup_move_account_page_stat() inline. include/linux/memcontrol.h | 3 ++ mm/memcontrol.c | 86 +++++++++++++++++++++++++++++++++++++++---- 2 files changed, 81 insertions(+), 8 deletions(-) diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index 067115c..ef2eec7 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h @@ -28,6 +28,9 @@ struct mm_struct; /* Stats that can be updated by kernel. */ enum mem_cgroup_page_stat_item { MEMCG_NR_FILE_MAPPED, /* # of pages charged as file rss */ + MEMCG_NR_FILE_DIRTY, /* # of dirty pages in page cache */ + MEMCG_NR_FILE_WRITEBACK, /* # of pages under writeback */ + MEMCG_NR_FILE_UNSTABLE_NFS, /* # of NFS unstable pages */ }; extern unsigned long mem_cgroup_isolate_pages(unsigned long nr_to_scan, diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 94359d6..7f91029 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -85,10 +85,13 @@ enum mem_cgroup_stat_index { */ MEM_CGROUP_STAT_CACHE, /* # of pages charged as cache */ MEM_CGROUP_STAT_RSS, /* # of pages charged as anon rss */ - MEM_CGROUP_STAT_FILE_MAPPED, /* # of pages charged as file rss */ MEM_CGROUP_STAT_PGPGIN_COUNT, /* # of pages paged in */ MEM_CGROUP_STAT_PGPGOUT_COUNT, /* # of pages paged out */ MEM_CGROUP_STAT_SWAPOUT, /* # of pages, swapped out */ + MEM_CGROUP_STAT_FILE_MAPPED, /* # of pages charged as file rss */ + MEM_CGROUP_STAT_FILE_DIRTY, /* # of dirty pages in page cache */ + MEM_CGROUP_STAT_FILE_WRITEBACK, /* # of pages under writeback */ + MEM_CGROUP_STAT_FILE_UNSTABLE_NFS, /* # of NFS unstable pages */ MEM_CGROUP_STAT_DATA, /* end of data requires synchronization */ /* incremented at every pagein/pageout */ MEM_CGROUP_EVENTS = MEM_CGROUP_STAT_DATA, @@ -1625,6 +1628,44 @@ void mem_cgroup_update_page_stat(struct page *page, ClearPageCgroupFileMapped(pc); idx = MEM_CGROUP_STAT_FILE_MAPPED; break; + + case MEMCG_NR_FILE_DIRTY: + /* Use Test{Set,Clear} to only un/charge the memcg once. */ + if (val > 0) { + if (TestSetPageCgroupFileDirty(pc)) + val = 0; + } else { + if (!TestClearPageCgroupFileDirty(pc)) + val = 0; + } + idx = MEM_CGROUP_STAT_FILE_DIRTY; + break; + + case MEMCG_NR_FILE_WRITEBACK: + /* + * This counter is adjusted while holding the mapping's + * tree_lock. Therefore there is no race between settings and + * clearing of this flag. + */ + if (val > 0) + SetPageCgroupFileWriteback(pc); + else + ClearPageCgroupFileWriteback(pc); + idx = MEM_CGROUP_STAT_FILE_WRITEBACK; + break; + + case MEMCG_NR_FILE_UNSTABLE_NFS: + /* Use Test{Set,Clear} to only un/charge the memcg once. */ + if (val > 0) { + if (TestSetPageCgroupFileUnstableNFS(pc)) + val = 0; + } else { + if (!TestClearPageCgroupFileUnstableNFS(pc)) + val = 0; + } + idx = MEM_CGROUP_STAT_FILE_UNSTABLE_NFS; + break; + default: BUG(); } @@ -2129,6 +2170,17 @@ static void __mem_cgroup_commit_charge(struct mem_cgroup *mem, memcg_check_events(mem, pc->page); } +static inline +void mem_cgroup_move_account_page_stat(struct mem_cgroup *from, + struct mem_cgroup *to, + enum mem_cgroup_stat_index idx) +{ + preempt_disable(); + __this_cpu_dec(from->stat->count[idx]); + __this_cpu_inc(to->stat->count[idx]); + preempt_enable(); +} + /** * __mem_cgroup_move_account - move account of the page * @pc: page_cgroup of the page. @@ -2155,13 +2207,18 @@ static void __mem_cgroup_move_account(struct page_cgroup *pc, VM_BUG_ON(!PageCgroupUsed(pc)); VM_BUG_ON(pc->mem_cgroup != from); - if (PageCgroupFileMapped(pc)) { - /* Update mapped_file data for mem_cgroup */ - preempt_disable(); - __this_cpu_dec(from->stat->count[MEM_CGROUP_STAT_FILE_MAPPED]); - __this_cpu_inc(to->stat->count[MEM_CGROUP_STAT_FILE_MAPPED]); - preempt_enable(); - } + if (PageCgroupFileMapped(pc)) + mem_cgroup_move_account_page_stat(from, to, + MEM_CGROUP_STAT_FILE_MAPPED); + if (PageCgroupFileDirty(pc)) + mem_cgroup_move_account_page_stat(from, to, + MEM_CGROUP_STAT_FILE_DIRTY); + if (PageCgroupFileWriteback(pc)) + mem_cgroup_move_account_page_stat(from, to, + MEM_CGROUP_STAT_FILE_WRITEBACK); + if (PageCgroupFileUnstableNFS(pc)) + mem_cgroup_move_account_page_stat(from, to, + MEM_CGROUP_STAT_FILE_UNSTABLE_NFS); mem_cgroup_charge_statistics(from, pc, false); if (uncharge) /* This is not "cancel", but cancel_charge does all we need. */ @@ -3540,6 +3597,9 @@ enum { MCS_PGPGIN, MCS_PGPGOUT, MCS_SWAP, + MCS_FILE_DIRTY, + MCS_WRITEBACK, + MCS_UNSTABLE_NFS, MCS_INACTIVE_ANON, MCS_ACTIVE_ANON, MCS_INACTIVE_FILE, @@ -3562,6 +3622,9 @@ struct { {"pgpgin", "total_pgpgin"}, {"pgpgout", "total_pgpgout"}, {"swap", "total_swap"}, + {"dirty", "total_dirty"}, + {"writeback", "total_writeback"}, + {"nfs_unstable", "total_nfs_unstable"}, {"inactive_anon", "total_inactive_anon"}, {"active_anon", "total_active_anon"}, {"inactive_file", "total_inactive_file"}, @@ -3591,6 +3654,13 @@ mem_cgroup_get_local_stat(struct mem_cgroup *mem, struct mcs_total_stat *s) s->stat[MCS_SWAP] += val * PAGE_SIZE; } + val = mem_cgroup_read_stat(mem, MEM_CGROUP_STAT_FILE_DIRTY); + s->stat[MCS_FILE_DIRTY] += val * PAGE_SIZE; + val = mem_cgroup_read_stat(mem, MEM_CGROUP_STAT_FILE_WRITEBACK); + s->stat[MCS_WRITEBACK] += val * PAGE_SIZE; + val = mem_cgroup_read_stat(mem, MEM_CGROUP_STAT_FILE_UNSTABLE_NFS); + s->stat[MCS_UNSTABLE_NFS] += val * PAGE_SIZE; + /* per zone stat */ val = mem_cgroup_get_local_zonestat(mem, LRU_INACTIVE_ANON); s->stat[MCS_INACTIVE_ANON] += val * PAGE_SIZE; -- 1.7.3.1 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: email@kvack.org From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933551Ab0J2HOV (ORCPT ); Fri, 29 Oct 2010 03:14:21 -0400 Received: from smtp-out.google.com ([216.239.44.51]:7989 "EHLO smtp-out.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933422Ab0J2HOO (ORCPT ); Fri, 29 Oct 2010 03:14:14 -0400 DomainKey-Signature: a=rsa-sha1; s=beta; d=google.com; c=nofws; q=dns; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references; b=IGC8YcSYb77vHD5Tpm9RGwmOhds+k9p5snyOOOBwxL7eebK6oh/NL0LKgTbltSq85 mRlIH+32/o2Gwa7gjo1Ug== From: Greg Thelen To: Andrew Morton Cc: linux-kernel@vger.kernel.org, linux-mm@kvack.org, containers@lists.osdl.org, Andrea Righi , Balbir Singh , KAMEZAWA Hiroyuki , Daisuke Nishimura , Minchan Kim , Ciju Rajan K , David Rientjes , Wu Fengguang , Greg Thelen Subject: [PATCH v4 06/11] memcg: add dirty page accounting infrastructure Date: Fri, 29 Oct 2010 00:09:09 -0700 Message-Id: <1288336154-23256-7-git-send-email-gthelen@google.com> X-Mailer: git-send-email 1.7.3.1 In-Reply-To: <1288336154-23256-1-git-send-email-gthelen@google.com> References: <1288336154-23256-1-git-send-email-gthelen@google.com> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add memcg routines to track dirty, writeback, and unstable_NFS pages. These routines are not yet used by the kernel to count such pages. A later change adds kernel calls to these new routines. Signed-off-by: Greg Thelen Signed-off-by: Andrea Righi Acked-by: KAMEZAWA Hiroyuki Acked-by: Daisuke Nishimura --- Changelog since v1: - Renamed "nfs"/"total_nfs" to "nfs_unstable"/"total_nfs_unstable" in per cgroup memory.stat to match /proc/meminfo. - Rename (for clarity): - mem_cgroup_write_page_stat_item -> mem_cgroup_page_stat_item - mem_cgroup_read_page_stat_item -> mem_cgroup_nr_pages_item - Remove redundant comments. - Made mem_cgroup_move_account_page_stat() inline. include/linux/memcontrol.h | 3 ++ mm/memcontrol.c | 86 +++++++++++++++++++++++++++++++++++++++---- 2 files changed, 81 insertions(+), 8 deletions(-) diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index 067115c..ef2eec7 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h @@ -28,6 +28,9 @@ struct mm_struct; /* Stats that can be updated by kernel. */ enum mem_cgroup_page_stat_item { MEMCG_NR_FILE_MAPPED, /* # of pages charged as file rss */ + MEMCG_NR_FILE_DIRTY, /* # of dirty pages in page cache */ + MEMCG_NR_FILE_WRITEBACK, /* # of pages under writeback */ + MEMCG_NR_FILE_UNSTABLE_NFS, /* # of NFS unstable pages */ }; extern unsigned long mem_cgroup_isolate_pages(unsigned long nr_to_scan, diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 94359d6..7f91029 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -85,10 +85,13 @@ enum mem_cgroup_stat_index { */ MEM_CGROUP_STAT_CACHE, /* # of pages charged as cache */ MEM_CGROUP_STAT_RSS, /* # of pages charged as anon rss */ - MEM_CGROUP_STAT_FILE_MAPPED, /* # of pages charged as file rss */ MEM_CGROUP_STAT_PGPGIN_COUNT, /* # of pages paged in */ MEM_CGROUP_STAT_PGPGOUT_COUNT, /* # of pages paged out */ MEM_CGROUP_STAT_SWAPOUT, /* # of pages, swapped out */ + MEM_CGROUP_STAT_FILE_MAPPED, /* # of pages charged as file rss */ + MEM_CGROUP_STAT_FILE_DIRTY, /* # of dirty pages in page cache */ + MEM_CGROUP_STAT_FILE_WRITEBACK, /* # of pages under writeback */ + MEM_CGROUP_STAT_FILE_UNSTABLE_NFS, /* # of NFS unstable pages */ MEM_CGROUP_STAT_DATA, /* end of data requires synchronization */ /* incremented at every pagein/pageout */ MEM_CGROUP_EVENTS = MEM_CGROUP_STAT_DATA, @@ -1625,6 +1628,44 @@ void mem_cgroup_update_page_stat(struct page *page, ClearPageCgroupFileMapped(pc); idx = MEM_CGROUP_STAT_FILE_MAPPED; break; + + case MEMCG_NR_FILE_DIRTY: + /* Use Test{Set,Clear} to only un/charge the memcg once. */ + if (val > 0) { + if (TestSetPageCgroupFileDirty(pc)) + val = 0; + } else { + if (!TestClearPageCgroupFileDirty(pc)) + val = 0; + } + idx = MEM_CGROUP_STAT_FILE_DIRTY; + break; + + case MEMCG_NR_FILE_WRITEBACK: + /* + * This counter is adjusted while holding the mapping's + * tree_lock. Therefore there is no race between settings and + * clearing of this flag. + */ + if (val > 0) + SetPageCgroupFileWriteback(pc); + else + ClearPageCgroupFileWriteback(pc); + idx = MEM_CGROUP_STAT_FILE_WRITEBACK; + break; + + case MEMCG_NR_FILE_UNSTABLE_NFS: + /* Use Test{Set,Clear} to only un/charge the memcg once. */ + if (val > 0) { + if (TestSetPageCgroupFileUnstableNFS(pc)) + val = 0; + } else { + if (!TestClearPageCgroupFileUnstableNFS(pc)) + val = 0; + } + idx = MEM_CGROUP_STAT_FILE_UNSTABLE_NFS; + break; + default: BUG(); } @@ -2129,6 +2170,17 @@ static void __mem_cgroup_commit_charge(struct mem_cgroup *mem, memcg_check_events(mem, pc->page); } +static inline +void mem_cgroup_move_account_page_stat(struct mem_cgroup *from, + struct mem_cgroup *to, + enum mem_cgroup_stat_index idx) +{ + preempt_disable(); + __this_cpu_dec(from->stat->count[idx]); + __this_cpu_inc(to->stat->count[idx]); + preempt_enable(); +} + /** * __mem_cgroup_move_account - move account of the page * @pc: page_cgroup of the page. @@ -2155,13 +2207,18 @@ static void __mem_cgroup_move_account(struct page_cgroup *pc, VM_BUG_ON(!PageCgroupUsed(pc)); VM_BUG_ON(pc->mem_cgroup != from); - if (PageCgroupFileMapped(pc)) { - /* Update mapped_file data for mem_cgroup */ - preempt_disable(); - __this_cpu_dec(from->stat->count[MEM_CGROUP_STAT_FILE_MAPPED]); - __this_cpu_inc(to->stat->count[MEM_CGROUP_STAT_FILE_MAPPED]); - preempt_enable(); - } + if (PageCgroupFileMapped(pc)) + mem_cgroup_move_account_page_stat(from, to, + MEM_CGROUP_STAT_FILE_MAPPED); + if (PageCgroupFileDirty(pc)) + mem_cgroup_move_account_page_stat(from, to, + MEM_CGROUP_STAT_FILE_DIRTY); + if (PageCgroupFileWriteback(pc)) + mem_cgroup_move_account_page_stat(from, to, + MEM_CGROUP_STAT_FILE_WRITEBACK); + if (PageCgroupFileUnstableNFS(pc)) + mem_cgroup_move_account_page_stat(from, to, + MEM_CGROUP_STAT_FILE_UNSTABLE_NFS); mem_cgroup_charge_statistics(from, pc, false); if (uncharge) /* This is not "cancel", but cancel_charge does all we need. */ @@ -3540,6 +3597,9 @@ enum { MCS_PGPGIN, MCS_PGPGOUT, MCS_SWAP, + MCS_FILE_DIRTY, + MCS_WRITEBACK, + MCS_UNSTABLE_NFS, MCS_INACTIVE_ANON, MCS_ACTIVE_ANON, MCS_INACTIVE_FILE, @@ -3562,6 +3622,9 @@ struct { {"pgpgin", "total_pgpgin"}, {"pgpgout", "total_pgpgout"}, {"swap", "total_swap"}, + {"dirty", "total_dirty"}, + {"writeback", "total_writeback"}, + {"nfs_unstable", "total_nfs_unstable"}, {"inactive_anon", "total_inactive_anon"}, {"active_anon", "total_active_anon"}, {"inactive_file", "total_inactive_file"}, @@ -3591,6 +3654,13 @@ mem_cgroup_get_local_stat(struct mem_cgroup *mem, struct mcs_total_stat *s) s->stat[MCS_SWAP] += val * PAGE_SIZE; } + val = mem_cgroup_read_stat(mem, MEM_CGROUP_STAT_FILE_DIRTY); + s->stat[MCS_FILE_DIRTY] += val * PAGE_SIZE; + val = mem_cgroup_read_stat(mem, MEM_CGROUP_STAT_FILE_WRITEBACK); + s->stat[MCS_WRITEBACK] += val * PAGE_SIZE; + val = mem_cgroup_read_stat(mem, MEM_CGROUP_STAT_FILE_UNSTABLE_NFS); + s->stat[MCS_UNSTABLE_NFS] += val * PAGE_SIZE; + /* per zone stat */ val = mem_cgroup_get_local_zonestat(mem, LRU_INACTIVE_ANON); s->stat[MCS_INACTIVE_ANON] += val * PAGE_SIZE; -- 1.7.3.1