public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 0/2] malloc: add multi-threaded tests for aligned_alloc/calloc/malloc
@ 2024-06-27 14:20 Miguel Martín
  2024-06-27 14:20 ` [PATCH 1/2] malloc: avoid global locks in tst-aligned_alloc-lib.c Miguel Martín
  2024-06-27 14:20 ` [PATCH 2/2] malloc: add multi-threaded tests for aligned_alloc/calloc/malloc Miguel Martín
  0 siblings, 2 replies; 5+ messages in thread
From: Miguel Martín @ 2024-06-27 14:20 UTC (permalink / raw)
  To: libc-alpha

Improve aligned_alloc/calloc/malloc test coverage by adding
multi-threaded tests with random memory allocations and with/without
cross-thread memory deallocations.

Modify the existing DSO used for random memory allocations to avoid
getting global locks in the allocation process.

The new tests are added to tests-exclude-mcheck as they don't seem
to play well with mcheck and I have not been able to find any problem
with the tests themselves. Happy to fix anything and/or file an issue
in mcheck for further investigation.

Miguel Martín (2):
  malloc: avoid global locks in tst-aligned_alloc-lib.c
  malloc: add multi-threaded tests for aligned_alloc/calloc/malloc

 malloc/Makefile                               |   8 +
 .../tst-aligned-alloc-random-thread-cross.c   |  19 ++
 malloc/tst-aligned-alloc-random-thread.c      | 170 ++++++++++++++++++
 malloc/tst-aligned_alloc-lib.c                |  39 ++--
 4 files changed, 217 insertions(+), 19 deletions(-)
 create mode 100644 malloc/tst-aligned-alloc-random-thread-cross.c
 create mode 100644 malloc/tst-aligned-alloc-random-thread.c

--
Miguel Martín
mmartinv@redhat.com


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/2] malloc: avoid global locks in tst-aligned_alloc-lib.c
  2024-06-27 14:20 [PATCH 0/2] malloc: add multi-threaded tests for aligned_alloc/calloc/malloc Miguel Martín
@ 2024-06-27 14:20 ` Miguel Martín
  2024-06-27 14:20 ` [PATCH 2/2] malloc: add multi-threaded tests for aligned_alloc/calloc/malloc Miguel Martín
  1 sibling, 0 replies; 5+ messages in thread
From: Miguel Martín @ 2024-06-27 14:20 UTC (permalink / raw)
  To: libc-alpha

Make sure the DSO used by aligned_alloc/calloc/malloc tests does not get
a global lock on multithreaded tests.
---
 malloc/tst-aligned_alloc-lib.c | 39 +++++++++++++++++-----------------
 1 file changed, 20 insertions(+), 19 deletions(-)

diff --git a/malloc/tst-aligned_alloc-lib.c b/malloc/tst-aligned_alloc-lib.c
index 0205df5acf..9ef1f839c1 100644
--- a/malloc/tst-aligned_alloc-lib.c
+++ b/malloc/tst-aligned_alloc-lib.c
@@ -17,37 +17,38 @@
    License along with the GNU C Library; see the file COPYING.LIB.  If
    not, see <https://www.gnu.org/licenses/>.  */
 
-#include <array_length.h>
 #include <libc-symbols.h>
 #include <stdlib.h>
+#include <time.h>
 
 extern void *__libc_malloc (size_t size);
 extern void *__libc_calloc (size_t n, size_t size);
 
+__thread unsigned int seed = 0;
+
 int aligned_alloc_count = 0;
 int libc_malloc_count = 0;
 int libc_calloc_count = 0;
 
-/* Get a random alignment value.  Biased towards the smaller values.  Must be
-   a power of 2. */
-static size_t get_random_alignment (void)
-{
-  size_t aligns[] = {
-    1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384
-  };
-
-  return aligns[random () % array_length (aligns)];
-}
-
-static void *get_random_alloc (size_t size)
+static void *
+get_random_alloc (size_t size)
 {
   void *retval;
   size_t align;
+  struct timespec tp;
+
+  if (seed == 0)
+    {
+      clock_gettime (CLOCK_REALTIME, &tp);
+      seed = tp.tv_nsec;
+    }
 
-  switch (random() % 3)
-  {
+  switch (rand_r (&seed) % 3)
+    {
     case 1:
-      align = get_random_alignment ();
+      /* Get a random alignment value.  Biased towards the smaller
+       * values up to 16384. Must be a power of 2. */
+      align = 1 << rand_r (&seed) % 15;
       retval = aligned_alloc (align, size);
       aligned_alloc_count++;
       break;
@@ -59,13 +60,13 @@ static void *get_random_alloc (size_t size)
       retval = __libc_malloc (size);
       libc_malloc_count++;
       break;
-  }
+    }
 
   return retval;
 }
 
-
-void * __random_malloc (size_t size)
+void *
+__random_malloc (size_t size)
 {
   return get_random_alloc (size);
 }
