Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1467478 > unrolled thread
| Started by | Hui Zhu <zhuhui@xiaomi.com> |
|---|---|
| First post | 2016-08-22 10:50 +0200 |
| Last post | 2016-08-25 10:30 +0200 |
| Articles | 6 — 4 participants |
Back to article view | Back to linux.kernel
[RFC 0/4] ZRAM: make it just store the high compression rate page Hui Zhu <zhuhui@xiaomi.com> - 2016-08-22 10:50 +0200
[RFC 4/4] vmscan.c: zram: add non swap support for shmem file pages Hui Zhu <zhuhui@xiaomi.com> - 2016-08-22 10:50 +0200
Re: [RFC 0/4] ZRAM: make it just store the high compression rate page Minchan Kim <minchan@kernel.org> - 2016-08-24 03:10 +0200
Re: [RFC 0/4] ZRAM: make it just store the high compression rate page Hui Zhu <teawater@gmail.com> - 2016-08-24 04:00 +0200
Re: [RFC 0/4] ZRAM: make it just store the high compression rate page Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com> - 2016-08-25 08:20 +0200
Re: [RFC 0/4] ZRAM: make it just store the high compression rate page Hui Zhu <teawater@gmail.com> - 2016-08-25 10:30 +0200
| From | Hui Zhu <zhuhui@xiaomi.com> |
|---|---|
| Date | 2016-08-22 10:50 +0200 |
| Subject | [RFC 0/4] ZRAM: make it just store the high compression rate page |
| Message-ID | <s8T5D-3Zg-11@gated-at.bofh.it> |
Current ZRAM just can store all pages even if the compression rate of a page is really low. So the compression rate of ZRAM is out of control when it is running. In my part, I did some test and record with ZRAM. The compression rate is about 40%. This series of patches make ZRAM can just store the page that the compressed size is smaller than a value. With these patches, I set the value to 2048 and did the same test with before. The compression rate is about 20%. The times of lowmemorykiller also decreased. Hui Zhu (4): vmscan.c: shrink_page_list: unmap anon pages after pageout Add non-swap page flag to mark a page will not swap ZRAM: do not swap the pages that compressed size bigger than non_swap vmscan.c: zram: add non swap support for shmem file pages drivers/block/zram/Kconfig | 11 +++ drivers/block/zram/zram_drv.c | 38 +++++++++++ drivers/block/zram/zram_drv.h | 4 + fs/proc/meminfo.c | 6 + include/linux/mm_inline.h | 20 +++++ include/linux/mmzone.h | 3 include/linux/page-flags.h | 8 ++ include/linux/rmap.h | 5 + include/linux/shmem_fs.h | 6 + include/trace/events/mmflags.h | 9 ++ kernel/events/uprobes.c | 16 ++++ mm/Kconfig | 9 ++ mm/memory.c | 34 ++++++++++ mm/migrate.c | 4 + mm/mprotect.c | 8 ++ mm/page_io.c | 11 ++- mm/rmap.c | 23 ++++++ mm/shmem.c | 77 +++++++++++++++++----- mm/vmscan.c | 139 +++++++++++++++++++++++++++++++++++------ 19 files changed, 387 insertions(+), 44 deletions(-)
[toc] | [next] | [standalone]
| From | Hui Zhu <zhuhui@xiaomi.com> |
|---|---|
| Date | 2016-08-22 10:50 +0200 |
| Subject | [RFC 4/4] vmscan.c: zram: add non swap support for shmem file pages |
| Message-ID | <s8T5E-3Zg-37@gated-at.bofh.it> |
| In reply to | #1467478 |
This patch add the whole support for shmem file pages non swap.
To make sure a page is shmem file page, check mapping->a_ops == &shmem_aops.
I think it is really a hack way.
There are not a lot of shmem file pages will be swapped out.
Signed-off-by: Hui Zhu <zhuhui@xiaomi.com>
---
drivers/block/zram/zram_drv.c | 3 +-
include/linux/shmem_fs.h | 6 ++++
mm/page_io.c | 2 +-
mm/rmap.c | 5 ---
mm/shmem.c | 77 ++++++++++++++++++++++++++++++++++---------
mm/vmscan.c | 27 +++++++++++----
6 files changed, 89 insertions(+), 31 deletions(-)
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index 8f7f1ec..914c096 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -715,8 +715,7 @@ compress_again:
}
#ifdef CONFIG_ZRAM_NON_SWAP
- if (!is_partial_io(bvec) && PageAnon(page) &&
- zram->non_swap && clen > zram->non_swap) {
+ if (!is_partial_io(bvec) && zram->non_swap && clen > zram->non_swap) {
ret = 0;
SetPageNonSwap(page);
goto out;
diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h
index ff078e7..fd44473 100644
--- a/include/linux/shmem_fs.h
+++ b/include/linux/shmem_fs.h
@@ -124,4 +124,10 @@ static inline bool shmem_huge_enabled(struct vm_area_struct *vma)
}
#endif
+extern const struct address_space_operations shmem_aops;
+
+#ifdef CONFIG_LATE_UNMAP
+extern void shmem_page_unmap(struct page *page);
+#endif
+
#endif
diff --git a/mm/page_io.c b/mm/page_io.c
index adaf801..5fd3069 100644
--- a/mm/page_io.c
+++ b/mm/page_io.c
@@ -238,7 +238,7 @@ int swap_writepage(struct page *page, struct writeback_control *wbc)
int ret = 0;
#ifdef CONFIG_LATE_UNMAP
- if (!(PageAnon(page) && page_mapped(page)))
+ if (!page_mapped(page))
#endif
if (try_to_free_swap(page)) {
unlock_page(page);
diff --git a/mm/rmap.c b/mm/rmap.c
index d484f95..418f731 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -1490,13 +1490,8 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
#ifdef CONFIG_LATE_UNMAP
if ((flags & TTU_CHECK_DIRTY) || (flags & TTU_READONLY)) {
- BUG_ON(!PageAnon(page));
-
pteval = *pte;
- BUG_ON(pte_write(pteval) &&
- page_mapcount(page) + page_swapcount(page) > 1);
-
if ((flags & TTU_CHECK_DIRTY) && pte_dirty(pteval)) {
set_page_dirty(page);
pteval = pte_mkclean(pteval);
diff --git a/mm/shmem.c b/mm/shmem.c
index fd8b2b5..556d853 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -182,7 +182,6 @@ static inline void shmem_unacct_blocks(unsigned long flags, long pages)
}
static const struct super_operations shmem_ops;
-static const struct address_space_operations shmem_aops;
static const struct file_operations shmem_file_operations;
static const struct inode_operations shmem_inode_operations;
static const struct inode_operations shmem_dir_inode_operations;
@@ -1178,6 +1177,55 @@ out:
return error;
}
+#define SHMEM_WRITEPAGE_LOCK \
+ do { \
+ mutex_lock(&shmem_swaplist_mutex); \
+ if (list_empty(&info->swaplist)) \
+ list_add_tail(&info->swaplist, \
+ &shmem_swaplist); \
+ } while (0)
+
+#define SHMEM_WRITEPAGE_SWAP \
+ do { \
+ spin_lock(&info->lock); \
+ shmem_recalc_inode(inode); \
+ info->swapped++; \
+ spin_unlock(&info->lock); \
+ swap_shmem_alloc(swap); \
+ shmem_delete_from_page_cache(page, \
+ swp_to_radix_entry(swap)); \
+ } while (0)
+
+#define SHMEM_WRITEPAGE_UNLOCK \
+ do { \
+ mutex_unlock(&shmem_swaplist_mutex); \
+ } while (0)
+
+#define SHMEM_WRITEPAGE_BUG_ON \
+ do { \
+ BUG_ON(page_mapped(page)); \
+ } while (0)
+
+#ifdef CONFIG_LATE_UNMAP
+void
+shmem_page_unmap(struct page *page)
+{
+ struct shmem_inode_info *info;
+ struct address_space *mapping;
+ struct inode *inode;
+ swp_entry_t swap = { .val = page_private(page) };
+
+ mapping = page->mapping;
+ inode = mapping->host;
+ info = SHMEM_I(inode);
+
+ SHMEM_WRITEPAGE_LOCK;
+ SHMEM_WRITEPAGE_SWAP;
+ SHMEM_WRITEPAGE_UNLOCK;
+ SHMEM_WRITEPAGE_BUG_ON;
+}
+#endif
+
/*
* Move the page from the page cache to the swap cache.
*/
@@ -1259,26 +1307,23 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc)
* we've incremented swapped, because shmem_unuse_inode() will
* prune a !swapped inode from the swaplist under this mutex.
*/
- mutex_lock(&shmem_swaplist_mutex);
- if (list_empty(&info->swaplist))
- list_add_tail(&info->swaplist, &shmem_swaplist);
+#ifndef CONFIG_LATE_UNMAP
+ SHMEM_WRITEPAGE_LOCK;
+#endif
if (add_to_swap_cache(page, swap, GFP_ATOMIC) == 0) {
- spin_lock_irq(&info->lock);
- shmem_recalc_inode(inode);
- info->swapped++;
- spin_unlock_irq(&info->lock);
-
- swap_shmem_alloc(swap);
- shmem_delete_from_page_cache(page, swp_to_radix_entry(swap));
-
- mutex_unlock(&shmem_swaplist_mutex);
- BUG_ON(page_mapped(page));
+#ifndef CONFIG_LATE_UNMAP
+ SHMEM_WRITEPAGE_SWAP;
+ SHMEM_WRITEPAGE_UNLOCK;
+ SHMEM_WRITEPAGE_BUG_ON;
+#endif
swap_writepage(page, wbc);
return 0;
}
- mutex_unlock(&shmem_swaplist_mutex);
+#ifndef CONFIG_LATE_UNMAP
+ SHMEM_WRITEPAGE_UNLOCK;
+#endif
free_swap:
swapcache_free(swap);
redirty:
@@ -3764,7 +3809,7 @@ static void shmem_destroy_inodecache(void)
kmem_cache_destroy(shmem_inode_cachep);
}
-static const struct address_space_operations shmem_aops = {
+const struct address_space_operations shmem_aops = {
.writepage = shmem_writepage,
.set_page_dirty = __set_page_dirty_no_writeback,
#ifdef CONFIG_TMPFS
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 14d49cd..effb6c4 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -54,6 +54,8 @@
#include <linux/swapops.h>
#include <linux/balloon_compaction.h>
+#include <linux/shmem_fs.h>
+
#include "internal.h"
#define CREATE_TRACE_POINTS
@@ -492,12 +494,13 @@ void drop_slab(void)
drop_slab_node(nid);
}
-static inline int is_page_cache_freeable(struct page *page)
+static inline int is_page_cache_freeable(struct page *page,
+ struct address_space *mapping)
{
int count = page_count(page) - page_has_private(page);
#ifdef CONFIG_LATE_UNMAP
- if (PageAnon(page))
+ if (PageAnon(page) || (mapping && mapping->a_ops == &shmem_aops))
count -= page_mapcount(page);
#endif
@@ -576,7 +579,7 @@ static pageout_t pageout(struct page *page, struct address_space *mapping,
* swap_backing_dev_info is bust: it doesn't reflect the
* congestion state of the swapdevs. Easy to fix, if needed.
*/
- if (!is_page_cache_freeable(page))
+ if (!is_page_cache_freeable(page, mapping))
return PAGE_KEEP;
if (!mapping) {
/*
@@ -972,7 +975,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,
struct page *page;
int may_enter_fs;
enum page_references references = PAGEREF_RECLAIM_CLEAN;
- bool dirty, writeback, anon;
+ bool dirty, writeback, anon, late_unmap;
bool lazyfree = false;
int ret = SWAP_SUCCESS;
@@ -1109,6 +1112,10 @@ static unsigned long shrink_page_list(struct list_head *page_list,
}
anon = PageAnon(page);
+ if (anon)
+ late_unmap = true;
+ else
+ late_unmap = false;
/*
* Anonymous process memory has backing store?
@@ -1144,13 +1151,16 @@ static unsigned long shrink_page_list(struct list_head *page_list,
enum ttu_flags l_ttu_flags = ttu_flags;
#ifdef CONFIG_LATE_UNMAP
+ if (mapping->a_ops == &shmem_aops)
+ late_unmap = true;
+
/* Hanle the pte_dirty
and change pte to readonly.
Write behavior before unmap will make
pte dirty again. Then we can check
pte_dirty before unmap to make sure
the page was written or not. */
- if (anon)
+ if (late_unmap)
l_ttu_flags |= TTU_CHECK_DIRTY | TTU_READONLY;
#endif
TRY_TO_UNMAP(page, l_ttu_flags);
@@ -1211,7 +1221,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,
goto keep_locked;
#ifdef CONFIG_LATE_UNMAP
- if (anon) {
+ if (late_unmap) {
if (!PageSwapCache(page))
goto keep_locked;
@@ -1231,8 +1241,11 @@ static unsigned long shrink_page_list(struct list_head *page_list,
}
#endif
- if (page_mapped(page) && mapping)
+ if (page_mapped(page) && mapping) {
TRY_TO_UNMAP(page, ttu_flags);
+ if (!anon)
+ shmem_page_unmap(page);
+ }
}
#endif
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Minchan Kim <minchan@kernel.org> |
|---|---|
| Date | 2016-08-24 03:10 +0200 |
| Message-ID | <s9uRz-3sv-7@gated-at.bofh.it> |
| In reply to | #1467478 |
Hi Hui, On Mon, Aug 22, 2016 at 04:25:05PM +0800, Hui Zhu wrote: > Current ZRAM just can store all pages even if the compression rate > of a page is really low. So the compression rate of ZRAM is out of > control when it is running. > In my part, I did some test and record with ZRAM. The compression rate > is about 40%. > > This series of patches make ZRAM can just store the page that the > compressed size is smaller than a value. > With these patches, I set the value to 2048 and did the same test with > before. The compression rate is about 20%. The times of lowmemorykiller > also decreased. I have an interest about the feature for a long time but didn't work on it because I didn't have a good idea to implment it with generic approach without layer violation. I will look into this after handling urgent works. Thanks.
[toc] | [prev] | [next] | [standalone]
| From | Hui Zhu <teawater@gmail.com> |
|---|---|
| Date | 2016-08-24 04:00 +0200 |
| Message-ID | <s9vDX-3Ld-1@gated-at.bofh.it> |
| In reply to | #1469002 |
Hi Minchan, On Wed, Aug 24, 2016 at 9:04 AM, Minchan Kim <minchan@kernel.org> wrote: > Hi Hui, > > On Mon, Aug 22, 2016 at 04:25:05PM +0800, Hui Zhu wrote: >> Current ZRAM just can store all pages even if the compression rate >> of a page is really low. So the compression rate of ZRAM is out of >> control when it is running. >> In my part, I did some test and record with ZRAM. The compression rate >> is about 40%. >> >> This series of patches make ZRAM can just store the page that the >> compressed size is smaller than a value. >> With these patches, I set the value to 2048 and did the same test with >> before. The compression rate is about 20%. The times of lowmemorykiller >> also decreased. > > I have an interest about the feature for a long time but didn't work on it > because I didn't have a good idea to implment it with generic approach > without layer violation. I will look into this after handling urgent works. > > Thanks. That will be great. Thanks. Best, Hui
[toc] | [prev] | [next] | [standalone]
| From | Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com> |
|---|---|
| Date | 2016-08-25 08:20 +0200 |
| Message-ID | <s9Wb7-5Ex-5@gated-at.bofh.it> |
| In reply to | #1467478 |
Hello, On (08/22/16 16:25), Hui Zhu wrote: > > Current ZRAM just can store all pages even if the compression rate > of a page is really low. So the compression rate of ZRAM is out of > control when it is running. > In my part, I did some test and record with ZRAM. The compression rate > is about 40%. > > This series of patches make ZRAM can just store the page that the > compressed size is smaller than a value. > With these patches, I set the value to 2048 and did the same test with > before. The compression rate is about 20%. The times of lowmemorykiller > also decreased. I haven't looked at the patches in details yet. can you educate me a bit? is your test stable? why the number of lowmemorykill-s has decreased? ... or am reading "The times of lowmemorykiller also decreased" wrong? suppose you have X pages that result in bad compression size (from zram point of view). zram stores such pages uncompressed, IOW we have no memory savings - swapped out page lands in zsmalloc PAGE_SIZE class. now you don't try to store those pages in zsmalloc, but keep them as unevictable. so the page still occupies PAGE_SIZE; no memory saving again. why did it improve LMK? -ss
[toc] | [prev] | [next] | [standalone]
| From | Hui Zhu <teawater@gmail.com> |
|---|---|
| Date | 2016-08-25 10:30 +0200 |
| Message-ID | <s9YcW-6Yd-7@gated-at.bofh.it> |
| In reply to | #1469861 |
On Thu, Aug 25, 2016 at 2:09 PM, Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com> wrote: > Hello, > > On (08/22/16 16:25), Hui Zhu wrote: >> >> Current ZRAM just can store all pages even if the compression rate >> of a page is really low. So the compression rate of ZRAM is out of >> control when it is running. >> In my part, I did some test and record with ZRAM. The compression rate >> is about 40%. >> >> This series of patches make ZRAM can just store the page that the >> compressed size is smaller than a value. >> With these patches, I set the value to 2048 and did the same test with >> before. The compression rate is about 20%. The times of lowmemorykiller >> also decreased. > > I haven't looked at the patches in details yet. can you educate me a bit? > is your test stable? why the number of lowmemorykill-s has decreased? > ... or am reading "The times of lowmemorykiller also decreased" wrong? > > suppose you have X pages that result in bad compression size (from zram > point of view). zram stores such pages uncompressed, IOW we have no memory > savings - swapped out page lands in zsmalloc PAGE_SIZE class. now you > don't try to store those pages in zsmalloc, but keep them as unevictable. > so the page still occupies PAGE_SIZE; no memory saving again. why did it > improve LMK? No, zram will not save this page uncompressed with these patches. It will set it as non-swap and kick back to shrink_page_list. Shrink_page_list will remove this page from swapcache and kick it to unevictable list. Then this page will not be swaped before it get write. That is why most of code are around vmscan.c. Thanks, Hui > > -ss
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web