Re: [PATCH 3/4] zswap: Zero-filled pages handling
On Wed, Aug 17, 2016 at 6:18 AM, Srividya Desireddy <srividya...@samsung.com> wrote: > From: Srividya Desireddy <srividya...@samsung.com> > Date: Wed, 17 Aug 2016 14:34:14 +0530 > Subject: [PATCH 3/4] zswap: Zero-filled pages handling > > This patch adds a check in zswap_frontswap_store() to identify zero-filled > page before compression of the page. If the page is a zero-filled page, set > zswap_entry.zeroflag and skip the compression of the page and alloction > of memory in zpool. In zswap_frontswap_load(), check if the zeroflag is > set for the page in zswap_entry. If the flag is set, memset the page with > zero. This saves the decompression time during load. > > The overall overhead caused due to zero-filled page check is very minimal > when compared to the time saved by avoiding compression and allocation in > case of zero-filled pages. The load time of a zero-filled page is reduced > by 80% when compared to baseline. this is unrelated to the same-page patches. send this patch by itself. > > Signed-off-by: Srividya Desireddy <srividya...@samsung.com> > --- > mm/zswap.c | 58 ++ > 1 file changed, 50 insertions(+), 8 deletions(-) > > diff --git a/mm/zswap.c b/mm/zswap.c > index ae39c77..d0c3f96 100644 > --- a/mm/zswap.c > +++ b/mm/zswap.c > @@ -58,6 +58,9 @@ static atomic_t zswap_stored_pages = ATOMIC_INIT(0); > */ > static atomic_t zswap_duplicate_pages = ATOMIC_INIT(0); > > +/* The number of zero filled pages swapped out to zswap */ > +static atomic_t zswap_zero_pages = ATOMIC_INIT(0); > + > /* > * The statistics below are not protected from concurrent access for > * performance reasons so they may not be a 100% accurate. However, > @@ -172,6 +175,8 @@ struct zswap_handle { > *be held, there is no reason to also make refcount atomic. > * pool - the zswap_pool the entry's data is in > * zhandle - pointer to struct zswap_handle > + * zeroflag - the flag is set if the content of the page is filled with > + *zeros > */ > struct zswap_entry { > struct rb_node rbnode; > @@ -179,6 +184,7 @@ struct zswap_entry { > int refcount; > struct zswap_pool *pool; > struct zswap_handle *zhandle; > + unsigned char zeroflag; > }; > > struct zswap_header { > @@ -269,6 +275,7 @@ static struct zswap_entry *zswap_entry_cache_alloc(gfp_t > gfp) > if (!entry) > return NULL; > entry->refcount = 1; > + entry->zeroflag = 0; > entry->zhandle = NULL; > RB_CLEAR_NODE(>rbnode); > return entry; > @@ -477,13 +484,17 @@ static bool zswap_handle_is_unique(struct zswap_handle > *zhandle) > */ > static void zswap_free_entry(struct zswap_entry *entry) > { > - if (zswap_handle_is_unique(entry->zhandle)) { > - zpool_free(entry->pool->zpool, entry->zhandle->handle); > - zswap_handle_cache_free(entry->zhandle); > - zswap_pool_put(entry->pool); > - } else { > - entry->zhandle->ref_count--; > - atomic_dec(_duplicate_pages); > + if (entry->zeroflag) > + atomic_dec(_zero_pages); > + else { > + if (zswap_handle_is_unique(entry->zhandle)) { > + zpool_free(entry->pool->zpool, > entry->zhandle->handle); > + zswap_handle_cache_free(entry->zhandle); > + zswap_pool_put(entry->pool); > + } else { > + entry->zhandle->ref_count--; > + atomic_dec(_duplicate_pages); > + } > } > zswap_entry_cache_free(entry); > atomic_dec(_stored_pages); > @@ -1140,6 +1151,21 @@ static int zswap_shrink(void) > return ret; > } > > +static int zswap_is_page_zero_filled(void *ptr) > +{ > + unsigned int pos; > + unsigned long *page; > + > + page = (unsigned long *)ptr; > + > + for (pos = 0; pos != PAGE_SIZE / sizeof(*page); pos++) { > + if (page[pos]) > + return 0; > + } > + > + return 1; > +} > + > /* > * frontswap hooks > **/ > @@ -1183,6 +1209,13 @@ static int zswap_frontswap_store(unsigned type, > pgoff_t offset, > } > > src = kmap_atomic(page); > + if (zswap_is_page_zero_filled(src)) { > + kunmap_atomic(src); > + entry->offset = offset; > +
Re: [PATCH 3/4] zswap: Zero-filled pages handling
On Wed, Aug 17, 2016 at 6:18 AM, Srividya Desireddy wrote: > From: Srividya Desireddy > Date: Wed, 17 Aug 2016 14:34:14 +0530 > Subject: [PATCH 3/4] zswap: Zero-filled pages handling > > This patch adds a check in zswap_frontswap_store() to identify zero-filled > page before compression of the page. If the page is a zero-filled page, set > zswap_entry.zeroflag and skip the compression of the page and alloction > of memory in zpool. In zswap_frontswap_load(), check if the zeroflag is > set for the page in zswap_entry. If the flag is set, memset the page with > zero. This saves the decompression time during load. > > The overall overhead caused due to zero-filled page check is very minimal > when compared to the time saved by avoiding compression and allocation in > case of zero-filled pages. The load time of a zero-filled page is reduced > by 80% when compared to baseline. this is unrelated to the same-page patches. send this patch by itself. > > Signed-off-by: Srividya Desireddy > --- > mm/zswap.c | 58 ++ > 1 file changed, 50 insertions(+), 8 deletions(-) > > diff --git a/mm/zswap.c b/mm/zswap.c > index ae39c77..d0c3f96 100644 > --- a/mm/zswap.c > +++ b/mm/zswap.c > @@ -58,6 +58,9 @@ static atomic_t zswap_stored_pages = ATOMIC_INIT(0); > */ > static atomic_t zswap_duplicate_pages = ATOMIC_INIT(0); > > +/* The number of zero filled pages swapped out to zswap */ > +static atomic_t zswap_zero_pages = ATOMIC_INIT(0); > + > /* > * The statistics below are not protected from concurrent access for > * performance reasons so they may not be a 100% accurate. However, > @@ -172,6 +175,8 @@ struct zswap_handle { > *be held, there is no reason to also make refcount atomic. > * pool - the zswap_pool the entry's data is in > * zhandle - pointer to struct zswap_handle > + * zeroflag - the flag is set if the content of the page is filled with > + *zeros > */ > struct zswap_entry { > struct rb_node rbnode; > @@ -179,6 +184,7 @@ struct zswap_entry { > int refcount; > struct zswap_pool *pool; > struct zswap_handle *zhandle; > + unsigned char zeroflag; > }; > > struct zswap_header { > @@ -269,6 +275,7 @@ static struct zswap_entry *zswap_entry_cache_alloc(gfp_t > gfp) > if (!entry) > return NULL; > entry->refcount = 1; > + entry->zeroflag = 0; > entry->zhandle = NULL; > RB_CLEAR_NODE(>rbnode); > return entry; > @@ -477,13 +484,17 @@ static bool zswap_handle_is_unique(struct zswap_handle > *zhandle) > */ > static void zswap_free_entry(struct zswap_entry *entry) > { > - if (zswap_handle_is_unique(entry->zhandle)) { > - zpool_free(entry->pool->zpool, entry->zhandle->handle); > - zswap_handle_cache_free(entry->zhandle); > - zswap_pool_put(entry->pool); > - } else { > - entry->zhandle->ref_count--; > - atomic_dec(_duplicate_pages); > + if (entry->zeroflag) > + atomic_dec(_zero_pages); > + else { > + if (zswap_handle_is_unique(entry->zhandle)) { > + zpool_free(entry->pool->zpool, > entry->zhandle->handle); > + zswap_handle_cache_free(entry->zhandle); > + zswap_pool_put(entry->pool); > + } else { > + entry->zhandle->ref_count--; > + atomic_dec(_duplicate_pages); > + } > } > zswap_entry_cache_free(entry); > atomic_dec(_stored_pages); > @@ -1140,6 +1151,21 @@ static int zswap_shrink(void) > return ret; > } > > +static int zswap_is_page_zero_filled(void *ptr) > +{ > + unsigned int pos; > + unsigned long *page; > + > + page = (unsigned long *)ptr; > + > + for (pos = 0; pos != PAGE_SIZE / sizeof(*page); pos++) { > + if (page[pos]) > + return 0; > + } > + > + return 1; > +} > + > /* > * frontswap hooks > **/ > @@ -1183,6 +1209,13 @@ static int zswap_frontswap_store(unsigned type, > pgoff_t offset, > } > > src = kmap_atomic(page); > + if (zswap_is_page_zero_filled(src)) { > + kunmap_atomic(src); > + entry->offset = offset; > + entry->zeroflag = 1; > + atomic_inc(_zero_pages); > + g
[PATCH 3/4] zswap: Zero-filled pages handling
On 17 August 2016 at 18:02, Pekka Enbergwrote: > On Wed, Aug 17, 2016 at 1:18 PM, Srividya Desireddy > wrote: >>> This patch adds a check in zswap_frontswap_store() to identify zero-filled >>> page before compression of the page. If the page is a zero-filled page, set >>> zswap_entry.zeroflag and skip the compression of the page and alloction >>> of memory in zpool. In zswap_frontswap_load(), check if the zeroflag is >>> set for the page in zswap_entry. If the flag is set, memset the page with >>> zero. This saves the decompression time during load. >>> >>> The overall overhead caused due to zero-filled page check is very minimal >>> when compared to the time saved by avoiding compression and allocation in >>> case of zero-filled pages. The load time of a zero-filled page is reduced >>> by 80% when compared to baseline. > > On Wed, Aug 17, 2016 at 3:25 PM, Pekka Enberg wrote: >> AFAICT, that's an overall improvement only if there are a lot of >> zero-filled pages because it's just overhead for pages that we *need* >> to compress, no? So I suppose the question is, are there a lot of >> zero-filled pages that we need to swap and why is that the case? > > I suppose reading your cover letter would have been helpful before > sending out my email: > > "Experiments have shown that around 10-15% of pages stored in zswap are > duplicates which results in 10-12% more RAM required to store these > duplicate compressed pages." > > But I still don't understand why we have zero-filled pages that we are > swapping out. > > - Pekka Zero-filled pages exists in memory because applications may be initializing the allocated pages with zeros and not using them; or the actual content written to the memory pages during execution itself is zeros. The existing page reclamation path in kernel does not check for zero-filled pages in the anonymous LRU lists before swapping out. - Srividya
[PATCH 3/4] zswap: Zero-filled pages handling
On 17 August 2016 at 18:02, Pekka Enberg wrote: > On Wed, Aug 17, 2016 at 1:18 PM, Srividya Desireddy > wrote: >>> This patch adds a check in zswap_frontswap_store() to identify zero-filled >>> page before compression of the page. If the page is a zero-filled page, set >>> zswap_entry.zeroflag and skip the compression of the page and alloction >>> of memory in zpool. In zswap_frontswap_load(), check if the zeroflag is >>> set for the page in zswap_entry. If the flag is set, memset the page with >>> zero. This saves the decompression time during load. >>> >>> The overall overhead caused due to zero-filled page check is very minimal >>> when compared to the time saved by avoiding compression and allocation in >>> case of zero-filled pages. The load time of a zero-filled page is reduced >>> by 80% when compared to baseline. > > On Wed, Aug 17, 2016 at 3:25 PM, Pekka Enberg wrote: >> AFAICT, that's an overall improvement only if there are a lot of >> zero-filled pages because it's just overhead for pages that we *need* >> to compress, no? So I suppose the question is, are there a lot of >> zero-filled pages that we need to swap and why is that the case? > > I suppose reading your cover letter would have been helpful before > sending out my email: > > "Experiments have shown that around 10-15% of pages stored in zswap are > duplicates which results in 10-12% more RAM required to store these > duplicate compressed pages." > > But I still don't understand why we have zero-filled pages that we are > swapping out. > > - Pekka Zero-filled pages exists in memory because applications may be initializing the allocated pages with zeros and not using them; or the actual content written to the memory pages during execution itself is zeros. The existing page reclamation path in kernel does not check for zero-filled pages in the anonymous LRU lists before swapping out. - Srividya
[PATCH 3/4] zswap: Zero-filled pages handling
On 17 August 2016 at 17:55, Pekka Enbergwrote: > On Wed, Aug 17, 2016 at 1:18 PM, Srividya Desireddy > wrote: >> @@ -1314,6 +1347,13 @@ static int zswap_frontswap_load(unsigned type, >> pgoff_t offset, >> } >> spin_unlock(>lock); >> >> + if (entry->zeroflag) { >> + dst = kmap_atomic(page); >> + memset(dst, 0, PAGE_SIZE); >> + kunmap_atomic(dst); >> + goto freeentry; >> + } > > Don't we need the same thing in zswap_writeback_entry() for the > ZSWAP_SWAPCACHE_NEW case? Zero-filled pages are not compressed and stored in the zpool memory. Zpool handle will not be created for zero-filled pages, hence they can not be picked for eviction/writeback to the swap device. - Srividya > >> + >> /* decompress */ >> dlen = PAGE_SIZE; >> src = (u8 *)zpool_map_handle(entry->pool->zpool, >> entry->zhandle->handle, >> @@ -1327,6 +1367,7 @@ static int zswap_frontswap_load(unsigned type, pgoff_t >> offset, >> zpool_unmap_handle(entry->pool->zpool, entry->zhandle->handle); >> BUG_ON(ret); > > - Pekka
[PATCH 3/4] zswap: Zero-filled pages handling
On 17 August 2016 at 17:55, Pekka Enberg wrote: > On Wed, Aug 17, 2016 at 1:18 PM, Srividya Desireddy > wrote: >> @@ -1314,6 +1347,13 @@ static int zswap_frontswap_load(unsigned type, >> pgoff_t offset, >> } >> spin_unlock(>lock); >> >> + if (entry->zeroflag) { >> + dst = kmap_atomic(page); >> + memset(dst, 0, PAGE_SIZE); >> + kunmap_atomic(dst); >> + goto freeentry; >> + } > > Don't we need the same thing in zswap_writeback_entry() for the > ZSWAP_SWAPCACHE_NEW case? Zero-filled pages are not compressed and stored in the zpool memory. Zpool handle will not be created for zero-filled pages, hence they can not be picked for eviction/writeback to the swap device. - Srividya > >> + >> /* decompress */ >> dlen = PAGE_SIZE; >> src = (u8 *)zpool_map_handle(entry->pool->zpool, >> entry->zhandle->handle, >> @@ -1327,6 +1367,7 @@ static int zswap_frontswap_load(unsigned type, pgoff_t >> offset, >> zpool_unmap_handle(entry->pool->zpool, entry->zhandle->handle); >> BUG_ON(ret); > > - Pekka
Re: [PATCH 3/4] zswap: Zero-filled pages handling
On Wed, Aug 17, 2016 at 1:18 PM, Srividya Desireddywrote: >> This patch adds a check in zswap_frontswap_store() to identify zero-filled >> page before compression of the page. If the page is a zero-filled page, set >> zswap_entry.zeroflag and skip the compression of the page and alloction >> of memory in zpool. In zswap_frontswap_load(), check if the zeroflag is >> set for the page in zswap_entry. If the flag is set, memset the page with >> zero. This saves the decompression time during load. >> >> The overall overhead caused due to zero-filled page check is very minimal >> when compared to the time saved by avoiding compression and allocation in >> case of zero-filled pages. The load time of a zero-filled page is reduced >> by 80% when compared to baseline. On Wed, Aug 17, 2016 at 3:25 PM, Pekka Enberg wrote: > AFAICT, that's an overall improvement only if there are a lot of > zero-filled pages because it's just overhead for pages that we *need* > to compress, no? So I suppose the question is, are there a lot of > zero-filled pages that we need to swap and why is that the case? I suppose reading your cover letter would have been helpful before sending out my email: "Experiments have shown that around 10-15% of pages stored in zswap are duplicates which results in 10-12% more RAM required to store these duplicate compressed pages." But I still don't understand why we have zero-filled pages that we are swapping out. - Pekka
Re: [PATCH 3/4] zswap: Zero-filled pages handling
On Wed, Aug 17, 2016 at 1:18 PM, Srividya Desireddy wrote: >> This patch adds a check in zswap_frontswap_store() to identify zero-filled >> page before compression of the page. If the page is a zero-filled page, set >> zswap_entry.zeroflag and skip the compression of the page and alloction >> of memory in zpool. In zswap_frontswap_load(), check if the zeroflag is >> set for the page in zswap_entry. If the flag is set, memset the page with >> zero. This saves the decompression time during load. >> >> The overall overhead caused due to zero-filled page check is very minimal >> when compared to the time saved by avoiding compression and allocation in >> case of zero-filled pages. The load time of a zero-filled page is reduced >> by 80% when compared to baseline. On Wed, Aug 17, 2016 at 3:25 PM, Pekka Enberg wrote: > AFAICT, that's an overall improvement only if there are a lot of > zero-filled pages because it's just overhead for pages that we *need* > to compress, no? So I suppose the question is, are there a lot of > zero-filled pages that we need to swap and why is that the case? I suppose reading your cover letter would have been helpful before sending out my email: "Experiments have shown that around 10-15% of pages stored in zswap are duplicates which results in 10-12% more RAM required to store these duplicate compressed pages." But I still don't understand why we have zero-filled pages that we are swapping out. - Pekka
Re: [PATCH 3/4] zswap: Zero-filled pages handling
On Wed, Aug 17, 2016 at 1:18 PM, Srividya Desireddywrote: > This patch adds a check in zswap_frontswap_store() to identify zero-filled > page before compression of the page. If the page is a zero-filled page, set > zswap_entry.zeroflag and skip the compression of the page and alloction > of memory in zpool. In zswap_frontswap_load(), check if the zeroflag is > set for the page in zswap_entry. If the flag is set, memset the page with > zero. This saves the decompression time during load. > > The overall overhead caused due to zero-filled page check is very minimal > when compared to the time saved by avoiding compression and allocation in > case of zero-filled pages. The load time of a zero-filled page is reduced > by 80% when compared to baseline. AFAICT, that's an overall improvement only if there are a lot of zero-filled pages because it's just overhead for pages that we *need* to compress, no? So I suppose the question is, are there a lot of zero-filled pages that we need to swap and why is that the case? > @@ -1314,6 +1347,13 @@ static int zswap_frontswap_load(unsigned type, pgoff_t > offset, > } > spin_unlock(>lock); > > + if (entry->zeroflag) { > + dst = kmap_atomic(page); > + memset(dst, 0, PAGE_SIZE); > + kunmap_atomic(dst); > + goto freeentry; > + } Don't we need the same thing in zswap_writeback_entry() for the ZSWAP_SWAPCACHE_NEW case? > + > /* decompress */ > dlen = PAGE_SIZE; > src = (u8 *)zpool_map_handle(entry->pool->zpool, > entry->zhandle->handle, > @@ -1327,6 +1367,7 @@ static int zswap_frontswap_load(unsigned type, pgoff_t > offset, > zpool_unmap_handle(entry->pool->zpool, entry->zhandle->handle); > BUG_ON(ret); - Pekka
Re: [PATCH 3/4] zswap: Zero-filled pages handling
On Wed, Aug 17, 2016 at 1:18 PM, Srividya Desireddy wrote: > This patch adds a check in zswap_frontswap_store() to identify zero-filled > page before compression of the page. If the page is a zero-filled page, set > zswap_entry.zeroflag and skip the compression of the page and alloction > of memory in zpool. In zswap_frontswap_load(), check if the zeroflag is > set for the page in zswap_entry. If the flag is set, memset the page with > zero. This saves the decompression time during load. > > The overall overhead caused due to zero-filled page check is very minimal > when compared to the time saved by avoiding compression and allocation in > case of zero-filled pages. The load time of a zero-filled page is reduced > by 80% when compared to baseline. AFAICT, that's an overall improvement only if there are a lot of zero-filled pages because it's just overhead for pages that we *need* to compress, no? So I suppose the question is, are there a lot of zero-filled pages that we need to swap and why is that the case? > @@ -1314,6 +1347,13 @@ static int zswap_frontswap_load(unsigned type, pgoff_t > offset, > } > spin_unlock(>lock); > > + if (entry->zeroflag) { > + dst = kmap_atomic(page); > + memset(dst, 0, PAGE_SIZE); > + kunmap_atomic(dst); > + goto freeentry; > + } Don't we need the same thing in zswap_writeback_entry() for the ZSWAP_SWAPCACHE_NEW case? > + > /* decompress */ > dlen = PAGE_SIZE; > src = (u8 *)zpool_map_handle(entry->pool->zpool, > entry->zhandle->handle, > @@ -1327,6 +1367,7 @@ static int zswap_frontswap_load(unsigned type, pgoff_t > offset, > zpool_unmap_handle(entry->pool->zpool, entry->zhandle->handle); > BUG_ON(ret); - Pekka
[PATCH 3/4] zswap: Zero-filled pages handling
From: Srividya Desireddy <srividya...@samsung.com> Date: Wed, 17 Aug 2016 14:34:14 +0530 Subject: [PATCH 3/4] zswap: Zero-filled pages handling This patch adds a check in zswap_frontswap_store() to identify zero-filled page before compression of the page. If the page is a zero-filled page, set zswap_entry.zeroflag and skip the compression of the page and alloction of memory in zpool. In zswap_frontswap_load(), check if the zeroflag is set for the page in zswap_entry. If the flag is set, memset the page with zero. This saves the decompression time during load. The overall overhead caused due to zero-filled page check is very minimal when compared to the time saved by avoiding compression and allocation in case of zero-filled pages. The load time of a zero-filled page is reduced by 80% when compared to baseline. Signed-off-by: Srividya Desireddy <srividya...@samsung.com> --- mm/zswap.c | 58 ++ 1 file changed, 50 insertions(+), 8 deletions(-) diff --git a/mm/zswap.c b/mm/zswap.c index ae39c77..d0c3f96 100644 --- a/mm/zswap.c +++ b/mm/zswap.c @@ -58,6 +58,9 @@ static atomic_t zswap_stored_pages = ATOMIC_INIT(0); */ static atomic_t zswap_duplicate_pages = ATOMIC_INIT(0); +/* The number of zero filled pages swapped out to zswap */ +static atomic_t zswap_zero_pages = ATOMIC_INIT(0); + /* * The statistics below are not protected from concurrent access for * performance reasons so they may not be a 100% accurate. However, @@ -172,6 +175,8 @@ struct zswap_handle { *be held, there is no reason to also make refcount atomic. * pool - the zswap_pool the entry's data is in * zhandle - pointer to struct zswap_handle + * zeroflag - the flag is set if the content of the page is filled with + *zeros */ struct zswap_entry { struct rb_node rbnode; @@ -179,6 +184,7 @@ struct zswap_entry { int refcount; struct zswap_pool *pool; struct zswap_handle *zhandle; + unsigned char zeroflag; }; struct zswap_header { @@ -269,6 +275,7 @@ static struct zswap_entry *zswap_entry_cache_alloc(gfp_t gfp) if (!entry) return NULL; entry->refcount = 1; + entry->zeroflag = 0; entry->zhandle = NULL; RB_CLEAR_NODE(>rbnode); return entry; @@ -477,13 +484,17 @@ static bool zswap_handle_is_unique(struct zswap_handle *zhandle) */ static void zswap_free_entry(struct zswap_entry *entry) { - if (zswap_handle_is_unique(entry->zhandle)) { - zpool_free(entry->pool->zpool, entry->zhandle->handle); - zswap_handle_cache_free(entry->zhandle); - zswap_pool_put(entry->pool); - } else { - entry->zhandle->ref_count--; - atomic_dec(_duplicate_pages); + if (entry->zeroflag) + atomic_dec(_zero_pages); + else { + if (zswap_handle_is_unique(entry->zhandle)) { + zpool_free(entry->pool->zpool, entry->zhandle->handle); + zswap_handle_cache_free(entry->zhandle); + zswap_pool_put(entry->pool); + } else { + entry->zhandle->ref_count--; + atomic_dec(_duplicate_pages); + } } zswap_entry_cache_free(entry); atomic_dec(_stored_pages); @@ -1140,6 +1151,21 @@ static int zswap_shrink(void) return ret; } +static int zswap_is_page_zero_filled(void *ptr) +{ + unsigned int pos; + unsigned long *page; + + page = (unsigned long *)ptr; + + for (pos = 0; pos != PAGE_SIZE / sizeof(*page); pos++) { + if (page[pos]) + return 0; + } + + return 1; +} + /* * frontswap hooks **/ @@ -1183,6 +1209,13 @@ static int zswap_frontswap_store(unsigned type, pgoff_t offset, } src = kmap_atomic(page); + if (zswap_is_page_zero_filled(src)) { + kunmap_atomic(src); + entry->offset = offset; + entry->zeroflag = 1; + atomic_inc(_zero_pages); + goto insert_entry; + } if (zswap_same_page_sharing) { checksum = jhash2((const u32 *)src, PAGE_SIZE / 4, 17); @@ -1314,6 +1347,13 @@ static int zswap_frontswap_load(unsigned type, pgoff_t offset, } spin_unlock(>lock); + if (entry->zeroflag) { + dst = kmap_atomic(page); + memset(dst, 0, PAGE_SIZE); + kunmap_atomic(dst); + goto freeentry; + } + /* decompress */ dlen = PAGE_SIZE; src = (u8 *)zpool_map_handle(entry->pool->zpool, entry->zhandle->handle, @@ -1327,6 +1367,7 @@ static int zswap_frontswap_l
[PATCH 3/4] zswap: Zero-filled pages handling
From: Srividya Desireddy Date: Wed, 17 Aug 2016 14:34:14 +0530 Subject: [PATCH 3/4] zswap: Zero-filled pages handling This patch adds a check in zswap_frontswap_store() to identify zero-filled page before compression of the page. If the page is a zero-filled page, set zswap_entry.zeroflag and skip the compression of the page and alloction of memory in zpool. In zswap_frontswap_load(), check if the zeroflag is set for the page in zswap_entry. If the flag is set, memset the page with zero. This saves the decompression time during load. The overall overhead caused due to zero-filled page check is very minimal when compared to the time saved by avoiding compression and allocation in case of zero-filled pages. The load time of a zero-filled page is reduced by 80% when compared to baseline. Signed-off-by: Srividya Desireddy --- mm/zswap.c | 58 ++ 1 file changed, 50 insertions(+), 8 deletions(-) diff --git a/mm/zswap.c b/mm/zswap.c index ae39c77..d0c3f96 100644 --- a/mm/zswap.c +++ b/mm/zswap.c @@ -58,6 +58,9 @@ static atomic_t zswap_stored_pages = ATOMIC_INIT(0); */ static atomic_t zswap_duplicate_pages = ATOMIC_INIT(0); +/* The number of zero filled pages swapped out to zswap */ +static atomic_t zswap_zero_pages = ATOMIC_INIT(0); + /* * The statistics below are not protected from concurrent access for * performance reasons so they may not be a 100% accurate. However, @@ -172,6 +175,8 @@ struct zswap_handle { *be held, there is no reason to also make refcount atomic. * pool - the zswap_pool the entry's data is in * zhandle - pointer to struct zswap_handle + * zeroflag - the flag is set if the content of the page is filled with + *zeros */ struct zswap_entry { struct rb_node rbnode; @@ -179,6 +184,7 @@ struct zswap_entry { int refcount; struct zswap_pool *pool; struct zswap_handle *zhandle; + unsigned char zeroflag; }; struct zswap_header { @@ -269,6 +275,7 @@ static struct zswap_entry *zswap_entry_cache_alloc(gfp_t gfp) if (!entry) return NULL; entry->refcount = 1; + entry->zeroflag = 0; entry->zhandle = NULL; RB_CLEAR_NODE(>rbnode); return entry; @@ -477,13 +484,17 @@ static bool zswap_handle_is_unique(struct zswap_handle *zhandle) */ static void zswap_free_entry(struct zswap_entry *entry) { - if (zswap_handle_is_unique(entry->zhandle)) { - zpool_free(entry->pool->zpool, entry->zhandle->handle); - zswap_handle_cache_free(entry->zhandle); - zswap_pool_put(entry->pool); - } else { - entry->zhandle->ref_count--; - atomic_dec(_duplicate_pages); + if (entry->zeroflag) + atomic_dec(_zero_pages); + else { + if (zswap_handle_is_unique(entry->zhandle)) { + zpool_free(entry->pool->zpool, entry->zhandle->handle); + zswap_handle_cache_free(entry->zhandle); + zswap_pool_put(entry->pool); + } else { + entry->zhandle->ref_count--; + atomic_dec(_duplicate_pages); + } } zswap_entry_cache_free(entry); atomic_dec(_stored_pages); @@ -1140,6 +1151,21 @@ static int zswap_shrink(void) return ret; } +static int zswap_is_page_zero_filled(void *ptr) +{ + unsigned int pos; + unsigned long *page; + + page = (unsigned long *)ptr; + + for (pos = 0; pos != PAGE_SIZE / sizeof(*page); pos++) { + if (page[pos]) + return 0; + } + + return 1; +} + /* * frontswap hooks **/ @@ -1183,6 +1209,13 @@ static int zswap_frontswap_store(unsigned type, pgoff_t offset, } src = kmap_atomic(page); + if (zswap_is_page_zero_filled(src)) { + kunmap_atomic(src); + entry->offset = offset; + entry->zeroflag = 1; + atomic_inc(_zero_pages); + goto insert_entry; + } if (zswap_same_page_sharing) { checksum = jhash2((const u32 *)src, PAGE_SIZE / 4, 17); @@ -1314,6 +1347,13 @@ static int zswap_frontswap_load(unsigned type, pgoff_t offset, } spin_unlock(>lock); + if (entry->zeroflag) { + dst = kmap_atomic(page); + memset(dst, 0, PAGE_SIZE); + kunmap_atomic(dst); + goto freeentry; + } + /* decompress */ dlen = PAGE_SIZE; src = (u8 *)zpool_map_handle(entry->pool->zpool, entry->zhandle->handle, @@ -1327,6 +1367,7 @@ static int zswap_frontswap_load(unsigned type, pgoff_t offset, zpoo