reducing page_cgroup size
Subsystems (4)
v2 cover reducing page_cgroup size
Hi, here is v2 (still RFC again because I changed many parts.) I'd like to post v3 without 'RFC' tag after Lsf-MM Summit.
This series is for reducing size of 'struct page_cgroup' to 8 bytes. v2 contains 6 patches and did clean-ups and fixes race in v1 and adds a trial to integrate struct page_cgroup into struct page.
each patches are...
1/6 ....add methods to access pc->mem_cgroup
2/6 ....add pc_set_mem_cgroup_and_flags() to set ->mem_cgroup and flags by one call. 3/6 ....add PageCgroupReset() for handling a race.
4/6 ....reduce size of struct page_cgroup by removing ->mem_cgroup
5/6 ....remove unnecessary memory barrier
6/6 ....add CONFIG_INTEGRATED_PAGE_CGROUP to place page_cgroup in struct page.
Regards,
-Kame
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
RFC PATCH v2 1/6 memcg: add methods to access pc->mem_cgroup
In order to encode pc->mem_cgroup and pc->flags to be in a word, access function to pc->mem_cgroup is required.
This patch replaces access to pc->mem_cgroup with
pc_to_mem_cgroup(pc) : pc->mem_cgroup
pc_set_mem_cgroup(pc, memcg) : pc->mem_cgroup = memcg
Changelog:
- rebased onto linux-next-Mar 27 2012 handle THP move_page
--- include/linux/page_cgroup.h | 12 +++++++ mm/memcontrol.c | 71 ++++++++++++++++++++++-------------------- 2 files changed, 49 insertions(+), 34 deletions(-)
include/linux/page_cgroup.h +12 -0
@@ -82,6 +82,18 @@ static inline void unlock_page_cgroup(struct page_cgroup *pc) bit_spin_unlock(PCG_LOCK, &pc->flags); } + +static inline struct mem_cgroup *pc_to_mem_cgroup (struct page_cgroup *pc) +{ +return pc->mem_cgroup; +} + +static inline void +pc_set_mem_cgroup (struct page_cgroup *pc,struct mem_cgroup *memcg) +{ + pc->mem_cgroup = memcg; +} +#else /* CONFIG_CGROUP_MEM_RES_CTLR */ struct page_cgroup ;
mm/memcontrol.c +37 -34
234 lines not on this page · raw message
Signature · 9 lines
1.7.4.1 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/ Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
RFC PATCH v2 2/6 memcg: add pc_set_mem_cgroup_and_flags()
In reply to KAMEZAWA HiroyukiConsolidate a code for setting pc->mem_cgroup and USED bit which requires smp_wmb(). And remove a macro PCGF_NOCOPY_AT_SPLIT which isn't helpful to read code, now.
--- include/linux/page_cgroup.h | 18 ++++++++++++++++++ mm/memcontrol.c | 18 ++++-------------- 2 files changed, 22 insertions(+), 14 deletions(-)
include/linux/page_cgroup.h +18 -0
@@ -1,6 +1,8 @@#ifndef __LINUX_PAGE_CGROUP_H#define __LINUX_PAGE_CGROUP_H +#include <linux/smp.h> +enum {/* flags for mem_cgroup */ PCG_LOCK, /* Lock for pc->mem_cgroup and following bits. */
@@ -94,6 +96,22 @@ pc_set_mem_cgroup(struct page_cgroup *pc, struct mem_cgroup *memcg) pc->mem_cgroup = memcg; } +static inline void +pc_set_mem_cgroup_and_flags (struct page_cgroup *pc,struct mem_cgroup *memcg, +unsigned long flags) +{ + pc->mem_cgroup = memcg; +/* +* We access a page_cgroup asynchronously without lock_page_cgroup(). +* Especially when a page_cgroup is taken from a page, pc's mem_cgroup +* is accessed after testing USED bit. To make pc's mem_cgroup visible +* before USED bit, we need memory barrier here. +* See mem_cgroup_add_lru_list(), etc. +*/ +smp_wmb (); + pc->flags = flags; +} +#else /* CONFIG_CGROUP_MEM_RES_CTLR */ struct page_cgroup ;
mm/memcontrol.c +4 -14
@@ -2511,16 +2511,7 @@ static void __mem_cgroup_commit_charge(struct mem_cgroup *memcg, } } -pc_set_mem_cgroup (pc, memcg); -/* -* We access a page_cgroup asynchronously without lock_page_cgroup(). -* Especially when a page_cgroup is taken from a page, pc's mem_cgroup -* is accessed after testing USED bit. To make pc's mem_cgroup visible -* before USED bit, we need memory barrier here. -* See mem_cgroup_add_lru_list(), etc. -*/ -smp_wmb (); -SetPageCgroupUsed (pc); +pc_set_mem_cgroup_and_flags (pc, memcg,BIT (PCG_USED ) |BIT (PCG_LOCK ));if (lrucare) {if (was_on_lru) {
@@ -2549,7 +2540,6 @@ static void __mem_cgroup_commit_charge(struct mem_cgroup *memcg,#ifdef CONFIG_TRANSPARENT_HUGEPAGE -#define PCGF_NOCOPY_AT_SPLIT ((1 << PCG_LOCK) | (1 << PCG_MIGRATION))/* * Because tail pages are not marked as "used", set it. We're under * zone->lru_lock, 'splitting on pmd' and compound_lock.
@@ -2565,11 +2555,11 @@ void mem_cgroup_split_huge_fixup(struct page *head)if (mem_cgroup_disabled ())return ; +if (!PageCgroupUsed (head_pc)) +return ;for (i =1 ; i <HPAGE_PMD_NR ; i++) { pc = head_pc + i; -pc_set_mem_cgroup (pc, memcg); -smp_wmb ();/* see __commit_charge() */ - pc->flags = head_pc->flags & ~PCGF_NOCOPY_AT_SPLIT ; +pc_set_mem_cgroup_and_flags (pc, memcg,BIT (PCG_USED )); } }#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
Signature · 9 lines
1.7.4.1 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/ Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [RFC][PATCH 2/6] memcg: add pc_set_mem_cgroup_and_flags()
Quoted 53 lines · KAMEZAWA Hiroyuki
Consolidate a code for setting
pc->mem_cgroupand USED bit which requiressmp_wmb(). And remove a macroPCGF_NOCOPY_AT_SPLITwhich isn't helpful to read code, now.Signed-off-by KAMEZAWA Hiroyuki <[email protected]>---
include/linux/page_cgroup.h | 18 ++++++++++++++++++mm/memcontrol.c| 18 ++++--------------2 files changed, 22 insertions(+), 14 deletions(-)include/linux/page_cgroup.h +2
-0@@ -1,6 +1,8 @@ #ifndef __LINUX_PAGE_CGROUP_H #define __LINUX_PAGE_CGROUP_H +#include <linux/smp.h> + enum { /* flags for mem_cgroup */PCG_LOCK, /* Lock for
pc->mem_cgroupand following bits. */include/linux/page_cgroup.h +16
-0@@ -94,6 +96,22 @@ pc_set_mem_cgroup(struct page_cgroup *pc, struct mem_cgroup *memcg) pc->mem_cgroup = memcg; } +static inline void +pc_set_mem_cgroup_and_flags (struct page_cgroup *pc,struct mem_cgroup *memcg, + unsigned long flags) +{ + pc->mem_cgroup = memcg; + /* + * We access a page_cgroup asynchronously without lock_page_cgroup(). + * Especially when a page_cgroup is taken from a page, pc's mem_cgroup + * is accessed after testing USED bit. To make pc's mem_cgroup visible + * before USED bit, we need memory barrier here. + * See mem_cgroup_add_lru_list(), etc. + */ + smp_wmb(); + pc->flags = flags; +} + #else /* CONFIG_CGROUP_MEM_RES_CTLR */ struct page_cgroup;mm/memcontrol.c +0
-0@@ -2511,16 +2511,7 @@ static void __mem_cgroup_commit_charge(struct mem_cgroup *memcg, } }
mm/memcontrol.c static void __mem_cgroup_commit_charge(struct mem_cgroup *memcg, · line 2523
Quoted 10 lines
mm/memcontrol.c +0
-10- pc_set_mem_cgroup(pc, memcg); - /* - * We access a page_cgroup asynchronously without lock_page_cgroup(). - * Especially when a page_cgroup is taken from a page, pc's mem_cgroup - * is accessed after testing USED bit. To make pc's mem_cgroup visible - * before USED bit, we need memory barrier here. - * See mem_cgroup_add_lru_list(), etc. - */ - smp_wmb(); - SetPageCgroupUsed(pc);
I might be confused. We removed this SetPageCgroupUsed() but not adding it back elsewhere ?
--Ying
Quoted 28 lines
mm/memcontrol.c +4
-5+ pc_set_mem_cgroup_and_flags(pc, memcg, BIT(PCG_USED) | BIT(PCG_LOCK)); if (lrucare) { if (was_on_lru) {@@ -2549,7 +2540,6 @@ static void __mem_cgroup_commit_charge(struct mem_cgroup *memcg, #ifdef CONFIG_TRANSPARENT_HUGEPAGE -#define PCGF_NOCOPY_AT_SPLIT ((1 << PCG_LOCK) | (1 << PCG_MIGRATION)) /** Because tail pages are not marked as "used", set it. We're under * zone->lru_lock, 'splitting on pmd' and compound_lock. @@ -2565,11 +2555,11 @@ void mem_cgroup_split_huge_fixup(struct page *head) if (mem_cgroup_disabled()) return; + if (!PageCgroupUsed(head_pc)) + return; for (i = 1; i < HPAGE_PMD_NR; i++) { pc = head_pc + i; - pc_set_mem_cgroup(pc, memcg); - smp_wmb();/* see __commit_charge() */ - pc->flags = head_pc->flags & ~PCGF_NOCOPY_AT_SPLIT; + pc_set_mem_cgroup_and_flags(pc, memcg, BIT(PCG_USED)); } } #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ --
Quoted 3 lines
1.7.4.1
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [RFC][PATCH 2/6] memcg: add pc_set_mem_cgroup_and_flags()
Quoted 69 lines · Ying Han
Quoted 53 lines · KAMEZAWA Hiroyuki
Consolidate a code for setting
pc->mem_cgroupand USED bit which requiressmp_wmb(). And remove a macroPCGF_NOCOPY_AT_SPLITwhich isn't helpful to read code, now.Signed-off-by KAMEZAWA Hiroyuki <[email protected]>--- include/linux/page_cgroup.h | 18 ++++++++++++++++++ mm/memcontrol.c | 18 ++++-------------- 2 files changed, 22 insertions(+), 14 deletions(-)include/linux/page_cgroup.h +18
-0@@ -1,6 +1,8 @@#ifndef __LINUX_PAGE_CGROUP_H#define __LINUX_PAGE_CGROUP_H +#include <linux/smp.h> +enum {/* flags for mem_cgroup */ PCG_LOCK, /* Lock for pc->mem_cgroup and following bits. */@@ -94,6 +96,22 @@ pc_set_mem_cgroup(struct page_cgroup *pc, struct mem_cgroup *memcg) pc->mem_cgroup = memcg; } +static inline void +pc_set_mem_cgroup_and_flags (struct page_cgroup *pc,struct mem_cgroup *memcg, +unsigned long flags) +{ + pc->mem_cgroup = memcg; +/* +* We access a page_cgroup asynchronously without lock_page_cgroup(). +* Especially when a page_cgroup is taken from a page, pc's mem_cgroup +* is accessed after testing USED bit. To make pc's mem_cgroup visible +* before USED bit, we need memory barrier here. +* See mem_cgroup_add_lru_list(), etc. +*/ +smp_wmb (); + pc->flags = flags; +} +#else /* CONFIG_CGROUP_MEM_RES_CTLR */ struct page_cgroup ;mm/memcontrol.c +0
-0@@ -2511,16 +2511,7 @@ static void __mem_cgroup_commit_charge(struct mem_cgroup *memcg, } }mm/memcontrol.c static void __mem_cgroup_commit_charge(struct mem_cgroup *memcg, · line 2523
Quoted 10 lines
mm/memcontrol.c +0
-10-pc_set_mem_cgroup (pc, memcg); -/* -* We access a page_cgroup asynchronously without lock_page_cgroup(). -* Especially when a page_cgroup is taken from a page, pc's mem_cgroup -* is accessed after testing USED bit. To make pc's mem_cgroup visible -* before USED bit, we need memory barrier here. -* See mem_cgroup_add_lru_list(), etc. -*/ -smp_wmb (); -SetPageCgroupUsed (pc);I might be confused. We removed this
SetPageCgroupUsed()but not adding it back elsewhere ?
Quoted 3 lines
--Ying
Quoted 1 line
mm/memcontrol.c +1
-0+pc_set_mem_cgroup_and_flags (pc, memcg,BIT (PCG_USED ) |BIT (PCG_LOCK ));
Added here. This sets
| memcg pointer | Used | Locked |
Thanks,
-Kame
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [RFC][PATCH 2/6] memcg: add pc_set_mem_cgroup_and_flags()
Quoted 71 lines · KAMEZAWA Hiroyuki
Quoted 69 lines · Ying Han
Quoted 53 lines · KAMEZAWA Hiroyuki
Consolidate a code for setting
pc->mem_cgroupand USED bit which requiressmp_wmb(). And remove a macroPCGF_NOCOPY_AT_SPLITwhich isn't helpful to read code, now.Signed-off-by KAMEZAWA Hiroyuki <[email protected]>---
include/linux/page_cgroup.h | 18 ++++++++++++++++++mm/memcontrol.c| 18 ++++--------------2 files changed, 22 insertions(+), 14 deletions(-)include/linux/page_cgroup.h +2
-0@@ -1,6 +1,8 @@ #ifndef __LINUX_PAGE_CGROUP_H #define __LINUX_PAGE_CGROUP_H +#include <linux/smp.h> + enum { /* flags for mem_cgroup */PCG_LOCK, /* Lock for
pc->mem_cgroupand following bits. */include/linux/page_cgroup.h +16
-0@@ -94,6 +96,22 @@ pc_set_mem_cgroup(struct page_cgroup *pc, struct mem_cgroup *memcg) pc->mem_cgroup = memcg; } +static inline void +pc_set_mem_cgroup_and_flags (struct page_cgroup *pc,struct mem_cgroup *memcg, + unsigned long flags) +{ + pc->mem_cgroup = memcg; + /* + * We access a page_cgroup asynchronously without lock_page_cgroup(). + * Especially when a page_cgroup is taken from a page, pc's mem_cgroup + * is accessed after testing USED bit. To make pc's mem_cgroup visible + * before USED bit, we need memory barrier here. + * See mem_cgroup_add_lru_list(), etc. + */ + smp_wmb(); + pc->flags = flags; +} + #else /* CONFIG_CGROUP_MEM_RES_CTLR */ struct page_cgroup;mm/memcontrol.c +0
-0@@ -2511,16 +2511,7 @@ static void __mem_cgroup_commit_charge(struct mem_cgroup *memcg, } }mm/memcontrol.c static void __mem_cgroup_commit_charge(struct mem_cgroup *memcg, · line 2523
Quoted 10 lines
mm/memcontrol.c +0
-10- pc_set_mem_cgroup(pc, memcg); - /* - * We access a page_cgroup asynchronously without lock_page_cgroup(). - * Especially when a page_cgroup is taken from a page, pc's mem_cgroup - * is accessed after testing USED bit. To make pc's mem_cgroup visible - * before USED bit, we need memory barrier here. - * See mem_cgroup_add_lru_list(), etc. - */ - smp_wmb(); - SetPageCgroupUsed(pc);I might be confused. We removed this
SetPageCgroupUsed()but not adding it back elsewhere ?
Quoted 8 lines
Quoted 3 lines
--Ying
Quoted 1 line
mm/memcontrol.c +1
-0+ pc_set_mem_cgroup_and_flags(pc, memcg, BIT(PCG_USED) | BIT(PCG_LOCK));Added here. This sets
| memcg pointer | Used | Locked |
Ah. I missed that part.
Thanks
--Ying
Quoted 8 lines
Thanks,
-Kame
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
RFC PATCH v2 3/6 memcg: add PageCgroupReset()
In reply to KAMEZAWA Hiroyuki A commit "memcg: simplify LRU handling by new rule" removes PCG_ACCT_LRU. and the bug introduced by it was fixed by "memcg: fix GPF when cgroup removal races with last exit"
This was for reducing flags on pc->flags....Now, we have 3bits of flags. but this patch adds a new flag, I'm sorry. (Considering alignment of kmalloc(), we'll able to have 5 bits..)
This patch adds PCG_RESET which is similar to PCG_ACCT_LRU. This is set when mem_cgroup_add_lru_list() finds we cannot trust the pc's mem_cgroup.
The reason why this patch adds a (renamed) flag again is for merging pc->flags and pc->mem_cgroup. Assume pc's mem_cgroup is encoded as
mem_cgroup = pc->flags & ~0x7
Updating multiple bits of pc->flags without talking lock_page_cgroup() is very dangerous. And mem_cgroup_add_lru_list() updates pc->mem_cgroup without taking lock. Then I add RESET bit. After this, pc_to_mem_cgroup() is written as
if (PageCgroupReset(pc)) return root_mem_cgroup; return pc->mem_cgroup;
This update of Reset bit can be done in atomic by set_bit(). And cleared when USED bit is set.
Considering kmalloc()'s alignment, having 4bits of flags will be ok....
--- include/linux/page_cgroup.h | 15 ++++++++------- mm/memcontrol.c | 5 +++-- 2 files changed, 11 insertions(+), 9 deletions(-)
include/linux/page_cgroup.h +8 -7
@@ -8,6 +8,7 @@ enum {PCG_LOCK ,/* Lock for pc->mem_cgroup and following bits. */ PCG_USED ,/* this object is in use. */ PCG_MIGRATION ,/* under page migration */ +PCG_RESET ,/* have been reset to root_mem_cgroup */ __NR_PCG_FLAGS, };
@@ -70,6 +71,9 @@ SETPCGFLAG(Migration, MIGRATION) CLEARPCGFLAG(Migration, MIGRATION) TESTPCGFLAG(Migration, MIGRATION) +TESTPCGFLAG(Reset, RESET) +SETPCGFLAG(Reset, RESET) +static inline void lock_page_cgroup (struct page_cgroup *pc) {/*
@@ -84,16 +88,13 @@ static inline void unlock_page_cgroup(struct page_cgroup *pc)bit_spin_unlock (PCG_LOCK , &pc->flags); } +extern struct mem_cgroup * root_mem_cgroup;static inline struct mem_cgroup *pc_to_mem_cgroup (struct page_cgroup *pc) { -return pc->mem_cgroup; -} - -static inline void -pc_set_mem_cgroup (struct page_cgroup *pc,struct mem_cgroup *memcg) -{ - pc->mem_cgroup = memcg; +if (likely (!PageCgroupReset (pc))) +return pc->mem_cgroup; +return root_mem_cgroup; } static inline void
mm/memcontrol.c +3 -2
@@ -1080,7 +1080,8 @@ struct lruvec *mem_cgroup_lru_add_list(struct zone *zone, struct page *page,* of pc's mem_cgroup safe. */ if (!PageCgroupUsed (pc) && memcg != root_mem_cgroup) { -pc_set_mem_cgroup (pc, root_mem_cgroup); +/* this reset bit is cleared when the page is charged */ +SetPageCgroupReset (pc); memcg = root_mem_cgroup; }
@@ -2626,7 +2627,7 @@ static int mem_cgroup_move_account(struct page *page,__mem_cgroup_cancel_charge (from, nr_pages);/* caller should have done css_get */ -pc_set_mem_cgroup (pc, to); +pc_set_mem_cgroup_and_flags (pc, to,BIT (PCG_USED ) |BIT (PCG_LOCK ));mem_cgroup_charge_statistics (to, anon, nr_pages);/* * We charges against "to" which may not have any tasks. Then, "to"
Signature · 9 lines
1.7.4.1 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/ Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [RFC][PATCH 3/6] memcg: add PageCgroupReset()
Quoted 10 lines · KAMEZAWA Hiroyuki
A commit "memcg: simplify LRU handling by new rule" removes
PCG_ACCT_LRU. and the bug introduced by it was fixed by "memcg: fix GPF when cgroup removal races with last exit"This was for reducing flags on pc->flags....Now, we have 3bits of flags. but this patch adds a new flag, I'm sorry. (Considering alignment of
kmalloc(), we'll able to have 5 bits..)This patch adds
PCG_RESETwhich is similar toPCG_ACCT_LRU.
This is set
Quoted 1 line
when
mem_cgroup_add_lru_list()finds we cannot trust the pc'smem_cgroup.
Do we still need the new flag? I assume some of the upcoming patches will provide the guarantee of pc->mem_cgroup.
--Ying
Quoted 93 lines
The reason why this patch adds a (renamed) flag again is for merging
pc->flagsandpc->mem_cgroup. Assume pc'smem_cgroupis encoded asmem_cgroup =
pc->flags& ~0x7Updating multiple bits of
pc->flagswithout talkinglock_page_cgroup()is very dangerous. Andmem_cgroup_add_lru_list()updatespc->mem_cgroupwithout taking lock. Then I add RESET bit. After this,pc_to_mem_cgroup()is written asif (PageCgroupReset(pc))
returnroot_mem_cgroup;
returnpc->mem_cgroup;This update of Reset bit can be done in atomic by
set_bit(). And cleared when USED bit is set.Considering kmalloc()'s alignment, having 4bits of flags will be ok....
Signed-off-by KAMEZAWA Hiroyuki <[email protected]>---
include/linux/page_cgroup.h | 15 ++++++++-------mm/memcontrol.c| 5 +++--2 files changed, 11 insertions(+), 9 deletions(-)include/linux/page_cgroup.h +0
-0@@ -8,6 +8,7 @@ enum {PCG_LOCK, /* Lock for
pc->mem_cgroupand following bits. */PCG_USED, /* this object is in use. */PCG_MIGRATION, /* under page migration */
+PCG_RESET, /* have been reset toroot_mem_cgroup*/__NR_PCG_FLAGS,
};include/linux/page_cgroup.h +7
-7@@ -70,6 +71,9 @@ SETPCGFLAG(Migration, MIGRATION) CLEARPCGFLAG(Migration, MIGRATION) TESTPCGFLAG(Migration, MIGRATION) +TESTPCGFLAG(Reset, RESET) +SETPCGFLAG(Reset, RESET) + static inline void lock_page_cgroup(struct page_cgroup *pc) { /*@@ -84,16 +88,13 @@ static inline void unlock_page_cgroup(struct page_cgroup *pc) bit_spin_unlock(PCG_LOCK, &pc->flags); } +extern struct mem_cgroup* root_mem_cgroup; static inline struct mem_cgroup* pc_to_mem_cgroup(struct page_cgroup *pc) { - return pc->mem_cgroup; -} - -static inline void -pc_set_mem_cgroup (struct page_cgroup *pc,struct mem_cgroup *memcg) -{ - pc->mem_cgroup = memcg; + if (likely(!PageCgroupReset(pc))) + return pc->mem_cgroup; + return root_mem_cgroup; }static inline void
mm/memcontrol.c +3
-3@@ -1080,7 +1080,8 @@ struct lruvec *mem_cgroup_lru_add_list(struct zone *zone, struct page *page,* of pc's mem_cgroup safe. */ if (!PageCgroupUsed(pc) && memcg != root_mem_cgroup) { - pc_set_mem_cgroup(pc, root_mem_cgroup); + /* this reset bit is cleared when the page is charged */ + SetPageCgroupReset(pc); memcg = root_mem_cgroup; }@@ -2626,7 +2627,7 @@ static int mem_cgroup_move_account(struct page *page, __mem_cgroup_cancel_charge(from, nr_pages); /* caller should have done css_get */ - pc_set_mem_cgroup(pc, to); + pc_set_mem_cgroup_and_flags(pc, to, BIT(PCG_USED) | BIT(PCG_LOCK)); mem_cgroup_charge_statistics(to, anon, nr_pages); /** We charges against "to" which may not have any tasks. Then, "to" --
Quoted 3 lines
1.7.4.1
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [RFC][PATCH 3/6] memcg: add PageCgroupReset()
Quoted 15 lines · Ying Han
Quoted 10 lines · KAMEZAWA Hiroyuki
A commit "memcg: simplify LRU handling by new rule" removes
PCG_ACCT_LRU. and the bug introduced by it was fixed by "memcg: fix GPF when cgroup removal races with last exit"This was for reducing flags on pc->flags....Now, we have 3bits of flags. but this patch adds a new flag, I'm sorry. (Considering alignment of
kmalloc(), we'll able to have 5 bits..)This patch adds
PCG_RESETwhich is similar toPCG_ACCT_LRU.
Quoted 6 lines
This is set
Quoted 1 line
when
mem_cgroup_add_lru_list()finds we cannot trust the pc'smem_cgroup.Do we still need the new flag? I assume some of the upcoming patches will provide the guarantee of
pc->mem_cgroup.
If per-lruvec locking can do reference-count GC, memcg will never be freed there are pages which points to the memcg, and allows us to remove whole this 'move to root' logic, I agree. We'll not require a new flag.
It means that memcg cannot be freed until there are not page(_cgroup) which points to dead memcg. mem_cgroup_reset_owner() is removed, now.
We need to handle 2 cases.
- newly allocated pages which linked to memcg before use.
- unused pages but added to lru by some lazy logic.
And make a guarantee
- pages added to LRU of dead memcg will be freed or moved to other cgroup, soon.
I have no good idea.
Thanks,
-Kame
Quoted 87 lines
--Ying
Quoted 86 lines
The reason why this patch adds a (renamed) flag again is for merging
pc->flagsandpc->mem_cgroup. Assume pc'smem_cgroupis encoded asmem_cgroup = pc->flags & ~0x7Updating multiple bits of
pc->flagswithout talkinglock_page_cgroup()is very dangerous. Andmem_cgroup_add_lru_list()updatespc->mem_cgroupwithout taking lock. Then I add RESET bit. After this,pc_to_mem_cgroup()is written asif (PageCgroupReset(pc)) return root_mem_cgroup; return pc->mem_cgroup;This update of Reset bit can be done in atomic by
set_bit(). And cleared when USED bit is set.Considering kmalloc()'s alignment, having 4bits of flags will be ok....
Signed-off-by KAMEZAWA Hiroyuki <[email protected]>--- include/linux/page_cgroup.h | 15 ++++++++------- mm/memcontrol.c | 5 +++-- 2 files changed, 11 insertions(+), 9 deletions(-)include/linux/page_cgroup.h +8
-7@@ -8,6 +8,7 @@ enum {PCG_LOCK ,/* Lock for pc->mem_cgroup and following bits. */ PCG_USED ,/* this object is in use. */ PCG_MIGRATION ,/* under page migration */ +PCG_RESET ,/* have been reset to root_mem_cgroup */ __NR_PCG_FLAGS, };@@ -70,6 +71,9 @@ SETPCGFLAG(Migration, MIGRATION) CLEARPCGFLAG(Migration, MIGRATION) TESTPCGFLAG(Migration, MIGRATION) +TESTPCGFLAG(Reset, RESET) +SETPCGFLAG(Reset, RESET) +static inline void lock_page_cgroup (struct page_cgroup *pc) {/* @@ -84,16 +88,13 @@ static inline void unlock_page_cgroup(struct page_cgroup *pc)bit_spin_unlock (PCG_LOCK , &pc->flags); } +extern struct mem_cgroup * root_mem_cgroup;static inline struct mem_cgroup *pc_to_mem_cgroup (struct page_cgroup *pc) { -return pc->mem_cgroup; -} - -static inline void -pc_set_mem_cgroup (struct page_cgroup *pc,struct mem_cgroup *memcg) -{ - pc->mem_cgroup = memcg; +if (likely (!PageCgroupReset (pc))) +return pc->mem_cgroup; +return root_mem_cgroup; } static inline voidmm/memcontrol.c +2
-1@@ -1080,7 +1080,8 @@ struct lruvec *mem_cgroup_lru_add_list(struct zone *zone, struct page *page,* of pc's mem_cgroup safe. */ if (!PageCgroupUsed (pc) && memcg != root_mem_cgroup) { -pc_set_mem_cgroup (pc, root_mem_cgroup); +/* this reset bit is cleared when the page is charged */ +SetPageCgroupReset (pc); memcg = root_mem_cgroup; }@@ -2626,7 +2627,7 @@ static int mem_cgroup_move_account(struct page *page,__mem_cgroup_cancel_charge (from, nr_pages);
Quoted 12 lines
Quoted 10 lines
mm/memcontrol.c +1
-2/* caller should have done css_get */ -pc_set_mem_cgroup (pc, to); +pc_set_mem_cgroup_and_flags (pc, to,BIT (PCG_USED ) |BIT (PCG_LOCK ));mem_cgroup_charge_statistics (to, anon, nr_pages);/* * We charges against "to" which may not have any tasks. Then, "to" -- 1.7.4.1
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
RFC PATCH v2 4/6 memcg: remove mem_cgroup pointer from page_cgroup
In reply to KAMEZAWA HiroyukiThis patch removes pc->mem_cgroup and merge the pointer into flags as
63 4 0
| pointer to memcg..........|flags|
After this, memory cgroup's overhead is 8(4)bytes per a page.
Changelog:
- added BUILD_BUG_ON()
- update comments in Kconfig
--- include/linux/page_cgroup.h | 21 +++++++++------------ init/Kconfig | 2 +- 2 files changed, 10 insertions(+), 13 deletions(-)
include/linux/page_cgroup.h +9 -12
@@ -3,6 +3,10 @@#include <linux/smp.h> +/* +* These flags are encoded into low bits of unsigned long, +* ORed with a pointer to mem_cgroup. +*/ enum {/* flags for mem_cgroup */ PCG_LOCK ,/* Lock for pc->mem_cgroup and following bits. */
@@ -12,6 +16,8 @@ enum { __NR_PCG_FLAGS, }; +#define PCG_FLAGS_MASK ((1 << __NR_PCG_FLAGS) - 1) +#ifndef __GENERATING_BOUNDS_H#include <generated/bounds.h>
@@ -27,7 +33,6 @@ enum {*/ struct page_cgroup {unsigned long flags; -struct mem_cgroup *mem_cgroup; };void __meminit pgdat_page_cgroup_init (struct pglist_data *pgdat);
@@ -93,7 +98,7 @@ extern struct mem_cgroup* root_mem_cgroup;static inline struct mem_cgroup *pc_to_mem_cgroup (struct page_cgroup *pc) {if (likely (!PageCgroupReset (pc))) -return pc->mem_cgroup; +return (struct mem_cgroup *)(pc->flags & ~PCG_FLAGS_MASK );return root_mem_cgroup; }
@@ -101,16 +106,8 @@ static inline void pc_set_mem_cgroup_and_flags(struct page_cgroup *pc, struct mem_cgroup *memcg, unsigned long flags) { - pc->mem_cgroup = memcg; -/* -* We access a page_cgroup asynchronously without lock_page_cgroup(). -* Especially when a page_cgroup is taken from a page, pc's mem_cgroup -* is accessed after testing USED bit. To make pc's mem_cgroup visible -* before USED bit, we need memory barrier here. -* See mem_cgroup_add_lru_list(), etc. -*/ -smp_wmb (); - pc->flags = flags; + BUILD_BUG_ON(__NR_PCG_FLAGS > 5); /* assume 32byte alignment. */ + pc->flags = (unsigned long )memcg | flags; }#else /* CONFIG_CGROUP_MEM_RES_CTLR */
init/Kconfig +1 -1
@@ -651,7 +651,7 @@ config CGROUP_MEM_RES_CTLR Note that setting this option increases fixed memory overhead associated with each page of memory in the system. By this, - 20(40)bytes/PAGE_SIZE on 32(64)bit system will be occupied by memory + 4(8)bytes/PAGE_SIZE on 32(64)bit system will be occupied by memory usage tracking struct at boot. Total amount of this is printed out at boot.
Signature · 9 lines
1.7.4.1 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/ Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
RFC PATCH v2 5/6 memcg: remove unnecessary memory barrier.
In reply to KAMEZAWA HiroyukiNow, Used bit and a pointer to memory cgroup are set at once. memory barrier for Used bit -> pc->mem_cgroup is not necessary.
--- mm/memcontrol.c | 2 -- 1 files changed, 0 insertions(+), 2 deletions(-)
mm/memcontrol.c +0 -2
@@ -1258,8 +1258,6 @@ mem_cgroup_get_reclaim_stat_from_page(struct page *page) pc =lookup_page_cgroup (page);if (!PageCgroupUsed (pc))return NULL ; -/* Ensure pc's mem_cgroup is visible after reading PCG_USED. */ -smp_rmb (); mz =page_cgroup_zoneinfo (pc_to_mem_cgroup (pc), page);return &mz->reclaim_stat; }
Signature · 9 lines
1.7.4.1 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/ Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
RFC PATCH v2 6/6 memcg: config for integrate page_cgroup into memmap
In reply to KAMEZAWA HiroyukiThis patch is an experimental patch.
Considering 32bit archs, I think this should be CONFIG option... ==
Now, struct page_cgroup is 8byte object and allocated per a page. This patch adds a config option to allocate page_cgroup in struct page.
By this
Pros.
- lookup_page_cgroup() is almost 0 cost.
- implementation seems very natural...
Cons.
- size of 'struct page' will be increased (to 64bytes in typical case)
- cgroup_disable=memory will not allow user to avoid 8bytes of overhead.
Tested 'kernel make' on tmpfs.
Config=n
Performance counter stats for 'make -j 8':
1,180,857,100,495 instructions # 0.00 insns per cycle
923,084,678 cache-misses
71.346377273 seconds time elapsedConfig=y
Performance counter stats for 'make -j 8':
1,178,404,304,530 instructions # 0.00 insns per cycle
911,098,615 cache-misses
71.607477840 seconds time elapsedseems instructions and cache-misses decreased to some extent. But no visible change in total execution time...
--- include/linux/mm_types.h | 4 +++- include/linux/page_cgroup.h | 33 ++++++++++++++++++++++++++++++++- init/Kconfig | 14 ++++++++++++++ mm/memcontrol.c | 3 ++- mm/page_alloc.c | 1 + mm/page_cgroup.c | 3 ++- 6 files changed, 54 insertions(+), 4 deletions(-)
include/linux/mm_types.h +3 -1
@@ -141,7 +141,9 @@ struct page {#ifdef CONFIG_WANT_PAGE_DEBUG_FLAGS unsigned long debug_flags;/* Use atomic bitops on this */ #endif - +#ifdef CONFIG_INTEGRATED_PAGE_CGROUP +unsigned long page_cgroup;/* see page_cgroup.h */ +#endif #ifdef CONFIG_KMEMCHECK /* * kmemcheck wants to track the status of each byte in a page; this
include/linux/page_cgroup.h +32 -1
@@ -35,8 +35,9 @@ struct page_cgroup {unsigned long flags; }; -void __meminit pgdat_page_cgroup_init (struct pglist_data *pgdat); +#ifndef CONFIG_INTEGRATED_PAGE_CGROUP +void __meminit pgdat_page_cgroup_init(struct pglist_data *pgdat); #ifdef CONFIG_SPARSEMEM static inline void __init page_cgroup_init_flatmem(void) {
@@ -51,6 +52,36 @@ static inline void __init page_cgroup_init(void)struct page_cgroup *lookup_page_cgroup (struct page *page);struct page *lookup_cgroup_page (struct page_cgroup *pc); +static inline void memmap_init_cgroup (struct page *page) +{ +} +#else +static inline struct page_cgroup *lookup_page_cgroup (struct page *page) +{ +return (struct page_cgroup *)&page->page_cgroup; +} + +static inline struct page *lookup_cgroup_page (struct page_cgroup *pc) +{ + return container_of((unsigned long*)pc, struct page, page_cgroup); +} + +static inline void memmap_init_cgroup (struct page *page) +{ + page->page_cgroup =0 ; +} + +static inline void __init page_cgroup_init_flatmem (void ) +{ +} +static inline void __init page_cgroup_init (void ) +{ +} + +static inline void pgdat_page_cgroup_init (struct pglist_data *pgdat) +{ +} +#endif #define TESTPCGFLAG (uname, lname) \ static inline int PageCgroup##uname(struct page_cgroup *pc) \
init/Kconfig +14 -0
@@ -694,6 +694,20 @@ config CGROUP_MEM_RES_CTLR_SWAP_ENABLED For those who want to have the feature enabled by default should select this option (if, for some reason, they need to disable it then swapaccount=0 does the trick). + +config INTEGRATED_PAGE_CGROUP + bool "record memory cgroup information into struct page" + depends on CGROUP_MEM_RES_CTLR + default n + help + Memory Resource Controller consumes 4/(8 if 64bit)bytes per page. + It's independent of 'struct page'. If you say Y here, memory cgroup + information is recorded into struct page and increase size of it + 4/8 bytes. With this, cpu overheads in runtime will be reduced + but you cannot avoid above overheads of 4/8 bytes per page by boot + option. If unsure, say N. + + config CGROUP_MEM_RES_CTLR_KMEM bool "Memory Resource Controller Kernel Memory accounting (EXPERIMENTAL)" depends on CGROUP_MEM_RES_CTLR && EXPERIMENTAL
mm/memcontrol.c +2 -1
@@ -2557,7 +2557,8 @@ void mem_cgroup_split_huge_fixup(struct page *head)if (!PageCgroupUsed (head_pc))return ;for (i =1 ; i <HPAGE_PMD_NR ; i++) { - pc = head_pc + i; +/* page struct is contiguous in hugepage. */ + pc =lookup_page_cgroup (head + i);pc_set_mem_cgroup_and_flags (pc, memcg,BIT (PCG_USED )); } }
mm/page_alloc.c +1 -0
@@ -3682,6 +3682,7 @@ void __meminit memmap_init_zone(unsigned long size, int nid, unsigned long zone,if (!is_highmem_idx (zone))set_page_address (page,__va (pfn <<PAGE_SHIFT ));#endif +memmap_init_cgroup (page); } }
mm/page_cgroup.c +2 -1
@@ -11,6 +11,7 @@#include <linux/swapops.h> #include <linux/kmemleak.h> +#ifndef CONFIG_INTEGRATED_PAGE_CGROUP static unsigned long total_usage;#if !defined(CONFIG_SPARSEMEM )
@@ -315,7 +316,7 @@ void __meminit pgdat_page_cgroup_init(struct pglist_data *pgdat) }#endif - +#endif #ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
Signature · 10 lines
1.7.4.1 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/ Don't email: <a href=mailto:"[email protected]"> [email protected] </a>