-- 
Miguel Martín
mmartinv@redhat.com


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 2/2] malloc: add multi-threaded tests for aligned_alloc/calloc/malloc
  2024-06-27 14:20 [PATCH 0/2] malloc: add multi-threaded tests for aligned_alloc/calloc/malloc Miguel Martín
  2024-06-27 14:20 ` [PATCH 1/2] malloc: avoid global locks in tst-aligned_alloc-lib.c Miguel Martín
@ 2024-06-27 14:20 ` Miguel Martín
  2024-07-01 12:13   ` Adhemerval Zanella Netto
  1 sibling, 1 reply; 5+ messages in thread
From: Miguel Martín @ 2024-06-27 14:20 UTC (permalink / raw)
  To: libc-alpha

Improve aligned_alloc/calloc/malloc test coverage by adding
multi-threaded tests with random memory allocations and with/without
cross-thread memory deallocations.

Perform a number of memory allocation calls with a randomly sized,
but limited to 0xffff, requests.

Use the existing DSO ('malloc/tst-aligned_alloc-lib.c') to randomize
allocator selection.

The multi-threaded allocation/deallocation is staged as described below:

- Stage 1: Half of the threads will be allocating memory and the
  other half will be waiting for them to finish the allocation.
- Stage 2: Half of the threads will be allocating memory and the
  other half will be deallocating memory.
- Stage 3: Half of the threads will be deallocating memory and the
  second half waiting on the to finish.

Add 'malloc/tst-aligned-alloc-random-thread.c' where each thread will
deallocate only the memory that was previously allocated by itself.

Add 'malloc/tst-aligned-alloc-random-thread-cross.c' where each thread
will deallocate memory that was previously allocated by another thread.

The intention is to be able to utilize existing malloc testing to ensure
that similar allocation APIs are also exposed to the same rigors.
---
 malloc/Makefile                               |   8 +
 .../tst-aligned-alloc-random-thread-cross.c   |  19 ++
 malloc/tst-aligned-alloc-random-thread.c      | 170 ++++++++++++++++++
 3 files changed, 197 insertions(+)
 create mode 100644 malloc/tst-aligned-alloc-random-thread-cross.c
 create mode 100644 malloc/tst-aligned-alloc-random-thread.c

diff --git a/malloc/Makefile b/malloc/Makefile
index 02aff1bd1d..98d507a6eb 100644
--- a/malloc/Makefile
+++ b/malloc/Makefile
@@ -28,6 +28,8 @@ tests := \
   mallocbug \
   tst-aligned-alloc \
   tst-aligned-alloc-random \
+  tst-aligned-alloc-random-thread \
+  tst-aligned-alloc-random-thread-cross \
   tst-alloc_buffer \
   tst-calloc \
   tst-free-errno \
@@ -151,6 +153,8 @@ ifeq ($(have-GLIBC_2.23)$(build-shared),yesyes)
 # the tests expect specific internal behavior that is changed due to linking to
 # libmcheck.a.
 tests-exclude-mcheck = \
+  tst-aligned-alloc-random-thread \
+  tst-aligned-alloc-random-thread-cross \
   tst-compathooks-off \
   tst-compathooks-on \
   tst-malloc-backtrace \
@@ -415,7 +419,11 @@ $(objpfx)tst-mallocstate: $(objpfx)libc_malloc_debug.so
 $(objpfx)tst-mallocstate-malloc-check: $(objpfx)libc_malloc_debug.so
 
 $(objpfx)tst-aligned-alloc-random.out: $(objpfx)tst-aligned_alloc-lib.so
+$(objpfx)tst-aligned-alloc-random-thread.out: $(objpfx)tst-aligned_alloc-lib.so
+$(objpfx)tst-aligned-alloc-random-thread-cross.out: $(objpfx)tst-aligned_alloc-lib.so
 $(objpfx)tst-malloc-random.out: $(objpfx)tst-aligned_alloc-lib.so
 
 tst-aligned-alloc-random-ENV = LD_PRELOAD=$(objpfx)tst-aligned_alloc-lib.so
+tst-aligned-alloc-random-thread-ENV = LD_PRELOAD=$(objpfx)tst-aligned_alloc-lib.so
+tst-aligned-alloc-random-thread-cross-ENV = LD_PRELOAD=$(objpfx)tst-aligned_alloc-lib.so
 tst-malloc-random-ENV = LD_PRELOAD=$(objpfx)tst-aligned_alloc-lib.so
diff --git a/malloc/tst-aligned-alloc-random-thread-cross.c b/malloc/tst-aligned-alloc-random-thread-cross.c
new file mode 100644
index 0000000000..360ecc56ee
--- /dev/null
+++ b/malloc/tst-aligned-alloc-random-thread-cross.c
@@ -0,0 +1,19 @@
+/* multi-threaded memory allocation and cross-thread deallocation test.
+   Copyright (C) 2024 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; see the file COPYING.LIB.  If
+   not, see <https://www.gnu.org/licenses/>.  */
+#define CROSS_THREAD_DEALLOC
+#include "tst-aligned-alloc-random-thread.c"
diff --git a/malloc/tst-aligned-alloc-random-thread.c b/malloc/tst-aligned-alloc-random-thread.c
new file mode 100644
index 0000000000..dfc29c0da4
--- /dev/null
+++ b/malloc/tst-aligned-alloc-random-thread.c
@@ -0,0 +1,170 @@
+/* multi-threaded memory allocation/deallocation test.
+   Copyright (C) 2024 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; see the file COPYING.LIB.  If
+   not, see <https://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/xthread.h>
+#include <support/test-driver.h>
+#include <sys/sysinfo.h>
+#include <unistd.h>
+
+#ifndef ITERATIONS
+#  define ITERATIONS 16
+#endif
+
+#ifndef NUM_THREADS
+#  define NUM_THREADS 8
+#endif
+
+#ifndef NUM_ALLOCATIONS
+#  define NUM_ALLOCATIONS (16 * 1024)
+#endif
+
+static pthread_barrier_t barrier;
+
+__thread unsigned int seed;
+
+typedef struct
+{
+  int id;
+  pthread_t thread;
+} thread;
+
+thread threads[NUM_THREADS];
+
+typedef struct
+{
+  void *ptr;
+  size_t size;
+} allocation;
+
+allocation allocations[NUM_ALLOCATIONS];
+
+void
+run_thread_dealloc (int id)
+{
+  int actual_thread = id;
+#ifdef CROSS_THREAD_DEALLOC
+  if (id < NUM_THREADS / 2)
+    actual_thread = (id + NUM_THREADS / 2);
+#endif
+  for (int i = id; i < NUM_ALLOCATIONS; i += NUM_THREADS)
+    {
+      free (allocations[i].ptr);
+      verbose_printf (
+	  "info: thread %.2d dealloc %lu bytes at %p (allocations[%d])\n",
+	  actual_thread, allocations[i].size, allocations[i].ptr, i);
+      allocations[i].ptr = NULL;
+      allocations[i].size = 0;
+    }
+}
+
+void
+run_thread_alloc (int id)
+{
+  int actual_thread = id;
+#ifdef CROSS_THREAD_DEALLOC
+  if (id >= NUM_THREADS / 2)
+    actual_thread = (id - NUM_THREADS / 2);
+#endif
+  for (int i = id; i < NUM_ALLOCATIONS; i += NUM_THREADS)
+    {
+      allocations[i].size = rand_r (&seed) & 0xffff;
+      allocations[i].ptr = malloc (allocations[i].size);
+      TEST_VERIFY_EXIT (allocations[i].ptr != NULL);
+      verbose_printf (
+	  "info: thread %.2d alloc %lu bytes at %p (allocations[%d])\n",
+	  actual_thread, allocations[i].size, allocations[i].ptr, i);
+    }
+}
+
+void *
+run_allocations (void *arg)
+{
+  int id = *((int *) arg);
+  seed = time (NULL) + id;
+
+  /* Stage 1: Half o the threads allocating memory */
+  if (id < NUM_THREADS / 2)
+    run_thread_alloc (id);
+
+  verbose_printf ("info: thread %.2d waiting for stage 1 barrier\n", id);
+  xpthread_barrier_wait (&barrier);
+
+  /* Stage 2: Half of the threads allocationg memory and the other
+   * half deallocating
+   */
+  if (id < NUM_THREADS / 2)
+#ifndef CROSS_THREAD_DEALLOC
+    run_thread_dealloc (id);
+#else
+    run_thread_alloc (id + NUM_THREADS / 2);
+#endif
+  else
+#ifndef CROSS_THREAD_DEALLOC
+    run_thread_alloc (id);
+#else
+    run_thread_dealloc (id - NUM_THREADS / 2);
+#endif
+
+  verbose_printf ("info: thread %.2d waiting for stage 2 barrier\n", id);
+  xpthread_barrier_wait (&barrier);
+
+  // Stage 3: Half of the threads deallocating and the other waiting for
+  // them to finish.
+  if (id >= NUM_THREADS / 2)
+    run_thread_dealloc (id);
+
+  verbose_printf ("info: thread %.2d waiting for stage 3 barrier\n", id);
+  xpthread_barrier_wait (&barrier);
+
+  return NULL;
+}
+
+static int
+do_test (void)
+{
+  memset (allocations, 0, sizeof (allocations));
+  memset (threads, 0, sizeof (threads));
+  xpthread_barrier_init (&barrier, NULL, NUM_THREADS);
+
+  verbose_printf ("info: running %d iterations with %d threads\n", ITERATIONS, NUM_THREADS);
+  for (int j = 0; j < ITERATIONS; j++)
+    {
+      for (int i = 0; i < NUM_THREADS; i++)
+	{
+	  threads[i].id = i;
+	  threads[i].thread
+	      = xpthread_create (NULL, run_allocations, &threads[i].id);
+	}
+
+      for (int i = 0; i < NUM_THREADS; i++)
+	xpthread_join (threads[i].thread);
+
+      // Check everything was freed
+      for (int i = 0; i < NUM_ALLOCATIONS; i++)
+	TEST_VERIFY_EXIT (allocations[i].ptr == NULL);
+    }
+
+  return 0;
+}
+
+#include <support/test-driver.c>
-- 
Miguel Martín
mmartinv@redhat.com


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 2/2] malloc: add multi-threaded tests for aligned_alloc/calloc/malloc
  2024-06-27 14:20 ` [PATCH 2/2] malloc: add multi-threaded tests for aligned_alloc/calloc/malloc Miguel Martín
