Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1226032 > unrolled thread

[PATCH 0/2] prepare zbud to be used by zram as underlying allocator

Started byVitaly Wool <vitalywool@gmail.com>
First post2015-09-16 13:50 +0200
Last post2015-09-21 23:20 +0200
Articles 12 — 5 participants

Back to article view | Back to linux.kernel


Contents

  [PATCH 0/2] prepare zbud to be used by zram as underlying allocator Vitaly Wool <vitalywool@gmail.com> - 2015-09-16 13:50 +0200
    [PATCH 1/2] zbud: allow PAGE_SIZE allocations Vitaly Wool <vitalywool@gmail.com> - 2015-09-16 14:00 +0200
      Re: [PATCH 1/2] zbud: allow PAGE_SIZE allocations Vlastimil Babka <vbabka@suse.cz> - 2015-09-17 15:10 +0200
        Re: [PATCH 1/2] zbud: allow PAGE_SIZE allocations Vitaly Wool <vitalywool@gmail.com> - 2015-09-18 10:10 +0200
          Re: [PATCH 1/2] zbud: allow PAGE_SIZE allocations Dan Streetman <ddstreet@ieee.org> - 2015-09-21 17:30 +0200
      Re: [PATCH 1/2] zbud: allow PAGE_SIZE allocations Dan Streetman <ddstreet@ieee.org> - 2015-09-21 18:20 +0200
    [PATCH 2/2] zpool/zsmalloc/zbud: align on interfaces Vitaly Wool <vitalywool@gmail.com> - 2015-09-16 14:00 +0200
      Re: [PATCH 2/2] zpool/zsmalloc/zbud: align on interfaces Dan Streetman <ddstreet@ieee.org> - 2015-09-21 19:20 +0200
    Re: [PATCH 0/2] prepare zbud to be used by zram as underlying  allocator Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com> - 2015-09-17 03:30 +0200
      Re: [PATCH 0/2] prepare zbud to be used by zram as underlying allocator Vitaly Wool <vitalywool@gmail.com> - 2015-09-17 12:30 +0200
        Re: [PATCH 0/2] prepare zbud to be used by zram as underlying  allocator Minchan Kim <minchan@kernel.org> - 2015-09-21 06:20 +0200
          Re: [PATCH 0/2] prepare zbud to be used by zram as underlying allocator Vitaly Wool <vitalywool@gmail.com> - 2015-09-21 23:20 +0200

#1226032 — [PATCH 0/2] prepare zbud to be used by zram as underlying allocator

FromVitaly Wool <vitalywool@gmail.com>
Date2015-09-16 13:50 +0200
Subject[PATCH 0/2] prepare zbud to be used by zram as underlying allocator
Message-ID<q9jnQ-3nM-17@gated-at.bofh.it>
Hi,

as a follow-up to my previous patchset, I decided to first prepare
zbud/zpool related patches and then have some testing rounds and
performance measurements for zram running over both, and come up
with improved/verified zram/zpool patches then. So for now, here
comes the zbud/zpool part.

-- 
Vitaly Wool <vitalywool@gmail.com>
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [next] | [standalone]


#1226033 — [PATCH 1/2] zbud: allow PAGE_SIZE allocations

FromVitaly Wool <vitalywool@gmail.com>
Date2015-09-16 14:00 +0200
Subject[PATCH 1/2] zbud: allow PAGE_SIZE allocations
Message-ID<q9jxw-3z3-5@gated-at.bofh.it>
In reply to#1226032
For zram to be able to use zbud via the common zpool API,
allocations of size PAGE_SIZE should be allowed by zpool.
zbud uses the beginning of an allocated page for its internal
structure but it is not a problem as long as we keep track of
such special pages using a newly introduced page flag.
To be able to keep track of zbud pages in any case, struct page's
lru pointer will be used for zbud page lists instead of the one
that used to be part of the aforementioned internal structure.

Signed-off-by: Vitaly Wool <vitalywool@gmail.com>
---
 include/linux/page-flags.h |  3 ++
 mm/zbud.c                  | 71 ++++++++++++++++++++++++++++++++++++++--------
 2 files changed, 62 insertions(+), 12 deletions(-)

diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
index 416509e..dd47cf0 100644
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -134,6 +134,9 @@ enum pageflags {
 
 	/* SLOB */
 	PG_slob_free = PG_private,
+
+	/* ZBUD */
+	PG_uncompressed = PG_owner_priv_1,
 };
 
 #ifndef __GENERATING_BOUNDS_H
diff --git a/mm/zbud.c b/mm/zbud.c
index fa48bcdf..ee8b5d6 100644
--- a/mm/zbud.c
+++ b/mm/zbud.c
@@ -107,13 +107,11 @@ struct zbud_pool {
  * struct zbud_header - zbud page metadata occupying the first chunk of each
  *			zbud page.
  * @buddy:	links the zbud page into the unbuddied/buddied lists in the pool
- * @lru:	links the zbud page into the lru list in the pool
  * @first_chunks:	the size of the first buddy in chunks, 0 if free
  * @last_chunks:	the size of the last buddy in chunks, 0 if free
  */
 struct zbud_header {
 	struct list_head buddy;
-	struct list_head lru;
 	unsigned int first_chunks;
 	unsigned int last_chunks;
 	bool under_reclaim;
@@ -221,6 +219,7 @@ MODULE_ALIAS("zpool-zbud");
 *****************/
 /* Just to make the code easier to read */
 enum buddy {
+	FULL,
 	FIRST,
 	LAST
 };
@@ -241,7 +240,7 @@ static struct zbud_header *init_zbud_page(struct page *page)
 	zhdr->first_chunks = 0;
 	zhdr->last_chunks = 0;
 	INIT_LIST_HEAD(&zhdr->buddy);
-	INIT_LIST_HEAD(&zhdr->lru);
+	INIT_LIST_HEAD(&page->lru);
 	zhdr->under_reclaim = 0;
 	return zhdr;
 }
@@ -267,11 +266,18 @@ static unsigned long encode_handle(struct zbud_header *zhdr, enum buddy bud)
 	 * over the zbud header in the first chunk.
 	 */
 	handle = (unsigned long)zhdr;
-	if (bud == FIRST)
+	switch (bud) {
+	case FIRST:
 		/* skip over zbud header */
 		handle += ZHDR_SIZE_ALIGNED;
-	else /* bud == LAST */
+		break;
+	case LAST:
 		handle += PAGE_SIZE - (zhdr->last_chunks  << CHUNK_SHIFT);
+		break;
+	case FULL:
+	default:
+		break;
+	}
 	return handle;
 }
 
