2023-08-08 17:59:18

by Vlastimil Babka

[permalink] [raw]
Subject: [RFC v1 5/5] maple_tree: replace preallocation with slub percpu array prefill

With the percpu array we can try not doing the preallocations in maple
tree, and instead make sure the percpu array is prefilled, and using
GFP_ATOMIC in places that relied on the preallocation (in case we miss
or fail trylock on the array), i.e. mas_store_prealloc(). For now simply
add __GFP_NOFAIL there as well.

First I tried to change mas_node_count_gfp() to not preallocate anything
anywhere, but that lead to warns and panics, even though the other
caller mas_node_count() uses GFP_NOWAIT | __GFP_NOWARN so it has no
guarantees... So I changed just mas_preallocate(). I let it still to
truly preallocate a single node, but maybe it's not necessary?
---
lib/maple_tree.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/lib/maple_tree.c b/lib/maple_tree.c
index 7a8e7c467d7c..5a209d88c318 100644
--- a/lib/maple_tree.c
+++ b/lib/maple_tree.c
@@ -5534,7 +5534,12 @@ void mas_store_prealloc(struct ma_state *mas, void *entry)

mas_wr_store_setup(&wr_mas);
trace_ma_write(__func__, mas, 0, entry);
+
+retry:
mas_wr_store_entry(&wr_mas);
+ if (unlikely(mas_nomem(mas, GFP_ATOMIC | __GFP_NOFAIL)))
+ goto retry;
+
MAS_WR_BUG_ON(&wr_mas, mas_is_err(mas));
mas_destroy(mas);
}
@@ -5550,9 +5555,10 @@ EXPORT_SYMBOL_GPL(mas_store_prealloc);
int mas_preallocate(struct ma_state *mas, gfp_t gfp)
{
int ret;
+ int count = 1 + mas_mt_height(mas) * 3;

- mas_node_count_gfp(mas, 1 + mas_mt_height(mas) * 3, gfp);
- mas->mas_flags |= MA_STATE_PREALLOC;
+ mas_node_count_gfp(mas, 1, gfp);
+ kmem_cache_prefill_percpu_array(maple_node_cache, count, gfp);
if (likely(!mas_is_err(mas)))
return 0;

--
2.41.0



2023-08-08 18:57:56

by Liam R. Howlett

[permalink] [raw]
Subject: Re: [RFC v1 5/5] maple_tree: replace preallocation with slub percpu array prefill

* Vlastimil Babka <[email protected]> [230808 05:53]:
> With the percpu array we can try not doing the preallocations in maple
> tree, and instead make sure the percpu array is prefilled, and using
> GFP_ATOMIC in places that relied on the preallocation (in case we miss
> or fail trylock on the array), i.e. mas_store_prealloc(). For now simply
> add __GFP_NOFAIL there as well.
>
> First I tried to change mas_node_count_gfp() to not preallocate anything
> anywhere, but that lead to warns and panics, even though the other
> caller mas_node_count() uses GFP_NOWAIT | __GFP_NOWARN so it has no
> guarantees... So I changed just mas_preallocate(). I let it still to
> truly preallocate a single node, but maybe it's not necessary?

Ah, yes. I added a check to make sure we didn't allocate more nodes
when using preallocations. This check is what you are hitting when you
don't allocate anything. This is tracked in mas_flags by
setting/clearing MA_STATE_PREALLOC. Good news, that check works!

> ---
> lib/maple_tree.c | 10 ++++++++--
> 1 file changed, 8 insertions(+), 2 deletions(-)
>
> diff --git a/lib/maple_tree.c b/lib/maple_tree.c
> index 7a8e7c467d7c..5a209d88c318 100644
> --- a/lib/maple_tree.c
> +++ b/lib/maple_tree.c
> @@ -5534,7 +5534,12 @@ void mas_store_prealloc(struct ma_state *mas, void *entry)
>
> mas_wr_store_setup(&wr_mas);
> trace_ma_write(__func__, mas, 0, entry);
> +
> +retry:
> mas_wr_store_entry(&wr_mas);
> + if (unlikely(mas_nomem(mas, GFP_ATOMIC | __GFP_NOFAIL)))
> + goto retry;
> +
> MAS_WR_BUG_ON(&wr_mas, mas_is_err(mas));
> mas_destroy(mas);
> }
> @@ -5550,9 +5555,10 @@ EXPORT_SYMBOL_GPL(mas_store_prealloc);
> int mas_preallocate(struct ma_state *mas, gfp_t gfp)
> {
> int ret;
> + int count = 1 + mas_mt_height(mas) * 3;
>
> - mas_node_count_gfp(mas, 1 + mas_mt_height(mas) * 3, gfp);
> - mas->mas_flags |= MA_STATE_PREALLOC;
> + mas_node_count_gfp(mas, 1, gfp);
> + kmem_cache_prefill_percpu_array(maple_node_cache, count, gfp);
> if (likely(!mas_is_err(mas)))
> return 0;
>
> --
> 2.41.0
>

2023-08-08 19:48:41

by Liam R. Howlett

[permalink] [raw]
Subject: Re: [RFC v1 5/5] maple_tree: replace preallocation with slub percpu array prefill

* Liam R. Howlett <[email protected]> [230808 10:37]:
> * Vlastimil Babka <[email protected]> [230808 05:53]:
> > With the percpu array we can try not doing the preallocations in maple
> > tree, and instead make sure the percpu array is prefilled, and using
> > GFP_ATOMIC in places that relied on the preallocation (in case we miss
> > or fail trylock on the array), i.e. mas_store_prealloc(). For now simply
> > add __GFP_NOFAIL there as well.
> >
> > First I tried to change mas_node_count_gfp() to not preallocate anything
> > anywhere, but that lead to warns and panics, even though the other
> > caller mas_node_count() uses GFP_NOWAIT | __GFP_NOWARN so it has no
> > guarantees... So I changed just mas_preallocate(). I let it still to
> > truly preallocate a single node, but maybe it's not necessary?
>
> Ah, yes. I added a check to make sure we didn't allocate more nodes
> when using preallocations. This check is what you are hitting when you
> don't allocate anything. This is tracked in mas_flags by
> setting/clearing MA_STATE_PREALLOC. Good news, that check works!

Adding the attached patch to your series prior to the below allows for
the removal of the extra preallocation.

>
> > ---
> > lib/maple_tree.c | 10 ++++++++--
> > 1 file changed, 8 insertions(+), 2 deletions(-)
> >
> > diff --git a/lib/maple_tree.c b/lib/maple_tree.c
> > index 7a8e7c467d7c..5a209d88c318 100644
> > --- a/lib/maple_tree.c
> > +++ b/lib/maple_tree.c
> > @@ -5534,7 +5534,12 @@ void mas_store_prealloc(struct ma_state *mas, void *entry)
> >
> > mas_wr_store_setup(&wr_mas);
> > trace_ma_write(__func__, mas, 0, entry);
> > +
> > +retry:
> > mas_wr_store_entry(&wr_mas);
> > + if (unlikely(mas_nomem(mas, GFP_ATOMIC | __GFP_NOFAIL)))
> > + goto retry;
> > +
> > MAS_WR_BUG_ON(&wr_mas, mas_is_err(mas));
> > mas_destroy(mas);
> > }
> > @@ -5550,9 +5555,10 @@ EXPORT_SYMBOL_GPL(mas_store_prealloc);
> > int mas_preallocate(struct ma_state *mas, gfp_t gfp)
> > {
> > int ret;
> > + int count = 1 + mas_mt_height(mas) * 3;
> >
> > - mas_node_count_gfp(mas, 1 + mas_mt_height(mas) * 3, gfp);
> > - mas->mas_flags |= MA_STATE_PREALLOC;
> > + mas_node_count_gfp(mas, 1, gfp);
> > + kmem_cache_prefill_percpu_array(maple_node_cache, count, gfp);
> > if (likely(!mas_is_err(mas)))
> > return 0;
> >
> > --
> > 2.41.0
> >


Attachments:
(No filename) (2.35 kB)
0001-maple_tree-Remove-MA_STATE_PREALLOC.patch (2.76 kB)
Download all attachments

2023-08-08 20:06:11

by Liam R. Howlett

[permalink] [raw]
Subject: Re: [RFC v1 5/5] maple_tree: replace preallocation with slub percpu array prefill

* Vlastimil Babka <[email protected]> [230808 05:53]:
> With the percpu array we can try not doing the preallocations in maple
> tree, and instead make sure the percpu array is prefilled, and using
> GFP_ATOMIC in places that relied on the preallocation (in case we miss
> or fail trylock on the array), i.e. mas_store_prealloc(). For now simply
> add __GFP_NOFAIL there as well.
>
> First I tried to change mas_node_count_gfp() to not preallocate anything
> anywhere, but that lead to warns and panics, even though the other
> caller mas_node_count() uses GFP_NOWAIT | __GFP_NOWARN so it has no
> guarantees... So I changed just mas_preallocate(). I let it still to
> truly preallocate a single node, but maybe it's not necessary?

Here's a patch to add the percpu array interface to the testing code.

Note that the maple tree preallocation testing isn't updated.

> ---
> lib/maple_tree.c | 10 ++++++++--
> 1 file changed, 8 insertions(+), 2 deletions(-)
>
> diff --git a/lib/maple_tree.c b/lib/maple_tree.c
> index 7a8e7c467d7c..5a209d88c318 100644
> --- a/lib/maple_tree.c
> +++ b/lib/maple_tree.c
> @@ -5534,7 +5534,12 @@ void mas_store_prealloc(struct ma_state *mas, void *entry)
>
> mas_wr_store_setup(&wr_mas);
> trace_ma_write(__func__, mas, 0, entry);
> +
> +retry:
> mas_wr_store_entry(&wr_mas);
> + if (unlikely(mas_nomem(mas, GFP_ATOMIC | __GFP_NOFAIL)))
> + goto retry;
> +
> MAS_WR_BUG_ON(&wr_mas, mas_is_err(mas));
> mas_destroy(mas);
> }
> @@ -5550,9 +5555,10 @@ EXPORT_SYMBOL_GPL(mas_store_prealloc);
> int mas_preallocate(struct ma_state *mas, gfp_t gfp)
> {
> int ret;
> + int count = 1 + mas_mt_height(mas) * 3;
>
> - mas_node_count_gfp(mas, 1 + mas_mt_height(mas) * 3, gfp);
> - mas->mas_flags |= MA_STATE_PREALLOC;
> + mas_node_count_gfp(mas, 1, gfp);
> + kmem_cache_prefill_percpu_array(maple_node_cache, count, gfp);
> if (likely(!mas_is_err(mas)))
> return 0;
>
> --
> 2.41.0
>


Attachments:
(No filename) (1.94 kB)
0001-tools-Add-SLUB-percpu-array-functions-for-testing.patch (2.58 kB)
Download all attachments