* [PATCH -mm 0/5] memcg: performance improvement v4
@ 2008-05-15 9:25 KAMEZAWA Hiroyuki
2008-05-15 9:27 ` [PATCH -mm 1/5] memcg: remove refcnt from page_cgroup KAMEZAWA Hiroyuki
` (4 more replies)
0 siblings, 5 replies; 6+ messages in thread
From: KAMEZAWA Hiroyuki @ 2008-05-15 9:25 UTC (permalink / raw)
To: LKML
Cc: linux-mm@kvack.org, Andrew Morton, balbir@linux.vnet.ibm.com,
xemul@openvz.org, lizf@cn.fujitsu.com, yamamoto@valinux.co.jp,
hugh@veritas.com, minchan.kim
Hi, this version is against 2.6.26-rc2-mm1...much easier to try ;)
please test.
Major changes from v3.
- shmem handling is fixed.
- dropped drop_pages patch (1/6 in v3). It will be rescheduled.
- applied comments (Thanks!)
brief test result on x86-64 (2core) system is attached below but it seems
better to be tested on bigger system/bigger benchmark.
(But I can't do now, sorry)
Patch Description
1/5 ... remove refcnt fron page_cgroup patch (shmem handling is fixed)
2/5 ... swapcache handling patch
3/5 ... add helper function for shmem's memory reclaim patch
4/5 ... optimize by likely/unlikely ppatch
5/5 ... remove redundunt check patch (shmem handling is fixed.)
Unix bench result.
== 2.6.26-rc2-mm1 + memory resource controller
Execl Throughput 2915.4 lps (29.6 secs, 3 samples)
C Compiler Throughput 1019.3 lpm (60.0 secs, 3 samples)
Shell Scripts (1 concurrent) 5796.0 lpm (60.0 secs, 3 samples)
Shell Scripts (8 concurrent) 1097.7 lpm (60.0 secs, 3 samples)
Shell Scripts (16 concurrent) 565.3 lpm (60.0 secs, 3 samples)
File Read 1024 bufsize 2000 maxblocks 1022128.0 KBps (30.0 secs, 3 samples)
File Write 1024 bufsize 2000 maxblocks 544057.0 KBps (30.0 secs, 3 samples)
File Copy 1024 bufsize 2000 maxblocks 346481.0 KBps (30.0 secs, 3 samples)
File Read 256 bufsize 500 maxblocks 319325.0 KBps (30.0 secs, 3 samples)
File Write 256 bufsize 500 maxblocks 148788.0 KBps (30.0 secs, 3 samples)
File Copy 256 bufsize 500 maxblocks 99051.0 KBps (30.0 secs, 3 samples)
File Read 4096 bufsize 8000 maxblocks 2058917.0 KBps (30.0 secs, 3 samples)
File Write 4096 bufsize 8000 maxblocks 1606109.0 KBps (30.0 secs, 3 samples)
File Copy 4096 bufsize 8000 maxblocks 854789.0 KBps (30.0 secs, 3 samples)
Dc: sqrt(2) to 99 decimal places 126145.2 lpm (30.0 secs, 3 samples)
INDEX VALUES
TEST BASELINE RESULT INDEX
Execl Throughput 43.0 2915.4 678.0
File Copy 1024 bufsize 2000 maxblocks 3960.0 346481.0 875.0
File Copy 256 bufsize 500 maxblocks 1655.0 99051.0 598.5
File Copy 4096 bufsize 8000 maxblocks 5800.0 854789.0 1473.8
Shell Scripts (8 concurrent) 6.0 1097.7 1829.5
=========
FINAL SCORE 991.3
== 2.6.26-rc2-mm1 + this set ==
Execl Throughput 3012.9 lps (29.9 secs, 3 samples)
C Compiler Throughput 981.0 lpm (60.0 secs, 3 samples)
Shell Scripts (1 concurrent) 5872.0 lpm (60.0 secs, 3 samples)
Shell Scripts (8 concurrent) 1120.3 lpm (60.0 secs, 3 samples)
Shell Scripts (16 concurrent) 578.0 lpm (60.0 secs, 3 samples)
File Read 1024 bufsize 2000 maxblocks 1003993.0 KBps (30.0 secs, 3 samples)
File Write 1024 bufsize 2000 maxblocks 550452.0 KBps (30.0 secs, 3 samples)
File Copy 1024 bufsize 2000 maxblocks 347159.0 KBps (30.0 secs, 3 samples)
File Read 256 bufsize 500 maxblocks 314644.0 KBps (30.0 secs, 3 samples)
File Write 256 bufsize 500 maxblocks 151852.0 KBps (30.0 secs, 3 samples)
File Copy 256 bufsize 500 maxblocks 101000.0 KBps (30.0 secs, 3 samples)
File Read 4096 bufsize 8000 maxblocks 2033256.0 KBps (30.0 secs, 3 samples)
File Write 4096 bufsize 8000 maxblocks 1611814.0 KBps (30.0 secs, 3 samples)
File Copy 4096 bufsize 8000 maxblocks 847979.0 KBps (30.0 secs, 3 samples)
Dc: sqrt(2) to 99 decimal places 128148.7 lpm (30.0 secs, 3 samples)
INDEX VALUES
TEST BASELINE RESULT INDEX
Execl Throughput 43.0 3012.9 700.7
File Copy 1024 bufsize 2000 maxblocks 3960.0 347159.0 876.7
File Copy 256 bufsize 500 maxblocks 1655.0 101000.0 610.3
File Copy 4096 bufsize 8000 maxblocks 5800.0 847979.0 1462.0
Shell Scripts (8 concurrent) 6.0 1120.3 1867.2
=========
FINAL SCORE 1004.6
Thanks,
-Kame
--
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: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH -mm 1/5] memcg: remove refcnt from page_cgroup
2008-05-15 9:25 [PATCH -mm 0/5] memcg: performance improvement v4 KAMEZAWA Hiroyuki
@ 2008-05-15 9:27 ` KAMEZAWA Hiroyuki
2008-05-15 9:30 ` [PATCH -mm 2/5] memcg: handle swap cache KAMEZAWA Hiroyuki
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: KAMEZAWA Hiroyuki @ 2008-05-15 9:27 UTC (permalink / raw)
To: KAMEZAWA Hiroyuki
Cc: LKML, linux-mm@kvack.org, Andrew Morton,
balbir@linux.vnet.ibm.com, xemul@openvz.org, lizf@cn.fujitsu.com,
yamamoto@valinux.co.jp, hugh@veritas.com, minchan.kim
This patch removes refcnt from page_cgroup().
After this,
* A page is charged only when !page_mapped() && no page_cgroup is assigned.
* Anon page is newly mapped.
* File page is added to mapping->tree.
* A page is uncharged only when
* Anon page is fully unmapped.
* File page is removed from LRU.
There is no change in behavior from user's view.
This patch also removes unnecessary calls in rmap.c which was used only for
refcnt mangement.
Changelog v3->v4:
- adjusted to 2.6.26-rc2-mm1.
- fixed shmem handling.
- fixed __mem_cgroup_uncharge_common() as static.
Changelog: v2->v3
- adjusted to 2.6.26-rc2
- Avoid accounting !Anon page in mem_cgroup_charge_page().
mapped-file pages must be accounted as file cache before here.
- Fixed shmem's page_cgroup refcnt handling. (but it's still complicated...)
- added detect-already-accounted-file-cache check to mem_cgroup_charge().
Changelog: v1->v2
adjusted to 2.6.25-mm1.
Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
---
include/linux/memcontrol.h | 10 ++--
mm/filemap.c | 6 +-
mm/memcontrol.c | 97 +++++++++++++++++++++++----------------------
mm/migrate.c | 3 -
mm/rmap.c | 14 ------
mm/shmem.c | 42 +++++++++++++------
6 files changed, 90 insertions(+), 82 deletions(-)
Index: mm-2.6.26-rc2-mm1/mm/memcontrol.c
===================================================================
--- mm-2.6.26-rc2-mm1.orig/mm/memcontrol.c
+++ mm-2.6.26-rc2-mm1/mm/memcontrol.c
@@ -166,7 +166,6 @@ struct page_cgroup {
struct list_head lru; /* per cgroup LRU list */
struct page *page;
struct mem_cgroup *mem_cgroup;
- int ref_cnt; /* cached, mapped, migrating */
int flags;
};
#define PAGE_CGROUP_FLAG_CACHE (0x1) /* charged as cache */
@@ -185,6 +184,7 @@ static enum zone_type page_cgroup_zid(st
enum charge_type {
MEM_CGROUP_CHARGE_TYPE_CACHE = 0,
MEM_CGROUP_CHARGE_TYPE_MAPPED,
+ MEM_CGROUP_CHARGE_TYPE_FORCE, /* used by force_empty */
};
/*
@@ -552,9 +552,7 @@ retry:
*/
if (pc) {
VM_BUG_ON(pc->page != page);
- VM_BUG_ON(pc->ref_cnt <= 0);
-
- pc->ref_cnt++;
+ VM_BUG_ON(!pc->mem_cgroup);
unlock_page_cgroup(page);
goto done;
}
@@ -570,10 +568,7 @@ retry:
* thread group leader migrates. It's possible that mm is not
* set, if so charge the init_mm (happens for pagecache usage).
*/
- if (!memcg) {
- if (!mm)
- mm = &init_mm;
-
+ if (likely(!memcg)) {
rcu_read_lock();
mem = mem_cgroup_from_task(rcu_dereference(mm->owner));
/*
@@ -609,7 +604,6 @@ retry:
}
}
- pc->ref_cnt = 1;
pc->mem_cgroup = mem;
pc->page = page;
/*
@@ -653,6 +647,17 @@ err:
int mem_cgroup_charge(struct page *page, struct mm_struct *mm, gfp_t gfp_mask)
{
+ /*
+ * If already mapped, we don't have to account.
+ * If page cache, page->mapping has address_space.
+ * But page->mapping may have out-of-use anon_vma pointer,
+ * detecit it by PageAnon() check. newly-mapped-anon's page->mapping
+ * is NULL.
+ */
+ if (page_mapped(page) || (page->mapping && !PageAnon(page)))
+ return 0;
+ if (unlikely(!mm))
+ mm = &init_mm;
return mem_cgroup_charge_common(page, mm, gfp_mask,
MEM_CGROUP_CHARGE_TYPE_MAPPED, NULL);
}
@@ -660,32 +665,17 @@ int mem_cgroup_charge(struct page *page,
int mem_cgroup_cache_charge(struct page *page, struct mm_struct *mm,
gfp_t gfp_mask)
{
- if (!mm)
+ if (unlikely(!mm))
mm = &init_mm;
return mem_cgroup_charge_common(page, mm, gfp_mask,
MEM_CGROUP_CHARGE_TYPE_CACHE, NULL);
}
-int mem_cgroup_getref(struct page *page)
-{
- struct page_cgroup *pc;
-
- if (mem_cgroup_subsys.disabled)
- return 0;
-
- lock_page_cgroup(page);
- pc = page_get_page_cgroup(page);
- VM_BUG_ON(!pc);
- pc->ref_cnt++;
- unlock_page_cgroup(page);
- return 0;
-}
-
/*
- * Uncharging is always a welcome operation, we never complain, simply
- * uncharge.
+ * uncharge if !page_mapped(page)
*/
-void mem_cgroup_uncharge_page(struct page *page)
+static void
+__mem_cgroup_uncharge_common(struct page *page, enum charge_type ctype)
{
struct page_cgroup *pc;
struct mem_cgroup *mem;
@@ -704,29 +694,41 @@ void mem_cgroup_uncharge_page(struct pag
goto unlock;
VM_BUG_ON(pc->page != page);
- VM_BUG_ON(pc->ref_cnt <= 0);
- if (--(pc->ref_cnt) == 0) {
- mz = page_cgroup_zoneinfo(pc);
- spin_lock_irqsave(&mz->lru_lock, flags);
- __mem_cgroup_remove_list(mz, pc);
- spin_unlock_irqrestore(&mz->lru_lock, flags);
+ if ((ctype == MEM_CGROUP_CHARGE_TYPE_MAPPED)
+ && ((pc->flags & PAGE_CGROUP_FLAG_CACHE)
+ || page_mapped(page)))
+ goto unlock;
- page_assign_page_cgroup(page, NULL);
- unlock_page_cgroup(page);
+ mz = page_cgroup_zoneinfo(pc);
+ spin_lock_irqsave(&mz->lru_lock, flags);
+ __mem_cgroup_remove_list(mz, pc);
+ spin_unlock_irqrestore(&mz->lru_lock, flags);
- mem = pc->mem_cgroup;
- res_counter_uncharge(&mem->res, PAGE_SIZE);
- css_put(&mem->css);
+ page_assign_page_cgroup(page, NULL);
+ unlock_page_cgroup(page);
- kmem_cache_free(page_cgroup_cache, pc);
- return;
- }
+ mem = pc->mem_cgroup;
+ res_counter_uncharge(&mem->res, PAGE_SIZE);
+ css_put(&mem->css);
+ kmem_cache_free(page_cgroup_cache, pc);
+ return;
unlock:
unlock_page_cgroup(page);
}
+void mem_cgroup_uncharge_page(struct page *page)
+{
+ __mem_cgroup_uncharge_common(page, MEM_CGROUP_CHARGE_TYPE_MAPPED);
+}
+
+void mem_cgroup_uncharge_cache_page(struct page *page)
+{
+ VM_BUG_ON(page_mapped(page));
+ __mem_cgroup_uncharge_common(page, MEM_CGROUP_CHARGE_TYPE_CACHE);
+}
+
/*
* Before starting migration, account against new page.
*/
@@ -757,15 +759,17 @@ int mem_cgroup_prepare_migration(struct
return ret;
}
-/* remove redundant charge */
+/* remove redundant charge if migration failed*/
void mem_cgroup_end_migration(struct page *newpage)
{
- mem_cgroup_uncharge_page(newpage);
+ /* At success, page->mapping is not NULL */
+ if (newpage->mapping)
+ __mem_cgroup_uncharge_common(newpage,
+ MEM_CGROUP_CHARGE_TYPE_FORCE);
}
/*
* This routine traverse page_cgroup in given list and drop them all.
- * This routine ignores page_cgroup->ref_cnt.
* *And* this routine doesn't reclaim page itself, just removes page_cgroup.
*/
#define FORCE_UNCHARGE_BATCH (128)
@@ -795,7 +799,8 @@ static void mem_cgroup_force_empty_list(
* if it's under page migration.
*/
if (PageLRU(page)) {
- mem_cgroup_uncharge_page(page);
+ __mem_cgroup_uncharge_common(page,
+ MEM_CGROUP_CHARGE_TYPE_FORCE);
put_page(page);
if (--count <= 0) {
count = FORCE_UNCHARGE_BATCH;
Index: mm-2.6.26-rc2-mm1/mm/filemap.c
===================================================================
--- mm-2.6.26-rc2-mm1.orig/mm/filemap.c
+++ mm-2.6.26-rc2-mm1/mm/filemap.c
@@ -115,7 +115,7 @@ void __remove_from_page_cache(struct pag
{
struct address_space *mapping = page->mapping;
- mem_cgroup_uncharge_page(page);
+ mem_cgroup_uncharge_cache_page(page);
radix_tree_delete(&mapping->page_tree, page->index);
page->mapping = NULL;
mapping->nrpages--;
@@ -474,12 +474,12 @@ int add_to_page_cache(struct page *page,
mapping->nrpages++;
__inc_zone_page_state(page, NR_FILE_PAGES);
} else
- mem_cgroup_uncharge_page(page);
+ mem_cgroup_uncharge_cache_page(page);
write_unlock_irq(&mapping->tree_lock);
radix_tree_preload_end();
} else
- mem_cgroup_uncharge_page(page);
+ mem_cgroup_uncharge_cache_page(page);
out:
return error;
}
Index: mm-2.6.26-rc2-mm1/mm/migrate.c
===================================================================
--- mm-2.6.26-rc2-mm1.orig/mm/migrate.c
+++ mm-2.6.26-rc2-mm1/mm/migrate.c
@@ -359,8 +359,7 @@ static int migrate_page_move_mapping(str
write_unlock_irq(&mapping->tree_lock);
if (!PageSwapCache(newpage)) {
- mem_cgroup_uncharge_page(page);
- mem_cgroup_getref(newpage);
+ mem_cgroup_uncharge_cache_page(page);
}
return 0;
Index: mm-2.6.26-rc2-mm1/include/linux/memcontrol.h
===================================================================
--- mm-2.6.26-rc2-mm1.orig/include/linux/memcontrol.h
+++ mm-2.6.26-rc2-mm1/include/linux/memcontrol.h
@@ -35,6 +35,7 @@ extern int mem_cgroup_charge(struct page
extern int mem_cgroup_cache_charge(struct page *page, struct mm_struct *mm,
gfp_t gfp_mask);
extern void mem_cgroup_uncharge_page(struct page *page);
+extern void mem_cgroup_uncharge_cache_page(struct page *page);
extern void mem_cgroup_move_lists(struct page *page, bool active);
extern unsigned long mem_cgroup_isolate_pages(unsigned long nr_to_scan,
struct list_head *dst,
@@ -53,7 +54,6 @@ extern struct mem_cgroup *mem_cgroup_fro
extern int
mem_cgroup_prepare_migration(struct page *page, struct page *newpage);
extern void mem_cgroup_end_migration(struct page *page);
-extern int mem_cgroup_getref(struct page *page);
/*
* For memory reclaim.
@@ -98,6 +98,10 @@ static inline void mem_cgroup_uncharge_p
{
}
+static inline void mem_cgroup_uncharge_cache_page(struct page *page)
+{
+}
+
static inline void mem_cgroup_move_lists(struct page *page, bool active)
{
}
@@ -123,10 +127,6 @@ static inline void mem_cgroup_end_migrat
{
}
-static inline void mem_cgroup_getref(struct page *page)
-{
-}
-
static inline int mem_cgroup_calc_mapped_ratio(struct mem_cgroup *mem)
{
return 0;
Index: mm-2.6.26-rc2-mm1/mm/rmap.c
===================================================================
--- mm-2.6.26-rc2-mm1.orig/mm/rmap.c
+++ mm-2.6.26-rc2-mm1/mm/rmap.c
@@ -586,14 +586,8 @@ void page_add_anon_rmap(struct page *pag
VM_BUG_ON(address < vma->vm_start || address >= vma->vm_end);
if (atomic_inc_and_test(&page->_mapcount))
__page_set_anon_rmap(page, vma, address);
- else {
+ else
__page_check_anon_rmap(page, vma, address);
- /*
- * We unconditionally charged during prepare, we uncharge here
- * This takes care of balancing the reference counts
- */
- mem_cgroup_uncharge_page(page);
- }
}
/**
@@ -624,12 +618,6 @@ void page_add_file_rmap(struct page *pag
{
if (atomic_inc_and_test(&page->_mapcount))
__inc_zone_page_state(page, NR_FILE_MAPPED);
- else
- /*
- * We unconditionally charged during prepare, we uncharge here
- * This takes care of balancing the reference counts
- */
- mem_cgroup_uncharge_page(page);
}
#ifdef CONFIG_DEBUG_VM
Index: mm-2.6.26-rc2-mm1/mm/shmem.c
===================================================================
--- mm-2.6.26-rc2-mm1.orig/mm/shmem.c
+++ mm-2.6.26-rc2-mm1/mm/shmem.c
@@ -922,20 +922,29 @@ found:
error = 1;
if (!inode)
goto out;
- /* Precharge page while we can wait, compensate afterwards */
- error = mem_cgroup_cache_charge(page, current->mm, GFP_KERNEL);
+ error = radix_tree_preload(GFP_KERNEL);
if (error)
goto out;
- error = radix_tree_preload(GFP_KERNEL);
+ /*
+ * Because we use GFP_NOWAIT in add_to_page_cache(), we can see -ENOMEM
+ * failure because of memory pressure in memory resource controller.
+ * Then, precharge page while we can wait, uncharge at failure will be
+ * automatically done in add_to_page_cache()
+ */
+ error = mem_cgroup_cache_charge(page, current->mm, GFP_KERNEL);
if (error)
- goto uncharge;
+ goto preload_out;
+
error = 1;
spin_lock(&info->lock);
ptr = shmem_swp_entry(info, idx, NULL);
if (ptr && ptr->val == entry.val)
- error = add_to_page_cache(page, inode->i_mapping,
- idx, GFP_NOWAIT);
+ error = add_to_page_cache(page, inode->i_mapping, idx,
+ GFP_NOWAIT);
+ else /* we don't have to account this page. */
+ mem_cgroup_uncharge_cache_page(page);
+
if (error == -EEXIST) {
struct page *filepage = find_get_page(inode->i_mapping, idx);
error = 1;
@@ -960,9 +969,8 @@ found:
if (ptr)
shmem_swp_unmap(ptr);
spin_unlock(&info->lock);
+preload_out:
radix_tree_preload_end();
-uncharge:
- mem_cgroup_uncharge_page(page);
out:
unlock_page(page);
page_cache_release(page);
@@ -1319,7 +1327,7 @@ repeat:
page_cache_release(swappage);
goto failed;
}
- mem_cgroup_uncharge_page(swappage);
+ mem_cgroup_uncharge_cache_page(swappage);
}
page_cache_release(swappage);
goto repeat;
@@ -1358,6 +1366,8 @@ repeat:
}
if (!filepage) {
+ int ret;
+
spin_unlock(&info->lock);
filepage = shmem_alloc_page(gfp, info, idx);
if (!filepage) {
@@ -1386,10 +1396,17 @@ repeat:
swap = *entry;
shmem_swp_unmap(entry);
}
- if (error || swap.val || 0 != add_to_page_cache_lru(
- filepage, mapping, idx, GFP_NOWAIT)) {
+ if (error || swap.val)
+ mem_cgroup_uncharge_cache_page(filepage);
+ else
+ ret = add_to_page_cache_lru(filepage, mapping,
+ idx, GFP_NOWAIT);
+ /*
+ * At add_to_page_cache_lru() failure, uncharge will
+ * be done automatically.
+ */
+ if (error || swap.val || ret) {
spin_unlock(&info->lock);
- mem_cgroup_uncharge_page(filepage);
page_cache_release(filepage);
shmem_unacct_blocks(info->flags, 1);
shmem_free_blocks(inode, 1);
@@ -1398,7 +1415,6 @@ repeat:
goto failed;
goto repeat;
}
- mem_cgroup_uncharge_page(filepage);
info->flags |= SHMEM_PAGEIN;
}
--
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: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH -mm 2/5] memcg: handle swap cache
2008-05-15 9:25 [PATCH -mm 0/5] memcg: performance improvement v4 KAMEZAWA Hiroyuki
2008-05-15 9:27 ` [PATCH -mm 1/5] memcg: remove refcnt from page_cgroup KAMEZAWA Hiroyuki
@ 2008-05-15 9:30 ` KAMEZAWA Hiroyuki
2008-05-15 9:31 ` [PATCH -mm 3/5] memcg: helper function for relcaim from shmem KAMEZAWA Hiroyuki
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: KAMEZAWA Hiroyuki @ 2008-05-15 9:30 UTC (permalink / raw)
To: KAMEZAWA Hiroyuki
Cc: LKML, linux-mm@kvack.org, Andrew Morton,
balbir@linux.vnet.ibm.com, xemul@openvz.org, lizf@cn.fujitsu.com,
yamamoto@valinux.co.jp, hugh@veritas.com, minchan.kim
Now swapcache is not accounted. (because it had some troubles.)
This is retrying account swap cache, based on remove-refcnt patch.
* If a page is swap-cache, mem_cgroup_uncharge_page() will *not*
uncharge a page even if page->mapcount == 0.
* If a page is removed from swap-cache, mem_cgroup_uncharge_page()
is called.
* A new swapcache page is not charged until when it's mapped. By this
we can avoid complicated read-ahead troubles.
A file, memory.stat,"rss" member is changed to "anon/swapcache".
(rss is not precise name here...)
When all processes in cgroup exits, rss/swapcache counter can have some
numbers because of lazy behavior of LRU. So the word "rss" is confusing.
I can easily imagine a user says "Oh, there may be memory leak..."
Precise counting of swapcache will be tried in future (if necessary)
Change log: v3->v4
- adjusted to 2.6.26-rc2-mm1
Change log: v2->v3
- adjusted to 2.6.26-rc2+x
- changed "rss" in stat to "rss/swapcache". (stat value includes swapcache)
Change log: v1->v2
- adjusted to 2.6.25-mm1.
Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
---
mm/memcontrol.c | 9 +++++----
mm/migrate.c | 3 ++-
mm/swap_state.c | 1 +
3 files changed, 8 insertions(+), 5 deletions(-)
Index: mm-2.6.26-rc2-mm1/mm/migrate.c
===================================================================
--- mm-2.6.26-rc2-mm1.orig/mm/migrate.c
+++ mm-2.6.26-rc2-mm1/mm/migrate.c
@@ -360,7 +360,8 @@ static int migrate_page_move_mapping(str
write_unlock_irq(&mapping->tree_lock);
if (!PageSwapCache(newpage)) {
mem_cgroup_uncharge_cache_page(page);
- }
+ } else
+ mem_cgroup_uncharge_page(page);
return 0;
}
Index: mm-2.6.26-rc2-mm1/mm/swap_state.c
===================================================================
--- mm-2.6.26-rc2-mm1.orig/mm/swap_state.c
+++ mm-2.6.26-rc2-mm1/mm/swap_state.c
@@ -110,6 +110,7 @@ void __delete_from_swap_cache(struct pag
total_swapcache_pages--;
__dec_zone_page_state(page, NR_FILE_PAGES);
INC_CACHE_INFO(del_total);
+ mem_cgroup_uncharge_page(page);
}
/**
Index: mm-2.6.26-rc2-mm1/mm/memcontrol.c
===================================================================
--- mm-2.6.26-rc2-mm1.orig/mm/memcontrol.c
+++ mm-2.6.26-rc2-mm1/mm/memcontrol.c
@@ -44,10 +44,10 @@ static struct kmem_cache *page_cgroup_ca
*/
enum mem_cgroup_stat_index {
/*
- * For MEM_CONTAINER_TYPE_ALL, usage = pagecache + rss.
+ * For MEM_CONTAINER_TYPE_ALL, usage = pagecache + rss/swapcache.
*/
MEM_CGROUP_STAT_CACHE, /* # of pages charged as cache */
- MEM_CGROUP_STAT_RSS, /* # of pages charged as rss */
+ MEM_CGROUP_STAT_RSS, /* # of pages charged as anon/swapcache */
MEM_CGROUP_STAT_PGPGIN_COUNT, /* # of pages paged in */
MEM_CGROUP_STAT_PGPGOUT_COUNT, /* # of pages paged out */
@@ -697,7 +697,8 @@ __mem_cgroup_uncharge_common(struct page
if ((ctype == MEM_CGROUP_CHARGE_TYPE_MAPPED)
&& ((pc->flags & PAGE_CGROUP_FLAG_CACHE)
- || page_mapped(page)))
+ || page_mapped(page)
+ || PageSwapCache(page)))
goto unlock;
mz = page_cgroup_zoneinfo(pc);
@@ -904,7 +905,7 @@ static const struct mem_cgroup_stat_desc
u64 unit;
} mem_cgroup_stat_desc[] = {
[MEM_CGROUP_STAT_CACHE] = { "cache", PAGE_SIZE, },
- [MEM_CGROUP_STAT_RSS] = { "rss", PAGE_SIZE, },
+ [MEM_CGROUP_STAT_RSS] = { "anon/swapcache", PAGE_SIZE, },
[MEM_CGROUP_STAT_PGPGIN_COUNT] = {"pgpgin", 1, },
[MEM_CGROUP_STAT_PGPGOUT_COUNT] = {"pgpgout", 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: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH -mm 3/5] memcg: helper function for relcaim from shmem.
2008-05-15 9:25 [PATCH -mm 0/5] memcg: performance improvement v4 KAMEZAWA Hiroyuki
2008-05-15 9:27 ` [PATCH -mm 1/5] memcg: remove refcnt from page_cgroup KAMEZAWA Hiroyuki
2008-05-15 9:30 ` [PATCH -mm 2/5] memcg: handle swap cache KAMEZAWA Hiroyuki
@ 2008-05-15 9:31 ` KAMEZAWA Hiroyuki
2008-05-15 9:32 ` [PATCH -mm 4/5] memcg: add hints for branch KAMEZAWA Hiroyuki
2008-05-15 9:34 ` [PATCH -mm 5/5] memcg: remove a redundant check KAMEZAWA Hiroyuki
4 siblings, 0 replies; 6+ messages in thread
From: KAMEZAWA Hiroyuki @ 2008-05-15 9:31 UTC (permalink / raw)
To: KAMEZAWA Hiroyuki
Cc: LKML, linux-mm@kvack.org, Andrew Morton,
balbir@linux.vnet.ibm.com, xemul@openvz.org, lizf@cn.fujitsu.com,
yamamoto@valinux.co.jp, hugh@veritas.com, minchan.kim
A new call, mem_cgroup_shrink_usage() is added for shmem handling
and relacing non-standard usage of mem_cgroup_charge/uncharge.
Now, shmem calls mem_cgroup_charge() just for reclaim some pages from
mem_cgroup. In general, shmem is used by some process group and not for
global resource (like file caches). So, it's reasonable to reclaim pages from
mem_cgroup where shmem is mainly used.
Changelog v3->v4
- fixed while loop to be do_while loop.
- fixed declaration in header file.
- adjusted to 2.6.26-rc2-mm1
Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
---
include/linux/memcontrol.h | 7 +++++++
mm/memcontrol.c | 25 +++++++++++++++++++++++++
mm/shmem.c | 5 ++---
3 files changed, 34 insertions(+), 3 deletions(-)
Index: mm-2.6.26-rc2-mm1/mm/memcontrol.c
===================================================================
--- mm-2.6.26-rc2-mm1.orig/mm/memcontrol.c
+++ mm-2.6.26-rc2-mm1/mm/memcontrol.c
@@ -770,6 +770,31 @@ void mem_cgroup_end_migration(struct pag
}
/*
+ * A call to try to shrink memory usage under specified resource controller.
+ * This is typically used for page reclaiming for shmem for reducing side
+ * effect of page allocation from shmem, which is used by some mem_cgroup.
+ */
+int mem_cgroup_shrink_usage(struct mm_struct *mm, gfp_t gfp_mask)
+{
+ struct mem_cgroup *mem;
+ int progress = 0;
+ int retry = MEM_CGROUP_RECLAIM_RETRIES;
+
+ rcu_read_lock();
+ mem = mem_cgroup_from_task(rcu_dereference(mm->owner));
+ css_get(&mem->css);
+ rcu_read_unlock();
+
+ do {
+ progress = try_to_free_mem_cgroup_pages(mem, gfp_mask);
+ } while (!progress && --retry);
+
+ if (!retry)
+ return -ENOMEM;
+ return 0;
+}
+
+/*
* This routine traverse page_cgroup in given list and drop them all.
* *And* this routine doesn't reclaim page itself, just removes page_cgroup.
*/
Index: mm-2.6.26-rc2-mm1/mm/shmem.c
===================================================================
--- mm-2.6.26-rc2-mm1.orig/mm/shmem.c
+++ mm-2.6.26-rc2-mm1/mm/shmem.c
@@ -1321,13 +1321,12 @@ repeat:
unlock_page(swappage);
if (error == -ENOMEM) {
/* allow reclaim from this memory cgroup */
- error = mem_cgroup_cache_charge(swappage,
- current->mm, gfp & ~__GFP_HIGHMEM);
+ error = mem_cgroup_shrink_usage(current->mm,
+ gfp & ~__GFP_HIGHMEM);
if (error) {
page_cache_release(swappage);
goto failed;
}
- mem_cgroup_uncharge_cache_page(swappage);
}
page_cache_release(swappage);
goto repeat;
Index: mm-2.6.26-rc2-mm1/include/linux/memcontrol.h
===================================================================
--- mm-2.6.26-rc2-mm1.orig/include/linux/memcontrol.h
+++ mm-2.6.26-rc2-mm1/include/linux/memcontrol.h
@@ -37,6 +37,8 @@ extern int mem_cgroup_cache_charge(struc
extern void mem_cgroup_uncharge_page(struct page *page);
extern void mem_cgroup_uncharge_cache_page(struct page *page);
extern void mem_cgroup_move_lists(struct page *page, bool active);
+extern int mem_cgroup_shrink_usage(struct mm_struct *mm, gfp_t gfp_mask);
+
extern unsigned long mem_cgroup_isolate_pages(unsigned long nr_to_scan,
struct list_head *dst,
unsigned long *scanned, int order,
@@ -102,6 +104,11 @@ static inline void mem_cgroup_uncharge_c
{
}
+static inline int mem_cgroup_shrink_usage(struct mm_struct *mm, gfp_t gfp_mask)
+{
+ return 0;
+}
+
static inline void mem_cgroup_move_lists(struct page *page, bool active)
{
}
--
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: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH -mm 4/5] memcg: add hints for branch
2008-05-15 9:25 [PATCH -mm 0/5] memcg: performance improvement v4 KAMEZAWA Hiroyuki
` (2 preceding siblings ...)
2008-05-15 9:31 ` [PATCH -mm 3/5] memcg: helper function for relcaim from shmem KAMEZAWA Hiroyuki
@ 2008-05-15 9:32 ` KAMEZAWA Hiroyuki
2008-05-15 9:34 ` [PATCH -mm 5/5] memcg: remove a redundant check KAMEZAWA Hiroyuki
4 siblings, 0 replies; 6+ messages in thread
From: KAMEZAWA Hiroyuki @ 2008-05-15 9:32 UTC (permalink / raw)
To: KAMEZAWA Hiroyuki
Cc: LKML, linux-mm@kvack.org, Andrew Morton,
balbir@linux.vnet.ibm.com, xemul@openvz.org, lizf@cn.fujitsu.com,
yamamoto@valinux.co.jp, hugh@veritas.com, minchan.kim
Showing brach direction for obvious conditions.
Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
---
mm/memcontrol.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
Index: mm-2.6.26-rc2-mm1/mm/memcontrol.c
===================================================================
--- mm-2.6.26-rc2-mm1.orig/mm/memcontrol.c
+++ mm-2.6.26-rc2-mm1/mm/memcontrol.c
@@ -550,7 +550,7 @@ retry:
* The page_cgroup exists and
* the page has already been accounted.
*/
- if (pc) {
+ if (unlikely(pc)) {
VM_BUG_ON(pc->page != page);
VM_BUG_ON(!pc->mem_cgroup);
unlock_page_cgroup(page);
@@ -559,7 +559,7 @@ retry:
unlock_page_cgroup(page);
pc = kmem_cache_alloc(page_cgroup_cache, gfp_mask);
- if (pc == NULL)
+ if (unlikely(pc == NULL))
goto err;
/*
@@ -616,7 +616,7 @@ retry:
pc->flags = PAGE_CGROUP_FLAG_ACTIVE;
lock_page_cgroup(page);
- if (page_get_page_cgroup(page)) {
+ if (unlikely(page_get_page_cgroup(page))) {
unlock_page_cgroup(page);
/*
* Another charge has been added to this page already.
@@ -690,7 +690,7 @@ __mem_cgroup_uncharge_common(struct page
*/
lock_page_cgroup(page);
pc = page_get_page_cgroup(page);
- if (!pc)
+ if (unlikely(!pc))
goto unlock;
VM_BUG_ON(pc->page != page);
--
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: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH -mm 5/5] memcg: remove a redundant check
2008-05-15 9:25 [PATCH -mm 0/5] memcg: performance improvement v4 KAMEZAWA Hiroyuki
` (3 preceding siblings ...)
2008-05-15 9:32 ` [PATCH -mm 4/5] memcg: add hints for branch KAMEZAWA Hiroyuki
@ 2008-05-15 9:34 ` KAMEZAWA Hiroyuki
4 siblings, 0 replies; 6+ messages in thread
From: KAMEZAWA Hiroyuki @ 2008-05-15 9:34 UTC (permalink / raw)
To: KAMEZAWA Hiroyuki
Cc: LKML, linux-mm@kvack.org, Andrew Morton,
balbir@linux.vnet.ibm.com, xemul@openvz.org, lizf@cn.fujitsu.com,
yamamoto@valinux.co.jp, hugh@veritas.com, minchan.kim
Because of remove refcnt patch, it's very rare case to that
mem_cgroup_charge_common() is called against a page which is accounted.
mem_cgroup_charge_common() is called when.
1. a page is added into file cache.
2. an anon page is _newly_ mapped.
A racy case is that a newly-swapped-in anonymous page is referred from
prural threads in do_swap_page() at the same time.
(a page is not Locked when mem_cgroup_charge() is called from do_swap_page.)
Another case is shmem. It charges its page before calling add_to_page_cache().
Then, mem_cgroup_charge_cache() is called twice. This case is handled in
mem_cgroup_cache_charge(). But this check may be too hacky...
Changelog v3->v4
- added shmem's corner case handling in mem_cgroup_charge_cache().
Signed-off-by : KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
---
mm/memcontrol.c | 53 +++++++++++++++++++++++++----------------------------
1 file changed, 25 insertions(+), 28 deletions(-)
Index: mm-2.6.26-rc2-mm1/mm/memcontrol.c
===================================================================
--- mm-2.6.26-rc2-mm1.orig/mm/memcontrol.c
+++ mm-2.6.26-rc2-mm1/mm/memcontrol.c
@@ -536,28 +536,6 @@ static int mem_cgroup_charge_common(stru
if (mem_cgroup_subsys.disabled)
return 0;
- /*
- * Should page_cgroup's go to their own slab?
- * One could optimize the performance of the charging routine
- * by saving a bit in the page_flags and using it as a lock
- * to see if the cgroup page already has a page_cgroup associated
- * with it
- */
-retry:
- lock_page_cgroup(page);
- pc = page_get_page_cgroup(page);
- /*
- * The page_cgroup exists and
- * the page has already been accounted.
- */
- if (unlikely(pc)) {
- VM_BUG_ON(pc->page != page);
- VM_BUG_ON(!pc->mem_cgroup);
- unlock_page_cgroup(page);
- goto done;
- }
- unlock_page_cgroup(page);
-
pc = kmem_cache_alloc(page_cgroup_cache, gfp_mask);
if (unlikely(pc == NULL))
goto err;
@@ -618,15 +596,10 @@ retry:
lock_page_cgroup(page);
if (unlikely(page_get_page_cgroup(page))) {
unlock_page_cgroup(page);
- /*
- * Another charge has been added to this page already.
- * We take lock_page_cgroup(page) again and read
- * page->cgroup, increment refcnt.... just retry is OK.
- */
res_counter_uncharge(&mem->res, PAGE_SIZE);
css_put(&mem->css);
kmem_cache_free(page_cgroup_cache, pc);
- goto retry;
+ goto done;
}
page_assign_page_cgroup(page, pc);
@@ -665,8 +638,32 @@ int mem_cgroup_charge(struct page *page,
int mem_cgroup_cache_charge(struct page *page, struct mm_struct *mm,
gfp_t gfp_mask)
{
+ /*
+ * Corner case handling. This is called from add_to_page_cache()
+ * in usual. But some FS (shmem) precharges this page before calling it
+ * and call add_to_page_cache() with GFP_NOWAIT.
+ *
+ * For GFP_NOWAIT case, the page may be pre-charged before calling
+ * add_to_page_cache(). (See shmem.c) check it here and avoid to call
+ * charge twice. (It works but has to pay a bit larger cost.)
+ */
+ if (!(gfp_mask & __GFP_WAIT)) {
+ struct page_cgroup *pc;
+
+ lock_page_cgroup(page);
+ pc = page_get_page_cgroup(page);
+ if (pc) {
+ VM_BUG_ON(pc->page != page);
+ VM_BUG_ON(!pc->mem_cgroup);
+ unlock_page_cgroup(page);
+ return 0;
+ }
+ unlock_page_cgroup(page);
+ }
+
if (unlikely(!mm))
mm = &init_mm;
+
return mem_cgroup_charge_common(page, mm, gfp_mask,
MEM_CGROUP_CHARGE_TYPE_CACHE, NULL);
}
--
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: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2008-05-15 9:34 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-05-15 9:25 [PATCH -mm 0/5] memcg: performance improvement v4 KAMEZAWA Hiroyuki
2008-05-15 9:27 ` [PATCH -mm 1/5] memcg: remove refcnt from page_cgroup KAMEZAWA Hiroyuki
2008-05-15 9:30 ` [PATCH -mm 2/5] memcg: handle swap cache KAMEZAWA Hiroyuki
2008-05-15 9:31 ` [PATCH -mm 3/5] memcg: helper function for relcaim from shmem KAMEZAWA Hiroyuki
2008-05-15 9:32 ` [PATCH -mm 4/5] memcg: add hints for branch KAMEZAWA Hiroyuki
2008-05-15 9:34 ` [PATCH -mm 5/5] memcg: remove a redundant check KAMEZAWA Hiroyuki
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).