Re: [PATCH RESEND] slab: introduce the flag SLAB_MINIMIZE_WASTE

From: Mikulas Patocka
Date: Wed Jun 13 2018 - 13:01:36 EST


Hi

I'd like to ask about this patch - will you commit it, or do you want to
make some more changes to it?

Mikulas




On Fri, 27 Apr 2018, Mikulas Patocka wrote:

>
>
> On Fri, 27 Apr 2018, Christopher Lameter wrote:
>
> > On Thu, 26 Apr 2018, Mikulas Patocka wrote:
> >
> > > > Hmmm... order 4 for these caches may cause some concern. These should stay
> > > > under costly order I think. Otherwise allocations are no longer
> > > > guaranteed.
> > >
> > > You said that slub has fallback to smaller order allocations.
> >
> > Yes it does...
> >
> > > The whole purpose of this "minimize waste" approach is to use higher-order
> > > allocations to use memory more efficiently, so it is just doing its job.
> > > (for these 3 caches, order-4 really wastes less memory than order-3 - on
> > > my system TCPv6 and sighand_cache have size 2112, task_struct 2752).
> >
> > Hmmm... Ok if the others are fine with this as well. I got some pushback
> > there in the past.
> >
> > > We could improve the fallback code, so that if order-4 allocation fails,
> > > it tries order-3 allocation, and then falls back to order-0. But I think
> > > that these failures are rare enough that it is not a problem.
> >
> > I also think that would be too many fallbacks.
>
> You are right - it's better to fallback to the minimum possible size, so
> that the allocation is faster.
>
> > The old code uses the concept of a "fraction" to calculate overhead. The
> > code here uses absolute counts of bytes. Fraction looks better to me.
>
> OK - I reworked the patch using the same "fraction" calculation as before.
> The existing logic targets 1/16 wasted space, so I used this target in
> this patch too.
>
> This patch increases only the order of task_struct (from 3 to 4), all the
> other caches have the same order as before.
>
> Mikulas
>
>
>
> From: Mikulas Patocka <mpatocka@xxxxxxxxxx>
> Subject: [PATCH] slub: use higher order to reduce wasted space
>
> If we create a slub cache with large object size (larger than
> slub_max_order), the slub subsystem currently rounds up the object size to
> the next power of two.
>
> This is inefficient, because it wastes too much space. We use the slab
> cache as a buffer cache in dm-bufio, in order to use the memory
> efficiently, we need to reduce wasted space.
>
> This patch reworks the slub order calculation algorithm, so that it uses
> higher order allocations if it would reduce wasted space. The slub
> subsystem has fallback if the higher-order allocations fails, so using
> order higher than PAGE_ALLOC_COSTLY_ORDER is ok.
>
> The new algorithm first calculates the minimum order that can be used for
> a give object size and then increases the order according to these
> conditions:
> * if we would overshoot MAX_OBJS_PER_PAGE, don't increase
> * if we are below slub_min_order, increase
> * if we are below slub_max_order and below min_objects, increase
> * we increase above slub_max_order only if it reduces wasted space and if
> we alrady waste at least 1/16 of the compound page
>
> The new algorithm gives very similar results to the old one, all the
> caches on my system have the same order as before, only the order of
> task_struct (size 2752) is increased from 3 to 4.
>
> Signed-off-by: Mikulas Patocka <mpatocka@xxxxxxxxxx>
>
> ---
> mm/slub.c | 82 +++++++++++++++++++++++---------------------------------------
> 1 file changed, 31 insertions(+), 51 deletions(-)
>
> Index: linux-2.6/mm/slub.c
> ===================================================================
> --- linux-2.6.orig/mm/slub.c 2018-04-27 19:30:34.000000000 +0200
> +++ linux-2.6/mm/slub.c 2018-04-27 21:05:53.000000000 +0200
> @@ -3224,34 +3224,10 @@ static unsigned int slub_min_objects;
> * requested a higher mininum order then we start with that one instead of
> * the smallest order which will fit the object.
> */
> -static inline unsigned int slab_order(unsigned int size,
> - unsigned int min_objects, unsigned int max_order,
> - unsigned int fract_leftover, unsigned int reserved)
> +static int calculate_order(unsigned int size, unsigned int reserved)
> {
> - unsigned int min_order = slub_min_order;
> - unsigned int order;
> -
> - if (order_objects(min_order, size, reserved) > MAX_OBJS_PER_PAGE)
> - return get_order(size * MAX_OBJS_PER_PAGE) - 1;
> -
> - for (order = max(min_order, (unsigned int)get_order(min_objects * size + reserved));
> - order <= max_order; order++) {
> -
> - unsigned int slab_size = (unsigned int)PAGE_SIZE << order;
> - unsigned int rem;
> -
> - rem = (slab_size - reserved) % size;
> -
> - if (rem <= slab_size / fract_leftover)
> - break;
> - }
> -
> - return order;
> -}
> -
> -static inline int calculate_order(unsigned int size, unsigned int reserved)
> -{
> - unsigned int order;
> + unsigned int best_order;
> + unsigned int test_order;
> unsigned int min_objects;
> unsigned int max_objects;
>
> @@ -3269,34 +3245,38 @@ static inline int calculate_order(unsign
> max_objects = order_objects(slub_max_order, size, reserved);
> min_objects = min(min_objects, max_objects);
>
> - while (min_objects > 1) {
> - unsigned int fraction;
> + /* Get the minimum acceptable order for one object */
> + best_order = get_order(size + reserved);
> +
> + for (test_order = best_order + 1; test_order < MAX_ORDER; test_order++) {
> + unsigned best_order_obj = order_objects(best_order, size, reserved);
> + unsigned test_order_obj = order_objects(test_order, size, reserved);
> +
> + unsigned best_order_slab_size = (unsigned int)PAGE_SIZE << best_order;
> + unsigned best_order_rem = (best_order_slab_size - reserved) % size;
> +
> + /* If there would be too many objects, stop searching */
> + if (test_order_obj > MAX_OBJS_PER_PAGE)
> + break;
>
> - fraction = 16;
> - while (fraction >= 4) {
> - order = slab_order(size, min_objects,
> - slub_max_order, fraction, reserved);
> - if (order <= slub_max_order)
> - return order;
> - fraction /= 2;
> - }
> - min_objects--;
> + /* Always increase up to slub_min_order */
> + if (test_order <= slub_min_order)
> + best_order = test_order;
> +
> + /* If we are below min_objects and slub_max_order, increase the order */
> + if (best_order_obj < min_objects && test_order <= slub_max_order)
> + best_order = test_order;
> +
> + /* Increase the order even more, but only if it reduces waste */
> + /* If we already waste less than 1/16, don't increase it */
> + if (best_order_rem >= (best_order_slab_size / 16) &&
> + test_order_obj > (best_order_obj << (test_order - best_order)))
> + best_order = test_order;
> }
>
> - /*
> - * We were unable to place multiple objects in a slab. Now
> - * lets see if we can place a single object there.
> - */
> - order = slab_order(size, 1, slub_max_order, 1, reserved);
> - if (order <= slub_max_order)
> - return order;
> + if (best_order < MAX_ORDER)
> + return best_order;
>
> - /*
> - * Doh this slab cannot be placed using slub_max_order.
> - */
> - order = slab_order(size, 1, MAX_ORDER, 1, reserved);
> - if (order < MAX_ORDER)
> - return order;
> return -ENOSYS;
> }
>
>