@ 2024-07-01 12:13   ` Adhemerval Zanella Netto
  2024-07-03  6:04     ` Miguel Martín
  0 siblings, 1 reply; 5+ messages in thread
From: Adhemerval Zanella Netto @ 2024-07-01 12:13 UTC (permalink / raw)
  To: Miguel Martín, libc-alpha



On 27/06/24 11:20, Miguel Martín wrote:
> Improve aligned_alloc/calloc/malloc test coverage by adding
> multi-threaded tests with random memory allocations and with/without
> cross-thread memory deallocations.
> 
> Perform a number of memory allocation calls with a randomly sized,
> but limited to 0xffff, requests.
> 
> Use the existing DSO ('malloc/tst-aligned_alloc-lib.c') to randomize
> allocator selection.
> 
> The multi-threaded allocation/deallocation is staged as described below:
> 
> - Stage 1: Half of the threads will be allocating memory and the
>   other half will be waiting for them to finish the allocation.
> - Stage 2: Half of the threads will be allocating memory and the
>   other half will be deallocating memory.
> - Stage 3: Half of the threads will be deallocating memory and the
>   second half waiting on the to finish.
> 
> Add 'malloc/tst-aligned-alloc-random-thread.c' where each thread will
> deallocate only the memory that was previously allocated by itself.
> 
> Add 'malloc/tst-aligned-alloc-random-thread-cross.c' where each thread
> will deallocate memory that was previously allocated by another thread.
> 
> The intention is to be able to utilize existing malloc testing to ensure
> that similar allocation APIs are also exposed to the same rigors.