@@ -360,6 +366,24 @@ int zbud_alloc(struct zbud_pool *pool, size_t size, gfp_t gfp,
 
 	if (!size || (gfp & __GFP_HIGHMEM))
 		return -EINVAL;
+
+	if (size == PAGE_SIZE) {
+		/*
+		 * This is a special case. The page will be allocated
+		 * and used to store uncompressed data
+		 */
+		page = alloc_page(gfp);
+		if (!page)
+			return -ENOMEM;
+		spin_lock(&pool->lock);
+		pool->pages_nr++;
+		INIT_LIST_HEAD(&page->lru);
+		page->flags |= PG_uncompressed;
+		list_add(&page->lru, &pool->lru);
+		spin_unlock(&pool->lock);
+		*handle = encode_handle(page_address(page), FULL);
+		return 0;
+	}
 	if (size > PAGE_SIZE - ZHDR_SIZE_ALIGNED - CHUNK_SIZE)
 		return -ENOSPC;
 	chunks = size_to_chunks(size);
@@ -372,6 +396,7 @@ int zbud_alloc(struct zbud_pool *pool, size_t size, gfp_t gfp,
 			zhdr = list_first_entry(&pool->unbuddied[i],
 					struct zbud_header, buddy);
 			list_del(&zhdr->buddy);
+			page = virt_to_page(zhdr);
 			if (zhdr->first_chunks == 0)
 				bud = FIRST;
 			else
@@ -406,9 +431,9 @@ found:
 	}
 
 	/* Add/move zbud page to beginning of LRU */
-	if (!list_empty(&zhdr->lru))
-		list_del(&zhdr->lru);
-	list_add(&zhdr->lru, &pool->lru);
+	if (!list_empty(&page->lru))
+		list_del(&page->lru);
+	list_add(&page->lru, &pool->lru);
 
 	*handle = encode_handle(zhdr, bud);
 	spin_unlock(&pool->lock);
@@ -430,9 +455,21 @@ void zbud_free(struct zbud_pool *pool, unsigned long handle)
 {
 	struct zbud_header *zhdr;
 	int freechunks;
+	struct page *page;
 
 	spin_lock(&pool->lock);
 	zhdr = handle_to_zbud_header(handle);
+	page = virt_to_page(zhdr);
+
+	/* If it was an uncompressed full page, just free it */
+	if (page->flags & PG_uncompressed) {
+		page->flags &= ~PG_uncompressed;
+		list_del(&page->lru);
+		__free_page(page);
+		pool->pages_nr--;
+		spin_unlock(&pool->lock);
+		return;
+	}
 
 	/* If first buddy, handle will be page aligned */
 	if ((handle - ZHDR_SIZE_ALIGNED) & ~PAGE_MASK)
@@ -451,7 +488,7 @@ void zbud_free(struct zbud_pool *pool, unsigned long handle)
 
 	if (zhdr->first_chunks == 0 && zhdr->last_chunks == 0) {
 		/* zbud page is empty, free */
-		list_del(&zhdr->lru);
+		list_del(&page->lru);
 		free_zbud_page(zhdr);
 		pool->pages_nr--;
 	} else {
@@ -505,6 +542,7 @@ int zbud_reclaim_page(struct zbud_pool *pool, unsigned int retries)
 {
 	int i, ret, freechunks;
 	struct zbud_header *zhdr;
+	struct page *page;
 	unsigned long first_handle = 0, last_handle = 0;
 
 	spin_lock(&pool->lock);
@@ -514,8 +552,17 @@ int zbud_reclaim_page(struct zbud_pool *pool, unsigned int retries)
 		return -EINVAL;
 	}
 	for (i = 0; i < retries; i++) {
-		zhdr = list_tail_entry(&pool->lru, struct zbud_header, lru);
-		list_del(&zhdr->lru);
+		page = list_tail_entry(&pool->lru, struct page, lru);
+		zhdr = page_address(page);
+		list_del(&page->lru);
+		/* Uncompressed zbud page? just run eviction and free it */
+		if (page->flags & PG_uncompressed) {
+			page->flags &= ~PG_uncompressed;
+			spin_unlock(&pool->lock);
+			pool->ops->evict(pool, encode_handle(zhdr, FULL));
+			__free_page(page);
+			return 0;
+		}
 		list_del(&zhdr->buddy);
 		/* Protect zbud page against free */
 		zhdr->under_reclaim = true;
@@ -565,7 +612,7 @@ next:
 		}
 
 		/* add to beginning of LRU */
-		list_add(&zhdr->lru, &pool->lru);
+		list_add(&page->lru, &pool->lru);
 	}
 	spin_unlock(&pool->lock);
 	return -EAGAIN;
-- 
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1227008 — Re: [PATCH 1/2] zbud: allow PAGE_SIZE allocations

FromVlastimil Babka <vbabka@suse.cz>
Date2015-09-17 15:10 +0200
SubjectRe: [PATCH 1/2] zbud: allow PAGE_SIZE allocations
Message-ID<q9H6P-4rU-33@gated-at.bofh.it>
In reply to#1226033
On 09/16/2015 01:50 PM, Vitaly Wool wrote:
> For zram to be able to use zbud via the common zpool API,
> allocations of size PAGE_SIZE should be allowed by zpool.
> zbud uses the beginning of an allocated page for its internal
> structure but it is not a problem as long as we keep track of
> such special pages using a newly introduced page flag.
> To be able to keep track of zbud pages in any case, struct page's
> lru pointer will be used for zbud page lists instead of the one
> that used to be part of the aforementioned internal structure.

I don't know how zsmalloc handles uncompressible PAGE_SIZE allocations, 
but I wouldn't expect it to be any more clever than this? So why 
duplicate the functionality in zswap and zbud? This could be handled 
e.g. at the zpool level? Or maybe just in zram, as IIRC in zswap 
(frontswap) it's valid just to reject a page and it goes to physical swap.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1227637 — Re: [PATCH 1/2] zbud: allow PAGE_SIZE allocations

FromVitaly Wool <vitalywool@gmail.com>
Date2015-09-18 10:10 +0200
SubjectRe: [PATCH 1/2] zbud: allow PAGE_SIZE allocations
Message-ID<q9YU2-5cX-7@gated-at.bofh.it>
In reply to#1227008
> I don't know how zsmalloc handles uncompressible PAGE_SIZE allocations, but
> I wouldn't expect it to be any more clever than this? So why duplicate the
> functionality in zswap and zbud? This could be handled e.g. at the zpool
> level? Or maybe just in zram, as IIRC in zswap (frontswap) it's valid just
> to reject a page and it goes to physical swap.

From what I can see, zsmalloc just allocates pages and puts them into
a linked list. Using the beginning of a page for storing an internal
struct is zbud-specific, and so is this patch.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1229479 — Re: [PATCH 1/2] zbud: allow PAGE_SIZE allocations

FromDan Streetman <ddstreet@ieee.org>
Date2015-09-21 17:30 +0200
SubjectRe: [PATCH 1/2] zbud: allow PAGE_SIZE allocations
Message-ID<qbbcu-2a3-19@gated-at.bofh.it>
In reply to#1227637
On Fri, Sep 18, 2015 at 4:03 AM, Vitaly Wool <vitalywool@gmail.com> wrote:
>> I don't know how zsmalloc handles uncompressible PAGE_SIZE allocations, but
>> I wouldn't expect it to be any more clever than this? So why duplicate the
>> functionality in zswap and zbud? This could be handled e.g. at the zpool
>> level? Or maybe just in zram, as IIRC in zswap (frontswap) it's valid just
>> to reject a page and it goes to physical swap.

zpool doesn't actually store pages anywhere; zbud and zsmalloc do the
storing, and they do it in completely different ways.  Storing an
uncompressed page has to be done in zbud and zsmalloc, not zpool.  And
zram can't do it either; zram doesn't actually store pages either, it
relies on zsmalloc to store all its pages.

>
> From what I can see, zsmalloc just allocates pages and puts them into
> a linked list. Using the beginning of a page for storing an internal
> struct is zbud-specific, and so is this patch.

zsmalloc has size "classes" that allow storing "objects" of a specific
size range (i.e. the last class size + 1, up to class size).  the max
size class is:
#define ZS_MAX_ALLOC_SIZE PAGE_SIZE

so zsmalloc is able to store "objects" up to, and including, PAGE_SIZE.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1229527 — Re: [PATCH 1/2] zbud: allow PAGE_SIZE allocations

FromDan Streetman <ddstreet@ieee.org>
Date2015-09-21 18:20 +0200
SubjectRe: [PATCH 1/2] zbud: allow PAGE_SIZE allocations
Message-ID<qbbYS-3k6-17@gated-at.bofh.it>
In reply to#1226033
Please make sure to cc Seth also, he's the owner of zbud.

On Wed, Sep 16, 2015 at 7:50 AM, Vitaly Wool <vitalywool@gmail.com> wrote:
> For zram to be able to use zbud via the common zpool API,
> allocations of size PAGE_SIZE should be allowed by zpool.
> zbud uses the beginning of an allocated page for its internal
> structure but it is not a problem as long as we keep track of
> such special pages using a newly introduced page flag.
> To be able to keep track of zbud pages in any case, struct page's
> lru pointer will be used for zbud page lists instead of the one
> that used to be part of the aforementioned internal structure.
>
> Signed-off-by: Vitaly Wool <vitalywool@gmail.com>
> ---
>  include/linux/page-flags.h |  3 ++
>  mm/zbud.c                  | 71 ++++++++++++++++++++++++++++++++++++++--------
>  2 files changed, 62 insertions(+), 12 deletions(-)
>
> diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
> index 416509e..dd47cf0 100644
> --- a/include/linux/page-flags.h
> +++ b/include/linux/page-flags.h
> @@ -134,6 +134,9 @@ enum pageflags {
>
>         /* SLOB */
>         PG_slob_free = PG_private,
> +
> +       /* ZBUD */
> +       PG_uncompressed = PG_owner_priv_1,

you don't need a new page flag.  and there's 0% chance it would be
accepted even if you did.

>  };
>
>  #ifndef __GENERATING_BOUNDS_H
> diff --git a/mm/zbud.c b/mm/zbud.c
> index fa48bcdf..ee8b5d6 100644
> --- a/mm/zbud.c
> +++ b/mm/zbud.c
> @@ -107,13 +107,11 @@ struct zbud_pool {
>   * struct zbud_header - zbud page metadata occupying the first chunk of each
>   *                     zbud page.
>   * @buddy:     links the zbud page into the unbuddied/buddied lists in the pool
> - * @lru:       links the zbud page into the lru list in the pool
>   * @first_chunks:      the size of the first buddy in chunks, 0 if free
>   * @last_chunks:       the size of the last buddy in chunks, 0 if free
>   */
>  struct zbud_header {
>         struct list_head buddy;
> -       struct list_head lru;
>         unsigned int first_chunks;
>         unsigned int last_chunks;
>         bool under_reclaim;
> @@ -221,6 +219,7 @@ MODULE_ALIAS("zpool-zbud");
>  *****************/
>  /* Just to make the code easier to read */
>  enum buddy {
> +       FULL,
>         FIRST,
>         LAST
>  };
> @@ -241,7 +240,7 @@ static struct zbud_header *init_zbud_page(struct page *page)
>         zhdr->first_chunks = 0;
>         zhdr->last_chunks = 0;
>         INIT_LIST_HEAD(&zhdr->buddy);
> -       INIT_LIST_HEAD(&zhdr->lru);
> +       INIT_LIST_HEAD(&page->lru);
>         zhdr->under_reclaim = 0;
>         return zhdr;
>  }
> @@ -267,11 +266,18 @@ static unsigned long encode_handle(struct zbud_header *zhdr, enum buddy bud)
>          * over the zbud header in the first chunk.
>          */
>         handle = (unsigned long)zhdr;
> -       if (bud == FIRST)
> +       switch (bud) {
> +       case FIRST:
>                 /* skip over zbud header */
>                 handle += ZHDR_SIZE_ALIGNED;
> -       else /* bud == LAST */
> +               break;
> +       case LAST:
>                 handle += PAGE_SIZE - (zhdr->last_chunks  << CHUNK_SHIFT);
> +               break;
> +       case FULL:
> +       default:

Hmm, while it should be ok to treat a default (invalid) bud value as a
full page (assuming the caller treats it as such), you should at least
add a pr_warn() or pr_warn_ratelimited(), or maybe a WARN_ON() or
WARN_ON_ONCE().  the default case should never happen, and a warning
should be printed if it does.

> +               break;
> +       }
>         return handle;
>  }
>
> @@ -360,6 +366,24 @@ int zbud_alloc(struct zbud_pool *pool, size_t size, gfp_t gfp,
>
>         if (!size || (gfp & __GFP_HIGHMEM))
>                 return -EINVAL;
> +
> +       if (size == PAGE_SIZE) {
> +               /*
> +                * This is a special case. The page will be allocated
> +                * and used to store uncompressed data
> +                */

well you shouldn't special case only PAGE_SIZE.  If zram increases its
max_zpage_size to a value > (PAGE_SIZE - ZHDR_SIZE_ALIGNED -
CHUNK_SIZE) then those compressed pages will fail to store here.

I think it would be better to change the size check to a simple
if (size > PAGE_SIZE)
  return -ENOSPC;

then use the existing
>         if (size > PAGE_SIZE - ZHDR_SIZE_ALIGNED - CHUNK_SIZE)

to store the object (which is either a large compressed page, or an
uncompressed page) into the full zbud page.  And don't duplicate
everything the function does inside an if (), just update the function
to handle PAGE_SIZE storage.

> +               page = alloc_page(gfp);
> +               if (!page)
> +                       return -ENOMEM;
> +               spin_lock(&pool->lock);
> +               pool->pages_nr++;
> +               INIT_LIST_HEAD(&page->lru);
> +               page->flags |= PG_uncompressed;
> +               list_add(&page->lru, &pool->lru);
> +               spin_unlock(&pool->lock);
> +               *handle = encode_handle(page_address(page), FULL);
> +               return 0;
> +       }
>         if (size > PAGE_SIZE - ZHDR_SIZE_ALIGNED - CHUNK_SIZE)
>                 return -ENOSPC;
>         chunks = size_to_chunks(size);
> @@ -372,6 +396,7 @@ int zbud_alloc(struct zbud_pool *pool, size_t size, gfp_t gfp,
>                         zhdr = list_first_entry(&pool->unbuddied[i],
>                                         struct zbud_header, buddy);
>                         list_del(&zhdr->buddy);
> +                       page = virt_to_page(zhdr);
>                         if (zhdr->first_chunks == 0)
>                                 bud = FIRST;
>                         else
> @@ -406,9 +431,9 @@ found:
>         }
>
>         /* Add/move zbud page to beginning of LRU */
> -       if (!list_empty(&zhdr->lru))
> -               list_del(&zhdr->lru);
> -       list_add(&zhdr->lru, &pool->lru);
> +       if (!list_empty(&page->lru))
> +               list_del(&page->lru);
> +       list_add(&page->lru, &pool->lru);
>
>         *handle = encode_handle(zhdr, bud);
>         spin_unlock(&pool->lock);
> @@ -430,9 +455,21 @@ void zbud_free(struct zbud_pool *pool, unsigned long handle)
>  {
>         struct zbud_header *zhdr;
>         int freechunks;
> +       struct page *page;
>
>         spin_lock(&pool->lock);
>         zhdr = handle_to_zbud_header(handle);
> +       page = virt_to_page(zhdr);
> +
> +       /* If it was an uncompressed full page, just free it */
> +       if (page->flags & PG_uncompressed) {
> +               page->flags &= ~PG_uncompressed;
> +               list_del(&page->lru);
> +               __free_page(page);
> +               pool->pages_nr--;
> +               spin_unlock(&pool->lock);
> +               return;
> +       }

don't repeat this function inside an if() block.  update the actual
function to handle the new case.

and you don't need a new page flag.  you have 3 distinct cases:

switch (handle & ~PAGE_MASK) {
case 0: /* this is a full-sized page */
case ZHDR_SIZE_ALIGNED: /* this is the first buddy */
default: /* this is the last buddy */
}


>
>         /* If first buddy, handle will be page aligned */
>         if ((handle - ZHDR_SIZE_ALIGNED) & ~PAGE_MASK)
> @@ -451,7 +488,7 @@ void zbud_free(struct zbud_pool *pool, unsigned long handle)
>
>         if (zhdr->first_chunks == 0 && zhdr->last_chunks == 0) {
>                 /* zbud page is empty, free */
> -               list_del(&zhdr->lru);
> +               list_del(&page->lru);
>                 free_zbud_page(zhdr);
>                 pool->pages_nr--;
>         } else {
> @@ -505,6 +542,7 @@ int zbud_reclaim_page(struct zbud_pool *pool, unsigned int retries)
>  {
>         int i, ret, freechunks;
>         struct zbud_header *zhdr;
> +       struct page *page;
>         unsigned long first_handle = 0, last_handle = 0;
>
>         spin_lock(&pool->lock);
> @@ -514,8 +552,17 @@ int zbud_reclaim_page(struct zbud_pool *pool, unsigned int retries)
>                 return -EINVAL;
>         }
>         for (i = 0; i < retries; i++) {
> -               zhdr = list_tail_entry(&pool->lru, struct zbud_header, lru);
> -               list_del(&zhdr->lru);
> +               page = list_tail_entry(&pool->lru, struct page, lru);
> +               zhdr = page_address(page);
> +               list_del(&page->lru);
> +               /* Uncompressed zbud page? just run eviction and free it */
> +               if (page->flags & PG_uncompressed) {
> +                       page->flags &= ~PG_uncompressed;
> +                       spin_unlock(&pool->lock);
> +                       pool->ops->evict(pool, encode_handle(zhdr, FULL));
> +                       __free_page(page);
> +                       return 0;

again, don't be redundant.  change the function to handle full-sized
pages, don't repeat the function in an if() block for a special case.

> +               }
>                 list_del(&zhdr->buddy);
>                 /* Protect zbud page against free */
>                 zhdr->under_reclaim = true;
> @@ -565,7 +612,7 @@ next:
>                 }
>
>                 /* add to beginning of LRU */
> -               list_add(&zhdr->lru, &pool->lru);
> +               list_add(&page->lru, &pool->lru);
>         }
>         spin_unlock(&pool->lock);
>         return -EAGAIN;
> --
> 1.9.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1226035 — [PATCH 2/2] zpool/zsmalloc/zbud: align on interfaces

FromVitaly Wool <vitalywool@gmail.com>
Date2015-09-16 14:00 +0200
Subject[PATCH 2/2] zpool/zsmalloc/zbud: align on interfaces
Message-ID<q9jxw-3z3-13@gated-at.bofh.it>
In reply to#1226032
As a preparation step for zram to be able to use common zpool API,
there has to be some alignment done on it. This patch adds
functions that correspond to zsmalloc-specific API to the common
zpool API and takes care of the callbacks that have to be
introduced, too.

This version of the patch uses simplified 'compact' API/callbacks.

Signed-off-by: Vitaly Wool <vitalywool@gmail.com>
---
 drivers/block/zram/zram_drv.c |  4 ++--
 include/linux/zpool.h         | 14 ++++++++++++++
 include/linux/zsmalloc.h      |  8 ++------
 mm/zbud.c                     | 12 ++++++++++++
 mm/zpool.c                    | 21 +++++++++++++++++++++
 mm/zsmalloc.c                 | 19 ++++++++++++++++---
 6 files changed, 67 insertions(+), 11 deletions(-)

diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index 9fa15bb..a0a786e 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -426,12 +426,12 @@ static ssize_t mm_stat_show(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
 	struct zram *zram = dev_to_zram(dev);
-	struct zs_pool_stats pool_stats;
+	struct zpool_stats pool_stats;
 	u64 orig_size, mem_used = 0;
 	long max_used;
 	ssize_t ret;
 
-	memset(&pool_stats, 0x00, sizeof(struct zs_pool_stats));
+	memset(&pool_stats, 0x00, sizeof(struct zpool_stats));
 
 	down_read(&zram->init_lock);
 	if (init_done(zram)) {
diff --git a/include/linux/zpool.h b/include/linux/zpool.h
index 42f8ec9..a2a5bc4 100644
--- a/include/linux/zpool.h
+++ b/include/linux/zpool.h
@@ -17,6 +17,11 @@ struct zpool_ops {
 	int (*evict)(struct zpool *pool, unsigned long handle);
 };
 
+struct zpool_stats {
+	/* How many pages were migrated (freed) */
+	unsigned long pages_compacted;
+};
+
 /*
  * Control how a handle is mapped.  It will be ignored if the
  * implementation does not support it.  Its use is optional.
@@ -58,6 +63,10 @@ void *zpool_map_handle(struct zpool *pool, unsigned long handle,
 
 void zpool_unmap_handle(struct zpool *pool, unsigned long handle);
 
+unsigned long zpool_compact(struct zpool *pool);
+
+void zpool_stats(struct zpool *pool, struct zpool_stats *zstats);
+
 u64 zpool_get_total_size(struct zpool *pool);
 
 
@@ -72,6 +81,8 @@ u64 zpool_get_total_size(struct zpool *pool);
  * @shrink:	shrink the pool.
  * @map:	map a handle.
  * @unmap:	unmap a handle.
+ * @compact:	try to run compaction for the pool
+ * @stats:	get statistics for the pool
  * @total_size:	get total size of a pool.
  *
  * This is created by a zpool implementation and registered
@@ -98,6 +109,9 @@ struct zpool_driver {
 				enum zpool_mapmode mm);
 	void (*unmap)(void *pool, unsigned long handle);
 
+	unsigned long (*compact)(void *pool);
+	void (*stats)(void *pool, struct zpool_stats *stats);
+
 	u64 (*total_size)(void *pool);
 };
 
diff --git a/include/linux/zsmalloc.h b/include/linux/zsmalloc.h
index 6398dfa..5aee1c7 100644
--- a/include/linux/zsmalloc.h
+++ b/include/linux/zsmalloc.h
@@ -15,6 +15,7 @@
 #define _ZS_MALLOC_H_
 
 #include <linux/types.h>
+#include <linux/zpool.h>
 
 /*
  * zsmalloc mapping modes
@@ -34,11 +35,6 @@ enum zs_mapmode {
 	 */
 };
 
-struct zs_pool_stats {
-	/* How many pages were migrated (freed) */
-	unsigned long pages_compacted;
-};
-
 struct zs_pool;
 
 struct zs_pool *zs_create_pool(char *name, gfp_t flags);
@@ -54,5 +50,5 @@ void zs_unmap_object(struct zs_pool *pool, unsigned long handle);
 unsigned long zs_get_total_pages(struct zs_pool *pool);
 unsigned long zs_compact(struct zs_pool *pool);
 
-void zs_pool_stats(struct zs_pool *pool, struct zs_pool_stats *stats);
+void zs_pool_stats(struct zs_pool *pool, struct zpool_stats *stats);
 #endif
diff --git a/mm/zbud.c b/mm/zbud.c
index ee8b5d6..23cfc76 100644
--- a/mm/zbud.c
+++ b/mm/zbud.c
@@ -193,6 +193,16 @@ static void zbud_zpool_unmap(void *pool, unsigned long handle)
 	zbud_unmap(pool, handle);
 }
 
+static unsigned long zbud_zpool_compact(void *pool)
+{
+	return 0;
+}
+
+static void zbud_zpool_stats(void *pool, struct zpool_stats *stats)
+{
+	/* no-op */
+}
+
 static u64 zbud_zpool_total_size(void *pool)
 {
 	return zbud_get_pool_size(pool) * PAGE_SIZE;
@@ -208,6 +218,8 @@ static struct zpool_driver zbud_zpool_driver = {
 	.shrink =	zbud_zpool_shrink,
 	.map =		zbud_zpool_map,
 	.unmap =	zbud_zpool_unmap,
+	.compact =	zbud_zpool_compact,
+	.stats =	zbud_zpool_stats,
 	.total_size =	zbud_zpool_total_size,
 };
 
diff --git a/mm/zpool.c b/mm/zpool.c
index 8f670d3..d454f37 100644
--- a/mm/zpool.c
+++ b/mm/zpool.c
@@ -341,6 +341,27 @@ void zpool_unmap_handle(struct zpool *zpool, unsigned long handle)
 }
 
 /**
+ * zpool_compact() - try to run compaction over zpool
+ * @pool	The zpool to compact
+ *
+ * Returns: the number of migrated pages (0 if nothing happened)
+ */
+unsigned long zpool_compact(struct zpool *zpool)
+{
+	return zpool->driver->compact(zpool->pool);
+}
+
+/**
+ * zpool_stats() - obtain zpool statistics
+ * @pool	The zpool to get statistics for
+ * @zstats	stats to fill in
+ */
+void zpool_stats(struct zpool *zpool, struct zpool_stats *zstats)
+{
+	zpool->driver->stats(zpool->pool, zstats);
+}
+
+/**
  * zpool_get_total_size() - The total size of the pool
  * @pool	The zpool to check
  *
diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c
index f135b1b..3ab0515 100644
--- a/mm/zsmalloc.c
+++ b/mm/zsmalloc.c
@@ -245,7 +245,7 @@ struct zs_pool {
 	gfp_t flags;	/* allocation flags used when growing pool */
 	atomic_long_t pages_allocated;
 
-	struct zs_pool_stats stats;
+	struct zpool_stats stats;
 
 	/* Compact classes */
 	struct shrinker shrinker;
@@ -365,6 +365,17 @@ static void zs_zpool_unmap(void *pool, unsigned long handle)
 	zs_unmap_object(pool, handle);
 }
 
+static unsigned long zs_zpool_compact(void *pool)
+{
+	return zs_compact(pool);
+}
+
+
+static void zs_zpool_stats(void *pool, struct zpool_stats *stats)
+{
+	zs_pool_stats(pool, stats);
+}
+
 static u64 zs_zpool_total_size(void *pool)
 {
 	return zs_get_total_pages(pool) << PAGE_SHIFT;
@@ -380,6 +391,8 @@ static struct zpool_driver zs_zpool_driver = {
 	.shrink =	zs_zpool_shrink,
 	.map =		zs_zpool_map,
 	.unmap =	zs_zpool_unmap,
+	.compact =	zs_zpool_compact,
+	.stats =	zs_zpool_stats,
 	.total_size =	zs_zpool_total_size,
 };
 
@@ -1789,9 +1802,9 @@ unsigned long zs_compact(struct zs_pool *pool)
 }
 EXPORT_SYMBOL_GPL(zs_compact);
 
-void zs_pool_stats(struct zs_pool *pool, struct zs_pool_stats *stats)
+void zs_pool_stats(struct zs_pool *pool, struct zpool_stats *stats)
 {
-	memcpy(stats, &pool->stats, sizeof(struct zs_pool_stats));
+	memcpy(stats, &pool->stats, sizeof(struct zpool_stats));
 }
 EXPORT_SYMBOL_GPL(zs_pool_stats);
 
-- 
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1229585 — Re: [PATCH 2/2] zpool/zsmalloc/zbud: align on interfaces

FromDan Streetman <ddstreet@ieee.org>
Date2015-09-21 19:20 +0200
SubjectRe: [PATCH 2/2] zpool/zsmalloc/zbud: align on interfaces
Message-ID<qbcUW-4Fd-25@gated-at.bofh.it>
In reply to#1226035
On Wed, Sep 16, 2015 at 7:53 AM, Vitaly Wool <vitalywool@gmail.com> wrote:
> As a preparation step for zram to be able to use common zpool API,
> there has to be some alignment done on it. This patch adds
> functions that correspond to zsmalloc-specific API to the common
> zpool API and takes care of the callbacks that have to be
> introduced, too.
>
> This version of the patch uses simplified 'compact' API/callbacks.
>
> Signed-off-by: Vitaly Wool <vitalywool@gmail.com>
> ---
>  drivers/block/zram/zram_drv.c |  4 ++--
>  include/linux/zpool.h         | 14 ++++++++++++++
>  include/linux/zsmalloc.h      |  8 ++------
>  mm/zbud.c                     | 12 ++++++++++++
>  mm/zpool.c                    | 21 +++++++++++++++++++++
>  mm/zsmalloc.c                 | 19 ++++++++++++++++---
>  6 files changed, 67 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
> index 9fa15bb..a0a786e 100644
> --- a/drivers/block/zram/zram_drv.c
> +++ b/drivers/block/zram/zram_drv.c
> @@ -426,12 +426,12 @@ static ssize_t mm_stat_show(struct device *dev,
>                 struct device_attribute *attr, char *buf)
>  {
>         struct zram *zram = dev_to_zram(dev);
> -       struct zs_pool_stats pool_stats;
> +       struct zpool_stats pool_stats;
>         u64 orig_size, mem_used = 0;
>         long max_used;
>         ssize_t ret;
>
> -       memset(&pool_stats, 0x00, sizeof(struct zs_pool_stats));
> +       memset(&pool_stats, 0x00, sizeof(struct zpool_stats));
>
>         down_read(&zram->init_lock);
>         if (init_done(zram)) {

you don't need to change zram in this patch.  save this part for the
patch to update zram to use zpool.


> diff --git a/include/linux/zpool.h b/include/linux/zpool.h
> index 42f8ec9..a2a5bc4 100644
> --- a/include/linux/zpool.h
> +++ b/include/linux/zpool.h
> @@ -17,6 +17,11 @@ struct zpool_ops {
>         int (*evict)(struct zpool *pool, unsigned long handle);
>  };
>
> +struct zpool_stats {
> +       /* How many pages were migrated (freed) */
> +       unsigned long pages_compacted;
> +};
> +
>  /*
>   * Control how a handle is mapped.  It will be ignored if the
>   * implementation does not support it.  Its use is optional.
> @@ -58,6 +63,10 @@ void *zpool_map_handle(struct zpool *pool, unsigned long handle,
>
>  void zpool_unmap_handle(struct zpool *pool, unsigned long handle);
>
> +unsigned long zpool_compact(struct zpool *pool);
> +
> +void zpool_stats(struct zpool *pool, struct zpool_stats *zstats);
> +
>  u64 zpool_get_total_size(struct zpool *pool);
>
>
> @@ -72,6 +81,8 @@ u64 zpool_get_total_size(struct zpool *pool);
>   * @shrink:    shrink the pool.
>   * @map:       map a handle.
>   * @unmap:     unmap a handle.
> + * @compact:   try to run compaction for the pool
> + * @stats:     get statistics for the pool
>   * @total_size:        get total size of a pool.
>   *
>   * This is created by a zpool implementation and registered
> @@ -98,6 +109,9 @@ struct zpool_driver {
>                                 enum zpool_mapmode mm);
>         void (*unmap)(void *pool, unsigned long handle);
>
> +       unsigned long (*compact)(void *pool);
> +       void (*stats)(void *pool, struct zpool_stats *stats);
> +
>         u64 (*total_size)(void *pool);
>  };
>
> diff --git a/include/linux/zsmalloc.h b/include/linux/zsmalloc.h
> index 6398dfa..5aee1c7 100644
> --- a/include/linux/zsmalloc.h
> +++ b/include/linux/zsmalloc.h
> @@ -15,6 +15,7 @@
>  #define _ZS_MALLOC_H_
>
>  #include <linux/types.h>
> +#include <linux/zpool.h>
>
>  /*
>   * zsmalloc mapping modes
> @@ -34,11 +35,6 @@ enum zs_mapmode {
>          */
>  };
>
> -struct zs_pool_stats {
> -       /* How many pages were migrated (freed) */
> -       unsigned long pages_compacted;
> -};
> -
>  struct zs_pool;
>
>  struct zs_pool *zs_create_pool(char *name, gfp_t flags);
> @@ -54,5 +50,5 @@ void zs_unmap_object(struct zs_pool *pool, unsigned long handle);
>  unsigned long zs_get_total_pages(struct zs_pool *pool);
>  unsigned long zs_compact(struct zs_pool *pool);
>
> -void zs_pool_stats(struct zs_pool *pool, struct zs_pool_stats *stats);
> +void zs_pool_stats(struct zs_pool *pool, struct zpool_stats *stats);
>  #endif
> diff --git a/mm/zbud.c b/mm/zbud.c
> index ee8b5d6..23cfc76 100644
> --- a/mm/zbud.c
> +++ b/mm/zbud.c
> @@ -193,6 +193,16 @@ static void zbud_zpool_unmap(void *pool, unsigned long handle)
>         zbud_unmap(pool, handle);
>  }
>
> +static unsigned long zbud_zpool_compact(void *pool)
> +{
> +       return 0;
> +}
> +
> +static void zbud_zpool_stats(void *pool, struct zpool_stats *stats)
> +{
> +       /* no-op */
> +}
> +
>  static u64 zbud_zpool_total_size(void *pool)
>  {
>         return zbud_get_pool_size(pool) * PAGE_SIZE;
> @@ -208,6 +218,8 @@ static struct zpool_driver zbud_zpool_driver = {
>         .shrink =       zbud_zpool_shrink,
>         .map =          zbud_zpool_map,
>         .unmap =        zbud_zpool_unmap,
> +       .compact =      zbud_zpool_compact,
> +       .stats =        zbud_zpool_stats,
>         .total_size =   zbud_zpool_total_size,
>  };
>
> diff --git a/mm/zpool.c b/mm/zpool.c
> index 8f670d3..d454f37 100644
> --- a/mm/zpool.c
> +++ b/mm/zpool.c
> @@ -341,6 +341,27 @@ void zpool_unmap_handle(struct zpool *zpool, unsigned long handle)
>  }
>
>  /**
> + * zpool_compact() - try to run compaction over zpool
> + * @pool       The zpool to compact
> + *
> + * Returns: the number of migrated pages (0 if nothing happened)

don't say "nothing happened", 0 doesn't necessarily mean that.  0
means no pages were compacted.

> + */
> +unsigned long zpool_compact(struct zpool *zpool)
> +{
> +       return zpool->driver->compact(zpool->pool);
> +}
> +
> +/**
> + * zpool_stats() - obtain zpool statistics
> + * @pool       The zpool to get statistics for
> + * @zstats     stats to fill in

this doc needs more.  how is this function used?  what should the
caller expect in the zstats fields before and after the call?

for the common zpool interface, it might make more sense to just
include a direct function to access the pages_compacted, instead of
the indirect stats call.  If more stats get added in the future, the
call can be changed into a zpool_stats function.

> + */
> +void zpool_stats(struct zpool *zpool, struct zpool_stats *zstats)
> +{
> +       zpool->driver->stats(zpool->pool, zstats);
> +}
> +
> +/**
>   * zpool_get_total_size() - The total size of the pool
>   * @pool       The zpool to check
>   *
> diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c
> index f135b1b..3ab0515 100644
> --- a/mm/zsmalloc.c
> +++ b/mm/zsmalloc.c
> @@ -245,7 +245,7 @@ struct zs_pool {
>         gfp_t flags;    /* allocation flags used when growing pool */
>         atomic_long_t pages_allocated;
>
> -       struct zs_pool_stats stats;
> +       struct zpool_stats stats;

we haven't made zsmalloc completely dependent on zpool just yet :-)
this won't compile when CONFIG_ZPOOL isn't set.

leave this as a zs_pool_stats type and just handle the translation in
the zs_zpool_stats function call.

>
>         /* Compact classes */
>         struct shrinker shrinker;
> @@ -365,6 +365,17 @@ static void zs_zpool_unmap(void *pool, unsigned long handle)
>         zs_unmap_object(pool, handle);
>  }
>
> +static unsigned long zs_zpool_compact(void *pool)
> +{
> +       return zs_compact(pool);
> +}
> +
> +
> +static void zs_zpool_stats(void *pool, struct zpool_stats *stats)
> +{
> +       zs_pool_stats(pool, stats);
> +}
> +
>  static u64 zs_zpool_total_size(void *pool)
>  {
>         return zs_get_total_pages(pool) << PAGE_SHIFT;
> @@ -380,6 +391,8 @@ static struct zpool_driver zs_zpool_driver = {
>         .shrink =       zs_zpool_shrink,
>         .map =          zs_zpool_map,
>         .unmap =        zs_zpool_unmap,
> +       .compact =      zs_zpool_compact,
> +       .stats =        zs_zpool_stats,
>         .total_size =   zs_zpool_total_size,
>  };
>
> @@ -1789,9 +1802,9 @@ unsigned long zs_compact(struct zs_pool *pool)
>  }
>  EXPORT_SYMBOL_GPL(zs_compact);
>
> -void zs_pool_stats(struct zs_pool *pool, struct zs_pool_stats *stats)
> +void zs_pool_stats(struct zs_pool *pool, struct zpool_stats *stats)
>  {
> -       memcpy(stats, &pool->stats, sizeof(struct zs_pool_stats));
> +       memcpy(stats, &pool->stats, sizeof(struct zpool_stats));
>  }
>  EXPORT_SYMBOL_GPL(zs_pool_stats);
>
> --
> 1.9.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1226614 — Re: [PATCH 0/2] prepare zbud to be used by zram as underlying allocator

FromSergey Senozhatsky <sergey.senozhatsky.work@gmail.com>
Date2015-09-17 03:30 +0200
SubjectRe: [PATCH 0/2] prepare zbud to be used by zram as underlying allocator
Message-ID<q9wbo-505-1@gated-at.bofh.it>
In reply to#1226032
On (09/16/15 13:48), Vitaly Wool wrote:
> as a follow-up to my previous patchset, I decided to first prepare
> zbud/zpool related patches and then have some testing rounds and
> performance measurements for zram running over both, and come up
> with improved/verified zram/zpool patches then.

Hi,

just a side note,
I'm afraid this is not how it works. numbers go first, to justify
the patch set.

	-ss

>
> So for now, here comes the zbud/zpool part.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1226890

FromVitaly Wool <vitalywool@gmail.com>
Date2015-09-17 12:30 +0200
Message-ID<q9EBY-Ih-37@gated-at.bofh.it>
In reply to#1226614
On Thu, Sep 17, 2015 at 1:30 AM, Sergey Senozhatsky
<sergey.senozhatsky.work@gmail.com> wrote:

>
> just a side note,
> I'm afraid this is not how it works. numbers go first, to justify
> the patch set.
>

These patches are extension/alignment patches, why would anyone need
to justify that?

But just to help you understand where I am coming from, here are some numbers:
                               zsmalloc   zbud
kswapd_low_wmark_hit_quickly   4513       5696
kswapd_high_wmark_hit_quickly  861        902
allocstall                     2236       1122
pgmigrate_success              78229      31244
compact_stall                  1172       634
compact_fail                   194        95
compact_success                464        210

These are results from an Android device having run 3 'monkey' tests
each 20 minutes, with user switch to guest and back in between.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1229011 — Re: [PATCH 0/2] prepare zbud to be used by zram as underlying allocator

FromMinchan Kim <minchan@kernel.org>
Date2015-09-21 06:20 +0200
SubjectRe: [PATCH 0/2] prepare zbud to be used by zram as underlying allocator
Message-ID<qb0K5-449-1@gated-at.bofh.it>
In reply to#1226890
Hello Vitaly,

On Thu, Sep 17, 2015 at 12:26:12PM +0200, Vitaly Wool wrote:
> On Thu, Sep 17, 2015 at 1:30 AM, Sergey Senozhatsky
> <sergey.senozhatsky.work@gmail.com> wrote:
> 
> >
> > just a side note,
> > I'm afraid this is not how it works. numbers go first, to justify
> > the patch set.

I totally agree Sergey's opinion.

> >
> 
> These patches are extension/alignment patches, why would anyone need
> to justify that?

Sorry, because you wrote up "zram" in the title.
As I said earlier, we need several numbers to investigate.

First of all, what is culprit of your latency?
It seems you are thinking about compaction. so compaction what?
Frequent scanning? lock collision? or frequent sleeping in compaction
code somewhere? And then why does zbud solve it? If we use zbud for zram,
we lose memory efficiency so there is something to justify it.

The reason I am asking is I have investigated similar problems
in android and other plaforms and the reason of latency was not zsmalloc
but agressive high-order allocations from subsystems, watermark check
race, deferring of compaction, LMK not working and too much swapout so
it causes to reclaim lots of page cache pages which was main culprit
in my cases. When I checks with perf, compaction stall count is increased,
the time spent in there is not huge so it was not main factor of latency.

Your problem might be differnt with me so convincing us, you should
give us real data and investigation story.

Thanks.


> 
> But just to help you understand where I am coming from, here are some numbers:
>                                zsmalloc   zbud
> kswapd_low_wmark_hit_quickly   4513       5696
> kswapd_high_wmark_hit_quickly  861        902
> allocstall                     2236       1122
> pgmigrate_success              78229      31244
> compact_stall                  1172       634
> compact_fail                   194        95
> compact_success                464        210
> 
> These are results from an Android device having run 3 'monkey' tests
> each 20 minutes, with user switch to guest and back in between.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1229745

FromVitaly Wool <vitalywool@gmail.com>
Date2015-09-21 23:20 +0200
Message-ID<qbgFc-1AU-11@gated-at.bofh.it>
In reply to#1229011
Hello Minchan,

> Sorry, because you wrote up "zram" in the title.
> As I said earlier, we need several numbers to investigate.
>
> First of all, what is culprit of your latency?
> It seems you are thinking about compaction. so compaction what?
> Frequent scanning? lock collision? or frequent sleeping in compaction
> code somewhere? And then why does zbud solve it? If we use zbud for zram,
> we lose memory efficiency so there is something to justify it.

The data I've got so far strongly suggests that in some use cases (see
below) with zsmalloc
* there are more allocstalls
* memory compaction is triggered more frequently
* allocstalls happen more often
* page migrations are way more frequent, too.

Please also keep in mind that I do not advise you or anyone to use
zbud instead of zsmalloc. The point I'm trying to make is that zbud
fits my particular case better and I want to be able to choose it in
the kernel without hacking it with my private patches.
FWIW, given that I am not an author of either, I don't see why anyone
would consider me biased. :-)

As of the memory efficiency, you seem to be quite comfortable with
storing uncompressed pages when they compress to more than 3/4 of a
page. I observed ~13% reported ratio increase (3.8x to 4.3x) when I
increased max_zpage_size to PAGE_SIZE / 32 * 31. Doesn't look like a
fight for every byte to me.

> The reason I am asking is I have investigated similar problems
> in android and other plaforms and the reason of latency was not zsmalloc
> but agressive high-order allocations from subsystems, watermark check
> race, deferring of compaction, LMK not working and too much swapout so
> it causes to reclaim lots of page cache pages which was main culprit
> in my cases. When I checks with perf, compaction stall count is increased,
> the time spent in there is not huge so it was not main factor of latency.

The main use case where the difference is seen is switching between
users on an Android device. It does cause a lot of reclaim, too, as
you say, but this is in the nature of zbud that reclaim happens in a
more deterministic way and worst-case looks substantially nicer. That
said, the standard deviation calculated over 20 iterations of a
change-user-multiple-times-test is 2x less for zbud than the one of
zsmalloc.

I'll post some numbers in the next patch respin so they won't get lost :)

~vitaly
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web