Re: [PATCH 3/4] zswap: Zero-filled pages handling

2017-02-17 Thread Dan Streetman
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

2017-02-17 Thread Dan Streetman
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

2016-08-19 Thread Srividya Desireddy

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

2016-08-19 Thread Srividya Desireddy

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

2016-08-19 Thread Srividya Desireddy
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


[PATCH 3/4] zswap: Zero-filled pages handling

2016-08-19 Thread Srividya Desireddy
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

2016-08-17 Thread Pekka Enberg
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

2016-08-17 Thread Pekka Enberg
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

2016-08-17 Thread Pekka Enberg
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


Re: [PATCH 3/4] zswap: Zero-filled pages handling

2016-08-17 Thread Pekka Enberg
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

2016-08-17 Thread Srividya Desireddy
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

2016-08-17 Thread Srividya Desireddy
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