This new test failed on armhf CI for some reason [1]

=== glibc failures ===

FAIL: malloc/tst-aligned-alloc-random-thread-cross
original exit status 127

FAIL: malloc/tst-aligned-alloc-random-thread-cross-malloc-hugetlb1
original exit status 127

FAIL: malloc/tst-aligned-alloc-random-thread-malloc-hugetlb1
original exit status 127

FAIL: malloc/tst-aligned-alloc-random-thread-malloc-hugetlb2
original exit status 127

FAIL: malloc/tst-aligned-alloc-random-thread-malloc-check
original exit status 127

FAIL: malloc/tst-aligned-alloc-random-thread
original exit status 127

FAIL: malloc/tst-aligned-alloc-random-thread-cross-malloc-hugetlb2
original exit status 127

FAIL: malloc/tst-aligned-alloc-random-thread-cross-malloc-check
original exit status 127


Usually '127' means a SEGFAULT.

[1] https://ci.linaro.org/job/tcwg_glibc_check--master-arm-precommit/2067/artifact/artifacts/artifacts.precommit/00-sumfiles/

> ---
>  malloc/Makefile                               |   8 +
>  .../tst-aligned-alloc-random-thread-cross.c   |  19 ++
>  malloc/tst-aligned-alloc-random-thread.c      | 170 ++++++++++++++++++
>  3 files changed, 197 insertions(+)
>  create mode 100644 malloc/tst-aligned-alloc-random-thread-cross.c
>  create mode 100644 malloc/tst-aligned-alloc-random-thread.c
> 
> diff --git a/malloc/Makefile b/malloc/Makefile
> index 02aff1bd1d..98d507a6eb 100644
> --- a/malloc/Makefile
> +++ b/malloc/Makefile
> @@ -28,6 +28,8 @@ tests := \
>    mallocbug \
>    tst-aligned-alloc \
>    tst-aligned-alloc-random \
> +  tst-aligned-alloc-random-thread \
> +  tst-aligned-alloc-random-thread-cross \
>    tst-alloc_buffer \
>    tst-calloc \
>    tst-free-errno \
> @@ -151,6 +153,8 @@ ifeq ($(have-GLIBC_2.23)$(build-shared),yesyes)
>  # the tests expect specific internal behavior that is changed due to linking to
>  # libmcheck.a.
>  tests-exclude-mcheck = \
> +  tst-aligned-alloc-random-thread \
> +  tst-aligned-alloc-random-thread-cross \
>    tst-compathooks-off \
>    tst-compathooks-on \
>    tst-malloc-backtrace \
> @@ -415,7 +419,11 @@ $(objpfx)tst-mallocstate: $(objpfx)libc_malloc_debug.so
>  $(objpfx)tst-mallocstate-malloc-check: $(objpfx)libc_malloc_debug.so
>  
>  $(objpfx)tst-aligned-alloc-random.out: $(objpfx)tst-aligned_alloc-lib.so
> +$(objpfx)tst-aligned-alloc-random-thread.out: $(objpfx)tst-aligned_alloc-lib.so
> +$(objpfx)tst-aligned-alloc-random-thread-cross.out: $(objpfx)tst-aligned_alloc-lib.so
>  $(objpfx)tst-malloc-random.out: $(objpfx)tst-aligned_alloc-lib.so
>  
>  tst-aligned-alloc-random-ENV = LD_PRELOAD=$(objpfx)tst-aligned_alloc-lib.so
> +tst-aligned-alloc-random-thread-ENV = LD_PRELOAD=$(objpfx)tst-aligned_alloc-lib.so
> +tst-aligned-alloc-random-thread-cross-ENV = LD_PRELOAD=$(objpfx)tst-aligned_alloc-lib.so
>  tst-malloc-random-ENV = LD_PRELOAD=$(objpfx)tst-aligned_alloc-lib.so
> diff --git a/malloc/tst-aligned-alloc-random-thread-cross.c b/malloc/tst-aligned-alloc-random-thread-cross.c
> new file mode 100644
> index 0000000000..360ecc56ee
> --- /dev/null
> +++ b/malloc/tst-aligned-alloc-random-thread-cross.c
> @@ -0,0 +1,19 @@
> +/* multi-threaded memory allocation and cross-thread deallocation test.
> +   Copyright (C) 2024 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; see the file COPYING.LIB.  If
> +   not, see <https://www.gnu.org/licenses/>.  */
> +#define CROSS_THREAD_DEALLOC
> +#include "tst-aligned-alloc-random-thread.c"
> diff --git a/malloc/tst-aligned-alloc-random-thread.c b/malloc/tst-aligned-alloc-random-thread.c
> new file mode 100644
> index 0000000000..dfc29c0da4
> --- /dev/null
> +++ b/malloc/tst-aligned-alloc-random-thread.c
> @@ -0,0 +1,170 @@
> +/* multi-threaded memory allocation/deallocation test.
> +   Copyright (C) 2024 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; see the file COPYING.LIB.  If
> +   not, see <https://www.gnu.org/licenses/>.  */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <support/check.h>
> +#include <support/support.h>
> +#include <support/xthread.h>
> +#include <support/test-driver.h>
> +#include <sys/sysinfo.h>
> +#include <unistd.h>
> +
> +#ifndef ITERATIONS
> +#  define ITERATIONS 16
> +#endif
> +
> +#ifndef NUM_THREADS
> +#  define NUM_THREADS 8
> +#endif
> +
> +#ifndef NUM_ALLOCATIONS
> +#  define NUM_ALLOCATIONS (16 * 1024)
> +#endif
> +
> +static pthread_barrier_t barrier;
> +
> +__thread unsigned int seed;
> +
> +typedef struct
> +{
> +  int id;
> +  pthread_t thread;
> +} thread;
> +
> +thread threads[NUM_THREADS];
> +
> +typedef struct
> +{
> +  void *ptr;
> +  size_t size;
> +} allocation;
> +
> +allocation allocations[NUM_ALLOCATIONS];
> +
> +void
> +run_thread_dealloc (int id)
> +{
> +  int actual_thread = id;
> +#ifdef CROSS_THREAD_DEALLOC
> +  if (id < NUM_THREADS / 2)
> +    actual_thread = (id + NUM_THREADS / 2);
> +#endif
> +  for (int i = id; i < NUM_ALLOCATIONS; i += NUM_THREADS)
> +    {
> +      free (allocations[i].ptr);
> +      verbose_printf (
> +	  "info: thread %.2d dealloc %lu bytes at %p (allocations[%d])\n",
> +	  actual_thread, allocations[i].size, allocations[i].ptr, i);
> +      allocations[i].ptr = NULL;
> +      allocations[i].size = 0;
> +    }
> +}
> +
> +void
> +run_thread_alloc (int id)
> +{
> +  int actual_thread = id;
> +#ifdef CROSS_THREAD_DEALLOC
> +  if (id >= NUM_THREADS / 2)
> +    actual_thread = (id - NUM_THREADS / 2);
> +#endif
> +  for (int i = id; i < NUM_ALLOCATIONS; i += NUM_THREADS)
> +    {
> +      allocations[i].size = rand_r (&seed) & 0xffff;
> +      allocations[i].ptr = malloc (allocations[i].size);
> +      TEST_VERIFY_EXIT (allocations[i].ptr != NULL);
> +      verbose_printf (
> +	  "info: thread %.2d alloc %lu bytes at %p (allocations[%d])\n",
> +	  actual_thread, allocations[i].size, allocations[i].ptr, i);
> +    }
> +}
> +
> +void *
> +run_allocations (void *arg)
> +{
> +  int id = *((int *) arg);
> +  seed = time (NULL) + id;
> +
> +  /* Stage 1: Half o the threads allocating memory */
> +  if (id < NUM_THREADS / 2)
> +    run_thread_alloc (id);
> +
> +  verbose_printf ("info: thread %.2d waiting for stage 1 barrier\n", id);
> +  xpthread_barrier_wait (&barrier);
> +
> +  /* Stage 2: Half of the threads allocationg memory and the other
> +   * half deallocating
> +   */
> +  if (id < NUM_THREADS / 2)
> +#ifndef CROSS_THREAD_DEALLOC
> +    run_thread_dealloc (id);
> +#else
> +    run_thread_alloc (id + NUM_THREADS / 2);
> +#endif
> +  else
> +#ifndef CROSS_THREAD_DEALLOC
> +    run_thread_alloc (id);
> +#else
> +    run_thread_dealloc (id - NUM_THREADS / 2);
> +#endif
> +
> +  verbose_printf ("info: thread %.2d waiting for stage 2 barrier\n", id);
> +  xpthread_barrier_wait (&barrier);
> +
> +  // Stage 3: Half of the threads deallocating and the other waiting for
> +  // them to finish.
> +  if (id >= NUM_THREADS / 2)
> +    run_thread_dealloc (id);
> +
> +  verbose_printf ("info: thread %.2d waiting for stage 3 barrier\n", id);
> +  xpthread_barrier_wait (&barrier);
> +
> +  return NULL;
> +}
> +
> +static int
> +do_test (void)
> +{
> +  memset (allocations, 0, sizeof (allocations));
> +  memset (threads, 0, sizeof (threads));
> +  xpthread_barrier_init (&barrier, NULL, NUM_THREADS);
> +
> +  verbose_printf ("info: running %d iterations with %d threads\n", ITERATIONS, NUM_THREADS);
> +  for (int j = 0; j < ITERATIONS; j++)
> +    {
> +      for (int i = 0; i < NUM_THREADS; i++)
> +	{
> +	  threads[i].id = i;
> +	  threads[i].thread
> +	      = xpthread_create (NULL, run_allocations, &threads[i].id);
> +	}
> +
> +      for (int i = 0; i < NUM_THREADS; i++)
> +	xpthread_join (threads[i].thread);
> +
> +      // Check everything was freed
> +      for (int i = 0; i < NUM_ALLOCATIONS; i++)
> +	TEST_VERIFY_EXIT (allocations[i].ptr == NULL);
> +    }
> +
> +  return 0;
> +}
> +
> +#include <support/test-driver.c>

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 2/2] malloc: add multi-threaded tests for aligned_alloc/calloc/malloc
  2024-07-01 12:13   ` Adhemerval Zanella Netto
@ 2024-07-03  6:04     ` Miguel Martín
  0 siblings, 0 replies; 5+ messages in thread
