You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
251 lines
8.2 KiB
251 lines
8.2 KiB
commit b0fbcb7d0051a68baf26b2aed51a8a31c34d68e5 |
|
Author: Miguel Martín <mmartinv@redhat.com> |
|
Date: Tue Jul 16 17:14:57 2024 +0200 |
|
|
|
malloc: add multi-threaded tests for aligned_alloc/calloc/malloc |
|
|
|
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 random sizes limited |
|
to 0xffff. |
|
|
|
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 them 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. |
|
Reviewed-by: Arjun Shankar <arjun@redhat.com> |
|
|
|
Conflicts: |
|
malloc/Makefile |
|
(usual tests conflict) |
|
|
|
diff --git a/malloc/Makefile b/malloc/Makefile |
|
index e0fb433a15bad2c2..9dc068f6b3a69caa 100644 |
|
--- a/malloc/Makefile |
|
+++ b/malloc/Makefile |
|
@@ -46,6 +46,8 @@ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \ |
|
tst-malloc-alternate-path \ |
|
tst-aligned-alloc-random \ |
|
tst-malloc-random \ |
|
+ tst-aligned-alloc-random-thread \ |
|
+ tst-aligned-alloc-random-thread-cross \ |
|
|
|
tests-static := \ |
|
tst-interpose-static-nothread \ |
|
@@ -96,7 +98,9 @@ tests-exclude-mcheck = tst-mallocstate \ |
|
tst-malloc-thread-fail \ |
|
tst-malloc-usable-tunables \ |
|
tst-malloc_info \ |
|
- tst-compathooks-off tst-compathooks-on |
|
+ tst-compathooks-off tst-compathooks-on \ |
|
+ tst-aligned-alloc-random-thread \ |
|
+ tst-aligned-alloc-random-thread-cross \ |
|
|
|
tests-mcheck = $(filter-out $(tests-exclude-mcheck) $(tests-static), $(tests)) |
|
endif |
|
@@ -336,7 +340,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 0000000000000000..360ecc56ee7c8c06 |
|
--- /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 0000000000000000..e95f79250abec85e |
|
--- /dev/null |
|
+++ b/malloc/tst-aligned-alloc-random-thread.c |
|
@@ -0,0 +1,145 @@ |
|
+/* 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 2048 |
|
+#endif |
|
+ |
|
+static pthread_barrier_t barrier; |
|
+ |
|
+__thread unsigned int seed; |
|
+ |
|
+typedef struct |
|
+{ |
|
+ int id; |
|
+ pthread_t thread; |
|
+} thread; |
|
+ |
|
+thread threads[NUM_THREADS]; |
|
+ |
|
+void *allocations[NUM_THREADS][NUM_ALLOCATIONS]; |
|
+ |
|
+void |
|
+run_thread_dealloc (int id) |
|
+{ |
|
+ for (int i = 0; i < NUM_ALLOCATIONS; i++) |
|
+ { |
|
+ free (allocations[id][i]); |
|
+ allocations[id][i] = NULL; |
|
+ } |
|
+} |
|
+ |
|
+void |
|
+run_thread_alloc (int id) |
|
+{ |
|
+ size_t msb, size; |
|
+ for (int i = 0; i < NUM_ALLOCATIONS; i++) |
|
+ { |
|
+ msb = 1 << rand_r (&seed) % 16; |
|
+ size = msb + rand_r (&seed) % msb; |
|
+ allocations[id][i] = malloc (size); |
|
+ TEST_VERIFY_EXIT (allocations[id][i] != NULL); |
|
+ } |
|
+} |
|
+ |
|
+void * |
|
+run_allocations (void *arg) |
|
+{ |
|
+ int id = *((int *) arg); |
|
+ seed = time (NULL) + id; |
|
+ |
|
+ /* Stage 1: First half o the threads allocating memory and the second |
|
+ * half waiting for them to finish |
|
+ */ |
|
+ if (id < NUM_THREADS / 2) |
|
+ run_thread_alloc (id); |
|
+ |
|
+ xpthread_barrier_wait (&barrier); |
|
+ |
|
+ /* Stage 2: Half of the threads allocationg memory and the other |
|
+ * half deallocating: |
|
+ * - In the non cross-thread dealloc scenario the first half will be |
|
+ * deallocating the memory allocated by themselves in stage 1 and the |
|
+ * second half will be allocating memory. |
|
+ * - In the cross-thread dealloc scenario the first half will continue |
|
+ * to allocate memory and the second half will deallocate the memory |
|
+ * allocated by the first half in stage 1. |
|
+ */ |
|
+ 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 |
|
+ |
|
+ xpthread_barrier_wait (&barrier); |
|
+ |
|
+ // Stage 3: Second half of the threads deallocating and the first half |
|
+ // waiting for them to finish. |
|
+ if (id >= NUM_THREADS / 2) |
|
+ run_thread_dealloc (id); |
|
+ |
|
+ return NULL; |
|
+} |
|
+ |
|
+static int |
|
+do_test (void) |
|
+{ |
|
+ xpthread_barrier_init (&barrier, NULL, NUM_THREADS); |
|
+ |
|
+ for (int i = 0; i < ITERATIONS; i++) |
|
+ { |
|
+ for (int t = 0; t < NUM_THREADS; t++) |
|
+ { |
|
+ threads[t].id = t; |
|
+ threads[t].thread |
|
+ = xpthread_create (NULL, run_allocations, &threads[t].id); |
|
+ } |
|
+ |
|
+ for (int t = 0; t < NUM_THREADS; t++) |
|
+ xpthread_join (threads[t].thread); |
|
+ } |
|
+ |
|
+ return 0; |
|
+} |
|
+ |
|
+#include <support/test-driver.c>
|
|
|