public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
From: Xi Ruoyao <xry111@xry111.site>
To: DJ Delorie <dj@redhat.com>
Cc: libc-alpha@sourceware.org
Subject: Re: [PATCH v6 1/1] memalign: Support scanning for aligned chunks.
Date: Thu, 13 Apr 2023 13:51:50 +0800	[thread overview]
Message-ID: <c33cf4c1bb71a65a172b0ad8f256454d799a49a3.camel@xry111.site> (raw)
In-Reply-To: <xna5zcy2dg.fsf@greed.delorie.com>

On Wed, 2023-04-12 at 21:52 -0400, DJ Delorie wrote:
> Xi Ruoyao <xry111@xry111.site> writes:
> > Then we test ar_ptr != NULL in the if statement.
> 
> I haven't reproduce the tcache fail (it might be unrelated) but this
> should fix the ar_ptr case (most of the malloc.c patch just indents a
> bunch of code, to make it conditional).  We don't want to just fail on
> ar_ptr==NULL because that prevents us from calling sysmalloc() to get
> more plain heap.
> 
> From 250e31ff15d92d20e6c66689e34baeab8daa034d Mon Sep 17 00:00:00 2001
> From: DJ Delorie <dj@redhat.com>
> Date: Mon, 3 Apr 2023 17:33:03 -0400
> Subject: malloc: set NON_MAIN_ARENA flag for reclaimed memalign chunk
> (BZ
>  #30101)

Works for me.

> Based on these comments in malloc.c:
> 
>    size field is or'ed with NON_MAIN_ARENA if the chunk was obtained
>    from a non-main arena.  This is only set immediately before handing
>    the chunk to the user, if necessary.
> 
>    The NON_MAIN_ARENA flag is never set for unsorted chunks, so it
>    does not have to be taken into account in size comparisons.
> 
> When we pull a chunk off the unsorted list (or any list) we need to
> make sure that flag is set properly before returning the chunk.
> 
> Use the rounded-up size for chunk_ok_for_memalign()
> 
> Do not scan the arena for reusable chunks if there's no arena.
> 
> diff --git a/malloc/Makefile b/malloc/Makefile
> index f49675845e..e66247ed01 100644
> --- a/malloc/Makefile
> +++ b/malloc/Makefile
> @@ -43,7 +43,8 @@ tests := mallocbug tst-malloc tst-valloc tst-calloc
> tst-obstack \
>          tst-tcfree1 tst-tcfree2 tst-tcfree3 \
>          tst-safe-linking \
>          tst-mallocalign1 \
> -        tst-memalign-2
> +        tst-memalign-2 \
> +        tst-memalign-3
>  
>  tests-static := \
>          tst-interpose-static-nothread \
> @@ -71,7 +72,7 @@ test-srcs = tst-mtrace
>  # with MALLOC_CHECK_=3 because they expect a specific failure.
>  tests-exclude-malloc-check = tst-malloc-check tst-malloc-usable \
>         tst-mxfast tst-safe-linking \
> -       tst-compathooks-off tst-compathooks-on tst-memalign-2
> +       tst-compathooks-off tst-compathooks-on tst-memalign-2 tst-
> memalign-3
>  
>  # Run all tests with MALLOC_CHECK_=3
>  tests-malloc-check = $(filter-out $(tests-exclude-malloc-check) \
> diff --git a/malloc/malloc.c b/malloc/malloc.c
> index 0315ac5d16..7afc02a759 100644
> --- a/malloc/malloc.c
> +++ b/malloc/malloc.c
> @@ -5048,95 +5048,98 @@ _int_memalign (mstate av, size_t alignment,
> size_t bytes)
>       and unlikely to meet our alignment requirements.  We have not
> done
>       any experimentation with searching for aligned fastbins.  */
>  
> -  int first_bin_index;
> -  int first_largebin_index;
> -  int last_bin_index;
> +  if (av != NULL)
> +    {
> +      int first_bin_index;
> +      int first_largebin_index;
> +      int last_bin_index;
>  
> -  if (in_smallbin_range (nb))
> -    first_bin_index = smallbin_index (nb);
> -  else
> -    first_bin_index = largebin_index (nb);
> +      if (in_smallbin_range (nb))
> +       first_bin_index = smallbin_index (nb);
> +      else
> +       first_bin_index = largebin_index (nb);
>  
> -  if (in_smallbin_range (nb * 2))
> -    last_bin_index = smallbin_index (nb * 2);
> -  else
> -    last_bin_index = largebin_index (nb * 2);
> +      if (in_smallbin_range (nb * 2))
> +       last_bin_index = smallbin_index (nb * 2);
> +      else
> +       last_bin_index = largebin_index (nb * 2);
>  
> -  first_largebin_index = largebin_index (MIN_LARGE_SIZE);
> +      first_largebin_index = largebin_index (MIN_LARGE_SIZE);
>  
> -  int victim_index;                 /* its bin index */
> +      int victim_index;                 /* its bin index */
>  
> -  for (victim_index = first_bin_index;
> -       victim_index < last_bin_index;
> -       victim_index ++)
> -    {
> -      victim = NULL;
> +      for (victim_index = first_bin_index;
> +          victim_index < last_bin_index;
> +          victim_index ++)
> +       {
> +         victim = NULL;
>  
> -      if (victim_index < first_largebin_index)
> -    {
> -      /* Check small bins.  Small bin chunks are doubly-linked
> despite
> -        being the same size.  */
> +         if (victim_index < first_largebin_index)
> +           {
> +             /* Check small bins.  Small bin chunks are doubly-linked
> despite
> +                being the same size.  */
>  
> -      mchunkptr fwd;                    /* misc temp for linking */
> -      mchunkptr bck;                    /* misc temp for linking */
> +             mchunkptr fwd;                    /* misc temp for
> linking */
> +             mchunkptr bck;                    /* misc temp for
> linking */
>  
> -      bck = bin_at (av, victim_index);
> -      fwd = bck->fd;
> -      while (fwd != bck)
> -       {
> -         if (chunk_ok_for_memalign (fwd, alignment, bytes) > 0)
> -           {
> -             victim = fwd;
> +             bck = bin_at (av, victim_index);
> +             fwd = bck->fd;
> +             while (fwd != bck)
> +               {
> +                 if (chunk_ok_for_memalign (fwd, alignment, nb) > 0)
> +                   {
> +                     victim = fwd;
>  
> -             /* Unlink it */
> -             victim->fd->bk = victim->bk;
> -             victim->bk->fd = victim->fd;
> -             break;
> +                     /* Unlink it */
> +                     victim->fd->bk = victim->bk;
> +                     victim->bk->fd = victim->fd;
> +                     break;
> +                   }
> +
> +                 fwd = fwd->fd;
> +               }
>             }
> +         else
> +           {
> +             /* Check large bins.  */
> +             mchunkptr fwd;                    /* misc temp for
> linking */
> +             mchunkptr bck;                    /* misc temp for
> linking */
> +             mchunkptr best = NULL;
> +             size_t best_size = 0;
>  
> -         fwd = fwd->fd;
> -       }
> -    }
> -  else
> -    {
> -      /* Check large bins.  */
> -      mchunkptr fwd;                    /* misc temp for linking */
> -      mchunkptr bck;                    /* misc temp for linking */
> -      mchunkptr best = NULL;
> -      size_t best_size = 0;
> +             bck = bin_at (av, victim_index);
> +             fwd = bck->fd;
>  
> -      bck = bin_at (av, victim_index);
> -      fwd = bck->fd;
> +             while (fwd != bck)
> +               {
> +                 int extra;
>  
> -      while (fwd != bck)
> -       {
> -         int extra;
> +                 if (chunksize (fwd) < nb)
> +                   break;
> +                 extra = chunk_ok_for_memalign (fwd, alignment, nb);
> +                 if (extra > 0
> +                     && (extra <= best_size || best == NULL))
> +                   {
> +                     best = fwd;
> +                     best_size = extra;
> +                   }
>  
> -         if (chunksize (fwd) < nb)
> -             break;
> -         extra = chunk_ok_for_memalign (fwd, alignment, bytes);
> -         if (extra > 0
> -             && (extra <= best_size || best == NULL))
> -           {
> -             best = fwd;
> -             best_size = extra;
> -           }
> +                 fwd = fwd->fd;
> +               }
> +             victim = best;
>  
> -         fwd = fwd->fd;
> -       }
> -      victim = best;
> +             if (victim != NULL)
> +               {
> +                 unlink_chunk (av, victim);
> +                 break;
> +               }
> +           }
>  
> -      if (victim != NULL)
> -       {
> -         unlink_chunk (av, victim);
> -         break;
> +         if (victim != NULL)
> +           break;
>         }
>      }
>  
> -      if (victim != NULL)
> -       break;
> -    }
> -
>    /* Strategy: find a spot within that chunk that meets the alignment
>       request, and then possibly free the leading and trailing space.
>       This strategy is incredibly costly and can lead to external
> @@ -5147,6 +5150,8 @@ _int_memalign (mstate av, size_t alignment,
> size_t bytes)
>        p = victim;
>        m = chunk2mem (p);
>        set_inuse (p);
> +      if (av != &main_arena)
> +       set_non_main_arena (p);
>      }
>    else
>      {
> diff --git a/malloc/tst-memalign-2.c b/malloc/tst-memalign-2.c
> index 4996578e9f..f229283dbf 100644
> --- a/malloc/tst-memalign-2.c
> +++ b/malloc/tst-memalign-2.c
> @@ -33,9 +33,10 @@ typedef struct TestCase {
>  } TestCase;
>  
>  static TestCase tcache_allocs[] = {
> -  { 24, 8, NULL, NULL },
> -  { 24, 16, NULL, NULL },
> -  { 128, 32, NULL, NULL }
> +  { 24, 32, NULL, NULL },
> +  { 24, 64, NULL, NULL },
> +  { 128, 128, NULL, NULL },
> +  { 500, 128, NULL, NULL }
>  };
>  #define TN array_length (tcache_allocs)
>  
> @@ -70,11 +71,15 @@ do_test (void)
>  
>    for (i = 0; i < TN; ++ i)
>      {
> +      size_t sz2;
> +
>        tcache_allocs[i].ptr1 = memalign (tcache_allocs[i].alignment,
> tcache_allocs[i].size);
>        CHECK (tcache_allocs[i].ptr1, tcache_allocs[i].alignment);
> +      sz2 = malloc_usable_size (tcache_allocs[i].ptr1);
>        free (tcache_allocs[i].ptr1);
> +
>        /* This should return the same chunk as was just free'd.  */
> -      tcache_allocs[i].ptr2 = memalign (tcache_allocs[i].alignment,
> tcache_allocs[i].size);
> +      tcache_allocs[i].ptr2 = memalign (tcache_allocs[i].alignment,
> sz2);
>        CHECK (tcache_allocs[i].ptr2, tcache_allocs[i].alignment);
>        free (tcache_allocs[i].ptr2);
>  
> diff --git a/malloc/tst-memalign-3.c b/malloc/tst-memalign-3.c
> new file mode 100644
> index 0000000000..ab90d6ca9b
> --- /dev/null
> +++ b/malloc/tst-memalign-3.c
> @@ -0,0 +1,173 @@
> +/* Test for memalign chunk reuse.
> +   Copyright (C) 2022 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be
> useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <errno.h>
> +#include <malloc.h>
> +#include <stdio.h>
> +#include <pthread.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <array_length.h>
> +#include <libc-pointer-arith.h>
> +#include <support/check.h>
> +#include <support/xthread.h>
> +
> +
> +typedef struct TestCase {
> +  size_t size;
> +  size_t alignment;
> +  void *ptr1;
> +  void *ptr2;
> +} TestCase;
> +
> +static TestCase tcache_allocs[] = {
> +  { 24, 32, NULL, NULL },
> +  { 24, 64, NULL, NULL },
> +  { 128, 128, NULL, NULL },
> +  { 500, 128, NULL, NULL }
> +};
> +#define TN array_length (tcache_allocs)
> +
> +static TestCase large_allocs[] = {
> +  { 23450, 64, NULL, NULL },
> +  { 23450, 64, NULL, NULL },
> +  { 23550, 64, NULL, NULL },
> +  { 23550, 64, NULL, NULL },
> +  { 23650, 64, NULL, NULL },
> +  { 23650, 64, NULL, NULL },
> +  { 33650, 64, NULL, NULL },
> +  { 33650, 64, NULL, NULL }
> +};
> +#define LN array_length (large_allocs)
> +
> +void *p;
> +
> +/* Sanity checks, ancillary to the actual test.  */
> +#define CHECK(p,a) \
> +  if (p == NULL || !PTR_IS_ALIGNED (p, a)) \
> +    FAIL_EXIT1 ("NULL or misaligned memory detected.\n");
> +
> +static void *
> +mem_test (void *closure)
> +{
> +  int i;
> +  int j;
> +  int count;
> +  void *ptr[10];
> +  void *p;
> +
> +  /* TCache test.  */
> +  for (i = 0; i < TN; ++ i)
> +    {
> +      size_t sz2;
> +
> +      tcache_allocs[i].ptr1 = memalign (tcache_allocs[i].alignment,
> tcache_allocs[i].size);
> +      CHECK (tcache_allocs[i].ptr1, tcache_allocs[i].alignment);
> +      sz2 = malloc_usable_size (tcache_allocs[i].ptr1);
> +      free (tcache_allocs[i].ptr1);
> +
> +      /* This should return the same chunk as was just free'd.  */
> +      tcache_allocs[i].ptr2 = memalign (tcache_allocs[i].alignment,
> sz2);
> +      CHECK (tcache_allocs[i].ptr2, tcache_allocs[i].alignment);
> +      free (tcache_allocs[i].ptr2);
> +
> +      TEST_VERIFY (tcache_allocs[i].ptr1 == tcache_allocs[i].ptr2);
> +    }
> +
> +  /* Test for non-head tcache hits.  */
> +  for (i = 0; i < array_length (ptr); ++ i)
> +    {
> +      if (i == 4)
> +       {
> +         ptr[i] = memalign (64, 256);
> +         CHECK (ptr[i], 64);
> +       }
> +      else
> +       {
> +         ptr[i] = malloc (256);
> +         CHECK (ptr[i], 4);
> +       }
> +    }
> +  for (i = 0; i < array_length (ptr); ++ i)
> +    free (ptr[i]);
> +
> +  p = memalign (64, 256);
> +  CHECK (p, 64);
> +
> +  count = 0;
> +  for (i = 0; i < 10; ++ i)
> +    if (ptr[i] == p)
> +      ++ count;
> +  free (p);
> +  TEST_VERIFY (count > 0);
> +
> +  /* Large bins test.  */
> +
> +  for (i = 0; i < LN; ++ i)
> +    {
> +      large_allocs[i].ptr1 = memalign (large_allocs[i].alignment,
> large_allocs[i].size);
> +      CHECK (large_allocs[i].ptr1, large_allocs[i].alignment);
> +      /* Keep chunks from combining by fragmenting the heap.  */
> +      p = malloc (512);
> +      CHECK (p, 4);
> +    }
> +
> +  for (i = 0; i < LN; ++ i)
> +    free (large_allocs[i].ptr1);
> +
> +  /* Force the unsorted bins to be scanned and moved to small/large
> +     bins.  */
> +  p = malloc (60000);
> +
> +  for (i = 0; i < LN; ++ i)
> +    {
> +      large_allocs[i].ptr2 = memalign (large_allocs[i].alignment,
> large_allocs[i].size);
> +      CHECK (large_allocs[i].ptr2, large_allocs[i].alignment);
> +    }
> +
> +  count = 0;
> +  for (i = 0; i < LN; ++ i)
> +    {
> +      int ok = 0;
> +      for (j = 0; j < LN; ++ j)
> +       if (large_allocs[i].ptr1 == large_allocs[j].ptr2)
> +         ok = 1;
> +      if (ok == 1)
> +       count ++;
> +    }
> +
> +  /* The allocation algorithm is complicated outside of the memalign
> +     logic, so just make sure it's working for most of the
> +     allocations.  This avoids possible boundary conditions with
> +     empty/full heaps.  */
> +  TEST_VERIFY (count > LN / 2);
> +
> +  return 0;
> +}
> +
> +static int
> +do_test (void)
> +{
> +  pthread_t p;
> +
> +  p = xpthread_create (NULL, mem_test, NULL);
> +  xpthread_join (p);
> +  return 0;
> +}
> +
> +#include <support/test-driver.c>
> 

-- 
Xi Ruoyao <xry111@xry111.site>
School of Aerospace Science and Technology, Xidian University

  reply	other threads:[~2023-04-13  5:52 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-07-14  3:58 [PATCH v1 " DJ Delorie
2022-07-19  2:54 ` Carlos O'Donell
2022-07-19  3:57   ` [PATCH v2 " DJ Delorie
2022-07-19  9:19     ` Florian Weimer
2022-07-19 17:32       ` DJ Delorie
2022-07-20  0:32       ` [PATCH v3 " DJ Delorie
2022-07-22 20:21         ` DJ Delorie
2022-07-22 20:28         ` Joseph Myers
2022-07-28 19:50           ` [PATCH v4 " DJ Delorie
2022-08-17 19:00             ` DJ Delorie
2022-11-10 21:40               ` Ping^2: " DJ Delorie
2023-03-20 21:49                 ` Ping^3: " DJ Delorie
2023-03-28 19:07             ` Adhemerval Zanella Netto
2023-03-29  4:20               ` [PATCH v5 " DJ Delorie
2023-03-29 19:41                 ` Adhemerval Zanella Netto
2023-03-29 20:36                   ` DJ Delorie
2023-03-30 10:04                     ` Cristian Rodríguez
2023-03-30 10:50                       ` Adhemerval Zanella Netto
2023-03-30 21:43                         ` Cristian Rodríguez
2023-04-12 17:04                           ` Xi Ruoyao
2023-04-12 17:16                             ` DJ Delorie
2023-04-12 17:26                               ` Xi Ruoyao
2023-04-13  1:52                                 ` [PATCH v6 " DJ Delorie
2023-04-13  5:51                                   ` Xi Ruoyao [this message]
2023-04-17 21:48                                   ` Carlos O'Donell
2023-04-18  1:25                                     ` [PATCH v7] " DJ Delorie
2023-04-18 13:58                                       ` Carlos O'Donell
2023-04-18 15:02                                         ` DJ Delorie
2023-04-12 17:33                             ` [PATCH v5 1/1] " Adhemerval Zanella Netto
2023-04-12 17:40                               ` DJ Delorie
2023-04-12 18:01                                 ` Adhemerval Zanella Netto
2023-04-13  1:57                                   ` DJ Delorie
2023-04-13 10:46                                     ` Adhemerval Zanella Netto
2023-04-05 14:07                     ` Stefan Liebler
2023-04-05 17:58                       ` DJ Delorie
2023-04-11 11:40                         ` Stefan Liebler
2023-04-12 11:23                           ` Stefan Liebler
2023-03-31 15:39                 ` Adhemerval Zanella Netto

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=c33cf4c1bb71a65a172b0ad8f256454d799a49a3.camel@xry111.site \
    --to=xry111@xry111.site \
    --cc=dj@redhat.com \
    --cc=libc-alpha@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).