From: Miguel Martín @ 2024-07-03  6:04 UTC (permalink / raw)
  To: Adhemerval Zanella Netto; +Cc: libc-alpha

On 2024-07-01, Adhemerval Zanella Netto wrote:
> 
> 
> On 27/06/24 11:20, Miguel Martín wrote:
> > Improve aligned_alloc/calloc/malloc test coverage by adding
> > multi-threaded tests with random memory allocations and with/without
> > cross-thread memory deallocations.
> > 
> > Perform a number of memory allocation calls with a randomly sized,
> > but limited to 0xffff, requests.
> > 
> > Use the existing DSO ('malloc/tst-aligned_alloc-lib.c') to randomize
> > allocator selection.
> > 
> > The multi-threaded allocation/deallocation is staged as described below:
> > 
> > - Stage 1: Half of the threads will be allocating memory and the
> >   other half will be waiting for them to finish the allocation.
> > - Stage 2: Half of the threads will be allocating memory and the
> >   other half will be deallocating memory.
> > - Stage 3: Half of the threads will be deallocating memory and the
> >   second half waiting on the to finish.
> > 
> > Add 'malloc/tst-aligned-alloc-random-thread.c' where each thread will
> > deallocate only the memory that was previously allocated by itself.
> > 
> > Add 'malloc/tst-aligned-alloc-random-thread-cross.c' where each thread
> > will deallocate memory that was previously allocated by another thread.
> > 
> > The intention is to be able to utilize existing malloc testing to ensure
> > that similar allocation APIs are also exposed to the same rigors.
> 
> This new test failed on armhf CI for some reason [1]
> 
> === glibc failures ===
> 
> FAIL: malloc/tst-aligned-alloc-random-thread-cross
> original exit status 127
> 
> FAIL: malloc/tst-aligned-alloc-random-thread-cross-malloc-hugetlb1
> original exit status 127
> 
> FAIL: malloc/tst-aligned-alloc-random-thread-malloc-hugetlb1
> original exit status 127
> 
> FAIL: malloc/tst-aligned-alloc-random-thread-malloc-hugetlb2
> original exit status 127
> 
> FAIL: malloc/tst-aligned-alloc-random-thread-malloc-check
> original exit status 127
> 
> FAIL: malloc/tst-aligned-alloc-random-thread
> original exit status 127
> 
> FAIL: malloc/tst-aligned-alloc-random-thread-cross-malloc-hugetlb2
> original exit status 127
> 
> FAIL: malloc/tst-aligned-alloc-random-thread-cross-malloc-check
> original exit status 127
> 
> 
> Usually '127' means a SEGFAULT.
> 
> [1] https://ci.linaro.org/job/tcwg_glibc_check--master-arm-precommit/2067/artifact/artifacts/artifacts.precommit/00-sumfiles/
> 

