aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorzhouxianrong <zhouxianrong@huawei.com>2017-02-24 17:59:27 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2017-02-24 20:46:56 -0500
commit8e19d540d107ee897eb9a874844060c94e2376c0 (patch)
treea268e406f52137cf0f81150c8f27b0c9100c6bfb
parent517663edd6b5d2a822469885994f34e092e2cf9f (diff)
zram: extend zero pages to same element pages
The idea is that without doing more calculations we extend zero pages to same element pages for zram. zero page is special case of same element page with zero element. 1. the test is done under android 7.0 2. startup too many applications circularly 3. sample the zero pages, same pages (none-zero element) and total pages in function page_zero_filled the result is listed as below: ZERO SAME TOTAL 36214 17842 598196 ZERO/TOTAL SAME/TOTAL (ZERO+SAME)/TOTAL ZERO/SAME AVERAGE 0.060631909 0.024990816 0.085622726 2.663825038 STDEV 0.00674612 0.005887625 0.009707034 2.115881328 MAX 0.069698422 0.030046087 0.094975336 7.56043956 MIN 0.03959586 0.007332205 0.056055193 1.928985507 from the above data, the benefit is about 2.5% and up to 3% of total swapout pages. The defect of the patch is that when we recovery a page from non-zero element the operations are low efficient for partial read. This patch extends zero_page to same_page so if there is any user to have monitored zero_pages, he will be surprised if the number is increased but it's not harmful, I believe. [minchan@kernel.org: do not free same element pages in zram_meta_free] Link: http://lkml.kernel.org/r/20170207065741.GA2567@bbox Link: http://lkml.kernel.org/r/1483692145-75357-1-git-send-email-zhouxianrong@huawei.com Link: http://lkml.kernel.org/r/1486307804-27903-1-git-send-email-minchan@kernel.org Signed-off-by: zhouxianrong <zhouxianrong@huawei.com> Signed-off-by: Minchan Kim <minchan@kernel.org> Cc: Sergey Senozhatsky <sergey.senozhatsky@gmail.com> Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--Documentation/blockdev/zram.txt6
-rw-r--r--drivers/block/zram/zram_drv.c87
-rw-r--r--drivers/block/zram/zram_drv.h9
3 files changed, 69 insertions, 33 deletions
diff --git a/Documentation/blockdev/zram.txt b/Documentation/blockdev/zram.txt
index 1c0c08d9206b..4fced8a21307 100644
--- a/Documentation/blockdev/zram.txt
+++ b/Documentation/blockdev/zram.txt
@@ -201,8 +201,8 @@ File /sys/block/zram<id>/mm_stat
201The stat file represents device's mm statistics. It consists of a single 201The stat file represents device's mm statistics. It consists of a single
202line of text and contains the following stats separated by whitespace: 202line of text and contains the following stats separated by whitespace:
203 orig_data_size uncompressed size of data stored in this disk. 203 orig_data_size uncompressed size of data stored in this disk.
204 This excludes zero-filled pages (zero_pages) since no 204 This excludes same-element-filled pages (same_pages) since
205 memory is allocated for them. 205 no memory is allocated for them.
206 Unit: bytes 206 Unit: bytes
207 compr_data_size compressed size of data stored in this disk 207 compr_data_size compressed size of data stored in this disk
208 mem_used_total the amount of memory allocated for this disk. This 208 mem_used_total the amount of memory allocated for this disk. This
@@ -214,7 +214,7 @@ line of text and contains the following stats separated by whitespace:
214 the compressed data 214 the compressed data
215 mem_used_max the maximum amount of memory zram have consumed to 215 mem_used_max the maximum amount of memory zram have consumed to
216 store the data 216 store the data
217 zero_pages the number of zero filled pages written to this disk. 217 same_pages the number of same element filled pages written to this disk.
218 No memory is allocated for such pages. 218 No memory is allocated for such pages.
219 pages_compacted the number of pages freed during compaction 219 pages_compacted the number of pages freed during compaction
220 220
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index 662d62878e47..e27d89a36c34 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -74,6 +74,17 @@ static void zram_clear_flag(struct zram_meta *meta, u32 index,
74 meta->table[index].value &= ~BIT(flag); 74 meta->table[index].value &= ~BIT(flag);
75} 75}
76 76
77static inline void zram_set_element(struct zram_meta *meta, u32 index,
78 unsigned long element)
79{
80 meta->table[index].element = element;
81}
82
83static inline void zram_clear_element(struct zram_meta *meta, u32 index)
84{
85 meta->table[index].element = 0;
86}
87
77static size_t zram_get_obj_size(struct zram_meta *meta, u32 index) 88static size_t zram_get_obj_size(struct zram_meta *meta, u32 index)
78{ 89{
79 return meta->table[index].value & (BIT(ZRAM_FLAG_SHIFT) - 1); 90 return meta->table[index].value & (BIT(ZRAM_FLAG_SHIFT) - 1);
@@ -146,31 +157,46 @@ static inline void update_used_max(struct zram *zram,
146 } while (old_max != cur_max); 157 } while (old_max != cur_max);
147} 158}
148 159
149static bool page_zero_filled(void *ptr) 160static inline void zram_fill_page(char *ptr, unsigned long len,
161 unsigned long value)
162{
163 int i;
164 unsigned long *page = (unsigned long *)ptr;
165
166 WARN_ON_ONCE(!IS_ALIGNED(len, sizeof(unsigned long)));
167
168 if (likely(value == 0)) {
169 memset(ptr, 0, len);
170 } else {
171 for (i = 0; i < len / sizeof(*page); i++)
172 page[i] = value;
173 }
174}
175
176static bool page_same_filled(void *ptr, unsigned long *element)
150{ 177{
151 unsigned int pos; 178 unsigned int pos;
152 unsigned long *page; 179 unsigned long *page;
153 180
154 page = (unsigned long *)ptr; 181 page = (unsigned long *)ptr;
155 182
156 for (pos = 0; pos != PAGE_SIZE / sizeof(*page); pos++) { 183 for (pos = 0; pos < PAGE_SIZE / sizeof(*page) - 1; pos++) {
157 if (page[pos]) 184 if (page[pos] != page[pos + 1])
158 return false; 185 return false;
159 } 186 }
160 187
188 *element = page[pos];
189
161 return true; 190 return true;
162} 191}
163 192
164static void handle_zero_page(struct bio_vec *bvec) 193static void handle_same_page(struct bio_vec *bvec, unsigned long element)
165{ 194{
166 struct page *page = bvec->bv_page; 195 struct page *page = bvec->bv_page;
167 void *user_mem; 196 void *user_mem;
168 197
169 user_mem = kmap_atomic(page); 198 user_mem = kmap_atomic(page);
170 if (is_partial_io(bvec)) 199 zram_fill_page(user_mem + bvec->bv_offset, bvec->bv_len, element);
171 memset(user_mem + bvec->bv_offset, 0, bvec->bv_len);
172 else
173 clear_page(user_mem);
174 kunmap_atomic(user_mem); 200 kunmap_atomic(user_mem);
175 201
176 flush_dcache_page(page); 202 flush_dcache_page(page);
@@ -363,7 +389,7 @@ static ssize_t mm_stat_show(struct device *dev,
363 mem_used << PAGE_SHIFT, 389 mem_used << PAGE_SHIFT,
364 zram->limit_pages << PAGE_SHIFT, 390 zram->limit_pages << PAGE_SHIFT,
365 max_used << PAGE_SHIFT, 391 max_used << PAGE_SHIFT,
366 (u64)atomic64_read(&zram->stats.zero_pages), 392 (u64)atomic64_read(&zram->stats.same_pages),
367 pool_stats.pages_compacted); 393 pool_stats.pages_compacted);
368 up_read(&zram->init_lock); 394 up_read(&zram->init_lock);
369 395
@@ -399,8 +425,11 @@ static void zram_meta_free(struct zram_meta *meta, u64 disksize)
399 /* Free all pages that are still in this zram device */ 425 /* Free all pages that are still in this zram device */
400 for (index = 0; index < num_pages; index++) { 426 for (index = 0; index < num_pages; index++) {
401 unsigned long handle = meta->table[index].handle; 427 unsigned long handle = meta->table[index].handle;
402 428 /*
403 if (!handle) 429 * No memory is allocated for same element filled pages.
430 * Simply clear same page flag.
431 */
432 if (!handle || zram_test_flag(meta, index, ZRAM_SAME))
404 continue; 433 continue;
405 434
406 zs_free(meta->mem_pool, handle); 435 zs_free(meta->mem_pool, handle);
@@ -450,18 +479,20 @@ static void zram_free_page(struct zram *zram, size_t index)
450 struct zram_meta *meta = zram->meta; 479 struct zram_meta *meta = zram->meta;
451 unsigned long handle = meta->table[index].handle; 480 unsigned long handle = meta->table[index].handle;
452 481
453 if (unlikely(!handle)) { 482 /*
454 /* 483 * No memory is allocated for same element filled pages.
455 * No memory is allocated for zero filled pages. 484 * Simply clear same page flag.
456 * Simply clear zero page flag. 485 */
457 */ 486 if (zram_test_flag(meta, index, ZRAM_SAME)) {
458 if (zram_test_flag(meta, index, ZRAM_ZERO)) { 487 zram_clear_flag(meta, index, ZRAM_SAME);
459 zram_clear_flag(meta, index, ZRAM_ZERO); 488 zram_clear_element(meta, index);
460 atomic64_dec(&zram->stats.zero_pages); 489 atomic64_dec(&zram->stats.same_pages);
461 }
462 return; 490 return;
463 } 491 }
464 492
493 if (!handle)
494 return;
495
465 zs_free(meta->mem_pool, handle); 496 zs_free(meta->mem_pool, handle);
466 497
467 atomic64_sub(zram_get_obj_size(meta, index), 498 atomic64_sub(zram_get_obj_size(meta, index),
@@ -484,9 +515,9 @@ static int zram_decompress_page(struct zram *zram, char *mem, u32 index)
484 handle = meta->table[index].handle; 515 handle = meta->table[index].handle;
485 size = zram_get_obj_size(meta, index); 516 size = zram_get_obj_size(meta, index);
486 517
487 if (!handle || zram_test_flag(meta, index, ZRAM_ZERO)) { 518 if (!handle || zram_test_flag(meta, index, ZRAM_SAME)) {
488 bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value); 519 bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);
489 clear_page(mem); 520 zram_fill_page(mem, PAGE_SIZE, meta->table[index].element);
490 return 0; 521 return 0;
491 } 522 }
492 523
@@ -522,9 +553,9 @@ static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec,
522 553
523 bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value); 554 bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value);
524 if (unlikely(!meta->table[index].handle) || 555 if (unlikely(!meta->table[index].handle) ||
525 zram_test_flag(meta, index, ZRAM_ZERO)) { 556 zram_test_flag(meta, index, ZRAM_SAME)) {
526 bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value); 557 bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);
527 handle_zero_page(bvec); 558 handle_same_page(bvec, meta->table[index].element);
528 return 0; 559 return 0;
529 } 560 }
530 bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value); 561 bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);
@@ -572,6 +603,7 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
572 struct zram_meta *meta = zram->meta; 603 struct zram_meta *meta = zram->meta;
573 struct zcomp_strm *zstrm = NULL; 604 struct zcomp_strm *zstrm = NULL;
574 unsigned long alloced_pages; 605 unsigned long alloced_pages;
606 unsigned long element;
575 607
576 page = bvec->bv_page; 608 page = bvec->bv_page;
577 if (is_partial_io(bvec)) { 609 if (is_partial_io(bvec)) {
@@ -600,16 +632,17 @@ compress_again:
600 uncmem = user_mem; 632 uncmem = user_mem;
601 } 633 }
602 634
603 if (page_zero_filled(uncmem)) { 635 if (page_same_filled(uncmem, &element)) {
604 if (user_mem) 636 if (user_mem)
605 kunmap_atomic(user_mem); 637 kunmap_atomic(user_mem);
606 /* Free memory associated with this sector now. */ 638 /* Free memory associated with this sector now. */
607 bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value); 639 bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value);
608 zram_free_page(zram, index); 640 zram_free_page(zram, index);
609 zram_set_flag(meta, index, ZRAM_ZERO); 641 zram_set_flag(meta, index, ZRAM_SAME);
642 zram_set_element(meta, index, element);
610 bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value); 643 bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);
611 644
612 atomic64_inc(&zram->stats.zero_pages); 645 atomic64_inc(&zram->stats.same_pages);
613 ret = 0; 646 ret = 0;
614 goto out; 647 goto out;
615 } 648 }
diff --git a/drivers/block/zram/zram_drv.h b/drivers/block/zram/zram_drv.h
index 2692554b7737..caeff51f1571 100644
--- a/drivers/block/zram/zram_drv.h
+++ b/drivers/block/zram/zram_drv.h
@@ -61,7 +61,7 @@ static const size_t max_zpage_size = PAGE_SIZE / 4 * 3;
61/* Flags for zram pages (table[page_no].value) */ 61/* Flags for zram pages (table[page_no].value) */
62enum zram_pageflags { 62enum zram_pageflags {
63 /* Page consists entirely of zeros */ 63 /* Page consists entirely of zeros */
64 ZRAM_ZERO = ZRAM_FLAG_SHIFT, 64 ZRAM_SAME = ZRAM_FLAG_SHIFT,
65 ZRAM_ACCESS, /* page is now accessed */ 65 ZRAM_ACCESS, /* page is now accessed */
66 66
67 __NR_ZRAM_PAGEFLAGS, 67 __NR_ZRAM_PAGEFLAGS,
@@ -71,7 +71,10 @@ enum zram_pageflags {
71 71
72/* Allocated for each disk page */ 72/* Allocated for each disk page */
73struct zram_table_entry { 73struct zram_table_entry {
74 unsigned long handle; 74 union {
75 unsigned long handle;
76 unsigned long element;
77 };
75 unsigned long value; 78 unsigned long value;
76}; 79};
77 80
@@ -83,7 +86,7 @@ struct zram_stats {
83 atomic64_t failed_writes; /* can happen when memory is too low */ 86 atomic64_t failed_writes; /* can happen when memory is too low */
84 atomic64_t invalid_io; /* non-page-aligned I/O requests */ 87 atomic64_t invalid_io; /* non-page-aligned I/O requests */
85 atomic64_t notify_free; /* no. of swap slot free notifications */ 88 atomic64_t notify_free; /* no. of swap slot free notifications */
86 atomic64_t zero_pages; /* no. of zero filled pages */ 89 atomic64_t same_pages; /* no. of same element filled pages */
87 atomic64_t pages_stored; /* no. of pages currently stored */ 90 atomic64_t pages_stored; /* no. of pages currently stored */
88 atomic_long_t max_used_pages; /* no. of maximum pages stored */ 91 atomic_long_t max_used_pages; /* no. of maximum pages stored */
89 atomic64_t writestall; /* no. of write slow paths */ 92 atomic64_t writestall; /* no. of write slow paths */