Yeah, sorry for the late response but it took a while to figure out
what was going on.

It looks like the ARM compiler doesn't like the format of the
strings in the verbose_printf functions calls.

I will send an update with some other minor changes to improve
readability.

> > ---
> >  malloc/Makefile                               |   8 +
> >  .../tst-aligned-alloc-random-thread-cross.c   |  19 ++
> >  malloc/tst-aligned-alloc-random-thread.c      | 170 ++++++++++++++++++
> >  3 files changed, 197 insertions(+)
> >  create mode 100644 malloc/tst-aligned-alloc-random-thread-cross.c
> >  create mode 100644 malloc/tst-aligned-alloc-random-thread.c
> > 
> > diff --git a/malloc/Makefile b/malloc/Makefile
> > index 02aff1bd1d..98d507a6eb 100644
> > --- a/malloc/Makefile
> > +++ b/malloc/Makefile
> > @@ -28,6 +28,8 @@ tests := \
> >    mallocbug \
> >    tst-aligned-alloc \
> >    tst-aligned-alloc-random \
> > +  tst-aligned-alloc-random-thread \
> > +  tst-aligned-alloc-random-thread-cross \
> >    tst-alloc_buffer \
> >    tst-calloc \
> >    tst-free-errno \
> > @@ -151,6 +153,8 @@ ifeq ($(have-GLIBC_2.23)$(build-shared),yesyes)
> >  # the tests expect specific internal behavior that is changed due to linking to
> >  # libmcheck.a.
> >  tests-exclude-mcheck = \
> > +  tst-aligned-alloc-random-thread \
> > +  tst-aligned-alloc-random-thread-cross \
> >    tst-compathooks-off \
> >    tst-compathooks-on \
> >    tst-malloc-backtrace \
> > @@ -415,7 +419,11 @@ $(objpfx)tst-mallocstate: $(objpfx)libc_malloc_debug.so
> >  $(objpfx)tst-mallocstate-malloc-check: $(objpfx)libc_malloc_debug.so
> >  
> >  $(objpfx)tst-aligned-alloc-random.out: $(objpfx)tst-aligned_alloc-lib.so
> > +$(objpfx)tst-aligned-alloc-random-thread.out: $(objpfx)tst-aligned_alloc-lib.so
> > +$(objpfx)tst-aligned-alloc-random-thread-cross.out: $(objpfx)tst-aligned_alloc-lib.so
> >  $(objpfx)tst-malloc-random.out: $(objpfx)tst-aligned_alloc-lib.so
> >  
> >  tst-aligned-alloc-random-ENV = LD_PRELOAD=$(objpfx)tst-aligned_alloc-lib.so
> > +tst-aligned-alloc-random-thread-ENV = LD_PRELOAD=$(objpfx)tst-aligned_alloc-lib.so
> > +tst-aligned-alloc-random-thread-cross-ENV = LD_PRELOAD=$(objpfx)tst-aligned_alloc-lib.so
> >  tst-malloc-random-ENV = LD_PRELOAD=$(objpfx)tst-aligned_alloc-lib.so
> > diff --git a/malloc/tst-aligned-alloc-random-thread-cross.c b/malloc/tst-aligned-alloc-random-thread-cross.c
> > new file mode 100644
> > index 0000000000..360ecc56ee
> > --- /dev/null
> > +++ b/malloc/tst-aligned-alloc-random-thread-cross.c
> > @@ -0,0 +1,19 @@
> > +/* multi-threaded memory allocation and cross-thread deallocation test.
> > +   Copyright (C) 2024 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; see the file COPYING.LIB.  If
> > +   not, see <https://www.gnu.org/licenses/>.  */
> > +#define CROSS_THREAD_DEALLOC
> > +#include "tst-aligned-alloc-random-thread.c"
> > diff --git a/malloc/tst-aligned-alloc-random-thread.c b/malloc/tst-aligned-alloc-random-thread.c
> > new file mode 100644
> > index 0000000000..dfc29c0da4
> > --- /dev/null
> > +++ b/malloc/tst-aligned-alloc-random-thread.c
> > @@ -0,0 +1,170 @@
> > +/* multi-threaded memory allocation/deallocation test.
> > +   Copyright (C) 2024 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; see the file COPYING.LIB.  If
> > +   not, see <https://www.gnu.org/licenses/>.  */
> > +
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <string.h>
> > +#include <support/check.h>
> > +#include <support/support.h>
> > +#include <support/xthread.h>
> > +#include <support/test-driver.h>
> > +#include <sys/sysinfo.h>
> > +#include <unistd.h>
> > +
> > +#ifndef ITERATIONS
> > +#  define ITERATIONS 16
> > +#endif
> > +
> > +#ifndef NUM_THREADS
> > +#  define NUM_THREADS 8
> > +#endif
> > +
> > +#ifndef NUM_ALLOCATIONS
> > +#  define NUM_ALLOCATIONS (16 * 1024)
> > +#endif
> > +
> > +static pthread_barrier_t barrier;
> > +
> > +__thread unsigned int seed;
> > +
> > +typedef struct
> > +{
> > +  int id;
> > +  pthread_t thread;
> > +} thread;
> > +
> > +thread threads[NUM_THREADS];
> > +
> > +typedef struct
> > +{
> > +  void *ptr;
> > +  size_t size;
> > +} allocation;
> > +
> > +allocation allocations[NUM_ALLOCATIONS];
> > +
> > +void
> > +run_thread_dealloc (int id)
> > +{
> > +  int actual_thread = id;
> > +#ifdef CROSS_THREAD_DEALLOC
> > +  if (id < NUM_THREADS / 2)
> > +    actual_thread = (id + NUM_THREADS / 2);
> > +#endif
> > +  for (int i = id; i < NUM_ALLOCATIONS; i += NUM_THREADS)
> > +    {
> > +      free (allocations[i].ptr);
> > +      verbose_printf (
> > +	  "info: thread %.2d dealloc %lu bytes at %p (allocations[%d])\n",
> > +	  actual_thread, allocations[i].size, allocations[i].ptr, i);
> > +      allocations[i].ptr = NULL;
> > +      allocations[i].size = 0;
> > +    }
> > +}
> > +
> > +void
> > +run_thread_alloc (int id)
> > +{
> > +  int actual_thread = id;
> > +#ifdef CROSS_THREAD_DEALLOC
> > +  if (id >= NUM_THREADS / 2)
> > +    actual_thread = (id - NUM_THREADS / 2);
> > +#endif
> > +  for (int i = id; i < NUM_ALLOCATIONS; i += NUM_THREADS)
> > +    {
> > +      allocations[i].size = rand_r (&seed) & 0xffff;
> > +      allocations[i].ptr = malloc (allocations[i].size);
> > +      TEST_VERIFY_EXIT (allocations[i].ptr != NULL);
> > +      verbose_printf (
> > +	  "info: thread %.2d alloc %lu bytes at %p (allocations[%d])\n",
> > +	  actual_thread, allocations[i].size, allocations[i].ptr, i);
> > +    }
> > +}
> > +
> > +void *
> > +run_allocations (void *arg)
> > +{
> > +  int id = *((int *) arg);
> > +  seed = time (NULL) + id;
> > +
> > +  /* Stage 1: Half o the threads allocating memory */
> > +  if (id < NUM_THREADS / 2)
> > +    run_thread_alloc (id);
> > +
> > +  verbose_printf ("info: thread %.2d waiting for stage 1 barrier\n", id);
> > +  xpthread_barrier_wait (&barrier);
> > +
> > +  /* Stage 2: Half of the threads allocationg memory and the other
> > +   * half deallocating
> > +   */
> > +  if (id < NUM_THREADS / 2)
> > +#ifndef CROSS_THREAD_DEALLOC
> > +    run_thread_dealloc (id);
> > +#else
> > +    run_thread_alloc (id + NUM_THREADS / 2);
> > +#endif
> > +  else
> > +#ifndef CROSS_THREAD_DEALLOC
> > +    run_thread_alloc (id);
> > +#else
> > +    run_thread_dealloc (id - NUM_THREADS / 2);
> > +#endif
> > +
> > +  verbose_printf ("info: thread %.2d waiting for stage 2 barrier\n", id);
> > +  xpthread_barrier_wait (&barrier);
> > +
> > +  // Stage 3: Half of the threads deallocating and the other waiting for
> > +  // them to finish.
> > +  if (id >= NUM_THREADS / 2)
> > +    run_thread_dealloc (id);
> > +
> > +  verbose_printf ("info: thread %.2d waiting for stage 3 barrier\n", id);
> > +  xpthread_barrier_wait (&barrier);
> > +
> > +  return NULL;
> > +}
> > +
> > +static int
> > +do_test (void)
> > +{
> > +  memset (allocations, 0, sizeof (allocations));
> > +  memset (threads, 0, sizeof (threads));
> > +  xpthread_barrier_init (&barrier, NULL, NUM_THREADS);
> > +
> > +  verbose_printf ("info: running %d iterations with %d threads\n", ITERATIONS, NUM_THREADS);
> > +  for (int j = 0; j < ITERATIONS; j++)
> > +    {
> > +      for (int i = 0; i < NUM_THREADS; i++)
> > +	{
> > +	  threads[i].id = i;
> > +	  threads[i].thread
> > +	      = xpthread_create (NULL, run_allocations, &threads[i].id);
> > +	}
> > +
> > +      for (int i = 0; i < NUM_THREADS; i++)
> > +	xpthread_join (threads[i].thread);
> > +
> > +      // Check everything was freed
> > +      for (int i = 0; i < NUM_ALLOCATIONS; i++)
> > +	TEST_VERIFY_EXIT (allocations[i].ptr == NULL);
> > +    }
> > +
> > +  return 0;
> > +}
> > +
> > +#include <support/test-driver.c>
> 


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2024-07-03  6:04 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-06-27 14:20 [PATCH 0/2] malloc: add multi-threaded tests for aligned_alloc/calloc/malloc Miguel Martín
2024-06-27 14:20 ` [PATCH 1/2] malloc: avoid global locks in tst-aligned_alloc-lib.c Miguel Martín
2024-06-27 14:20 ` [PATCH 2/2] malloc: add multi-threaded tests for aligned_alloc/calloc/malloc Miguel Martín
2024-07-01 12:13   ` Adhemerval Zanella Netto
2024-07-03  6:04     ` Miguel Martín

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).