1 /* Copyright (C) 2020-2023 Free Software Foundation, Inc.
2 Contributed by Jakub Jelinek <jakub@redhat.com>.
4 This file is part of the GNU Offloading and Multi Processing Library
7 Libgomp is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
12 Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 Under Section 7 of GPL version 3, you are granted additional
18 permissions described in the GCC Runtime Library Exception, version
19 3.1, as published by the Free Software Foundation.
21 You should have received a copy of the GNU General Public License and
22 a copy of the GCC Runtime Library Exception along with this program;
23 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24 <http://www.gnu.org/licenses/>. */
26 /* This file contains wrappers for the system allocation routines. Most
27 places in the OpenMP API do not make any provision for failure, so in
28 general we cannot allow memory allocation to fail. */
34 #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA)
38 #define omp_max_predefined_alloc omp_thread_mem_alloc
40 enum gomp_numa_memkind_kind
42 GOMP_MEMKIND_NONE
= 0,
43 #define GOMP_MEMKIND_KINDS \
44 GOMP_MEMKIND_KIND (HBW_INTERLEAVE), \
45 GOMP_MEMKIND_KIND (HBW_PREFERRED), \
46 GOMP_MEMKIND_KIND (DAX_KMEM_ALL), \
47 GOMP_MEMKIND_KIND (DAX_KMEM), \
48 GOMP_MEMKIND_KIND (INTERLEAVE), \
49 GOMP_MEMKIND_KIND (DEFAULT)
50 #define GOMP_MEMKIND_KIND(kind) GOMP_MEMKIND_##kind
52 #undef GOMP_MEMKIND_KIND
54 GOMP_MEMKIND_LIBNUMA
= GOMP_MEMKIND_COUNT
57 struct omp_allocator_data
59 omp_memspace_handle_t memspace
;
60 omp_uintptr_t alignment
;
61 omp_uintptr_t pool_size
;
62 omp_uintptr_t used_pool_size
;
63 omp_allocator_handle_t fb_data
;
64 unsigned int sync_hint
: 8;
65 unsigned int access
: 8;
66 unsigned int fallback
: 8;
67 unsigned int pinned
: 1;
68 unsigned int partition
: 7;
69 #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA)
70 unsigned int memkind
: 8;
72 #ifndef HAVE_SYNC_BUILTINS
81 omp_allocator_handle_t allocator
;
85 struct gomp_libnuma_data
88 void *(*numa_alloc_local
) (size_t);
89 void *(*numa_realloc
) (void *, size_t, size_t);
90 void (*numa_free
) (void *, size_t);
93 struct gomp_memkind_data
96 void *(*memkind_malloc
) (void *, size_t);
97 void *(*memkind_calloc
) (void *, size_t, size_t);
98 void *(*memkind_realloc
) (void *, void *, size_t);
99 void (*memkind_free
) (void *, void *);
100 int (*memkind_check_available
) (void *);
101 void **kinds
[GOMP_MEMKIND_COUNT
];
104 #ifdef LIBGOMP_USE_LIBNUMA
105 static struct gomp_libnuma_data
*libnuma_data
;
106 static pthread_once_t libnuma_data_once
= PTHREAD_ONCE_INIT
;
109 gomp_init_libnuma (void)
111 void *handle
= dlopen ("libnuma.so.1", RTLD_LAZY
);
112 struct gomp_libnuma_data
*data
;
114 data
= calloc (1, sizeof (struct gomp_libnuma_data
));
123 __atomic_store_n (&libnuma_data
, data
, MEMMODEL_RELEASE
);
126 data
->numa_handle
= handle
;
127 data
->numa_alloc_local
128 = (__typeof (data
->numa_alloc_local
)) dlsym (handle
, "numa_alloc_local");
130 = (__typeof (data
->numa_realloc
)) dlsym (handle
, "numa_realloc");
132 = (__typeof (data
->numa_free
)) dlsym (handle
, "numa_free");
133 __atomic_store_n (&libnuma_data
, data
, MEMMODEL_RELEASE
);
136 static struct gomp_libnuma_data
*
137 gomp_get_libnuma (void)
139 struct gomp_libnuma_data
*data
140 = __atomic_load_n (&libnuma_data
, MEMMODEL_ACQUIRE
);
143 pthread_once (&libnuma_data_once
, gomp_init_libnuma
);
144 return __atomic_load_n (&libnuma_data
, MEMMODEL_ACQUIRE
);
148 #ifdef LIBGOMP_USE_MEMKIND
149 static struct gomp_memkind_data
*memkind_data
;
150 static pthread_once_t memkind_data_once
= PTHREAD_ONCE_INIT
;
153 gomp_init_memkind (void)
155 void *handle
= dlopen ("libmemkind.so.0", RTLD_LAZY
);
156 struct gomp_memkind_data
*data
;
158 static const char *kinds
[] = {
160 #define GOMP_MEMKIND_KIND(kind) "MEMKIND_" #kind
162 #undef GOMP_MEMKIND_KIND
165 data
= calloc (1, sizeof (struct gomp_memkind_data
));
174 __atomic_store_n (&memkind_data
, data
, MEMMODEL_RELEASE
);
177 data
->memkind_handle
= handle
;
179 = (__typeof (data
->memkind_malloc
)) dlsym (handle
, "memkind_malloc");
181 = (__typeof (data
->memkind_calloc
)) dlsym (handle
, "memkind_calloc");
182 data
->memkind_realloc
183 = (__typeof (data
->memkind_realloc
)) dlsym (handle
, "memkind_realloc");
185 = (__typeof (data
->memkind_free
)) dlsym (handle
, "memkind_free");
186 data
->memkind_check_available
187 = (__typeof (data
->memkind_check_available
))
188 dlsym (handle
, "memkind_check_available");
189 if (data
->memkind_malloc
190 && data
->memkind_calloc
191 && data
->memkind_realloc
192 && data
->memkind_free
193 && data
->memkind_check_available
)
194 for (i
= 1; i
< GOMP_MEMKIND_COUNT
; ++i
)
196 data
->kinds
[i
] = (void **) dlsym (handle
, kinds
[i
]);
197 if (data
->kinds
[i
] && data
->memkind_check_available (*data
->kinds
[i
]))
198 data
->kinds
[i
] = NULL
;
200 __atomic_store_n (&memkind_data
, data
, MEMMODEL_RELEASE
);
203 static struct gomp_memkind_data
*
204 gomp_get_memkind (void)
206 struct gomp_memkind_data
*data
207 = __atomic_load_n (&memkind_data
, MEMMODEL_ACQUIRE
);
210 pthread_once (&memkind_data_once
, gomp_init_memkind
);
211 return __atomic_load_n (&memkind_data
, MEMMODEL_ACQUIRE
);
215 omp_allocator_handle_t
216 omp_init_allocator (omp_memspace_handle_t memspace
, int ntraits
,
217 const omp_alloctrait_t traits
[])
219 struct omp_allocator_data data
220 = { memspace
, 1, ~(uintptr_t) 0, 0, 0, omp_atv_contended
, omp_atv_all
,
221 omp_atv_default_mem_fb
, omp_atv_false
, omp_atv_environment
,
222 #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA)
226 struct omp_allocator_data
*ret
;
229 if (memspace
> omp_low_lat_mem_space
)
230 return omp_null_allocator
;
231 for (i
= 0; i
< ntraits
; i
++)
232 switch (traits
[i
].key
)
234 case omp_atk_sync_hint
:
235 switch (traits
[i
].value
)
237 case omp_atv_default
:
238 data
.sync_hint
= omp_atv_contended
;
240 case omp_atv_contended
:
241 case omp_atv_uncontended
:
242 case omp_atv_serialized
:
243 case omp_atv_private
:
244 data
.sync_hint
= traits
[i
].value
;
247 return omp_null_allocator
;
250 case omp_atk_alignment
:
251 if (traits
[i
].value
== omp_atv_default
)
256 if ((traits
[i
].value
& (traits
[i
].value
- 1)) != 0
258 return omp_null_allocator
;
259 data
.alignment
= traits
[i
].value
;
262 switch (traits
[i
].value
)
264 case omp_atv_default
:
265 data
.access
= omp_atv_all
;
271 data
.access
= traits
[i
].value
;
274 return omp_null_allocator
;
277 case omp_atk_pool_size
:
278 if (traits
[i
].value
== omp_atv_default
)
279 data
.pool_size
= ~(uintptr_t) 0;
281 data
.pool_size
= traits
[i
].value
;
283 case omp_atk_fallback
:
284 switch (traits
[i
].value
)
286 case omp_atv_default
:
287 data
.fallback
= omp_atv_default_mem_fb
;
289 case omp_atv_default_mem_fb
:
290 case omp_atv_null_fb
:
291 case omp_atv_abort_fb
:
292 case omp_atv_allocator_fb
:
293 data
.fallback
= traits
[i
].value
;
296 return omp_null_allocator
;
299 case omp_atk_fb_data
:
300 data
.fb_data
= traits
[i
].value
;
303 switch (traits
[i
].value
)
305 case omp_atv_default
:
307 data
.pinned
= omp_atv_false
;
310 data
.pinned
= omp_atv_true
;
313 return omp_null_allocator
;
316 case omp_atk_partition
:
317 switch (traits
[i
].value
)
319 case omp_atv_default
:
320 data
.partition
= omp_atv_environment
;
322 case omp_atv_environment
:
323 case omp_atv_nearest
:
324 case omp_atv_blocked
:
325 case omp_atv_interleaved
:
326 data
.partition
= traits
[i
].value
;
329 return omp_null_allocator
;
333 return omp_null_allocator
;
336 if (data
.alignment
< sizeof (void *))
337 data
.alignment
= sizeof (void *);
341 #ifdef LIBGOMP_USE_MEMKIND
342 case omp_high_bw_mem_space
:
343 struct gomp_memkind_data
*memkind_data
;
344 memkind_data
= gomp_get_memkind ();
345 if (data
.partition
== omp_atv_interleaved
346 && memkind_data
->kinds
[GOMP_MEMKIND_HBW_INTERLEAVE
])
348 data
.memkind
= GOMP_MEMKIND_HBW_INTERLEAVE
;
351 else if (memkind_data
->kinds
[GOMP_MEMKIND_HBW_PREFERRED
])
353 data
.memkind
= GOMP_MEMKIND_HBW_PREFERRED
;
357 case omp_large_cap_mem_space
:
358 memkind_data
= gomp_get_memkind ();
359 if (memkind_data
->kinds
[GOMP_MEMKIND_DAX_KMEM_ALL
])
360 data
.memkind
= GOMP_MEMKIND_DAX_KMEM_ALL
;
361 else if (memkind_data
->kinds
[GOMP_MEMKIND_DAX_KMEM
])
362 data
.memkind
= GOMP_MEMKIND_DAX_KMEM
;
366 #ifdef LIBGOMP_USE_MEMKIND
367 if (data
.partition
== omp_atv_interleaved
)
369 memkind_data
= gomp_get_memkind ();
370 if (memkind_data
->kinds
[GOMP_MEMKIND_INTERLEAVE
])
371 data
.memkind
= GOMP_MEMKIND_INTERLEAVE
;
377 #ifdef LIBGOMP_USE_LIBNUMA
378 if (data
.memkind
== GOMP_MEMKIND_NONE
&& data
.partition
== omp_atv_nearest
)
380 libnuma_data
= gomp_get_libnuma ();
381 if (libnuma_data
->numa_alloc_local
!= NULL
)
382 data
.memkind
= GOMP_MEMKIND_LIBNUMA
;
386 /* No support for this so far. */
388 return omp_null_allocator
;
390 ret
= gomp_malloc (sizeof (struct omp_allocator_data
));
392 #ifndef HAVE_SYNC_BUILTINS
393 gomp_mutex_init (&ret
->lock
);
395 return (omp_allocator_handle_t
) ret
;
399 omp_destroy_allocator (omp_allocator_handle_t allocator
)
401 if (allocator
!= omp_null_allocator
)
403 #ifndef HAVE_SYNC_BUILTINS
404 gomp_mutex_destroy (&((struct omp_allocator_data
*) allocator
)->lock
);
406 free ((void *) allocator
);
410 ialias (omp_init_allocator
)
411 ialias (omp_destroy_allocator
)
414 omp_aligned_alloc (size_t alignment
, size_t size
,
415 omp_allocator_handle_t allocator
)
417 struct omp_allocator_data
*allocator_data
;
418 size_t new_size
, new_alignment
;
420 #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA)
421 enum gomp_numa_memkind_kind memkind
;
424 if (__builtin_expect (size
== 0, 0))
428 new_alignment
= alignment
;
429 if (allocator
== omp_null_allocator
)
431 struct gomp_thread
*thr
= gomp_thread ();
432 if (thr
->ts
.def_allocator
== omp_null_allocator
)
433 thr
->ts
.def_allocator
= gomp_def_allocator
;
434 allocator
= (omp_allocator_handle_t
) thr
->ts
.def_allocator
;
437 if (allocator
> omp_max_predefined_alloc
)
439 allocator_data
= (struct omp_allocator_data
*) allocator
;
440 if (new_alignment
< allocator_data
->alignment
)
441 new_alignment
= allocator_data
->alignment
;
442 #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA)
443 memkind
= allocator_data
->memkind
;
448 allocator_data
= NULL
;
449 if (new_alignment
< sizeof (void *))
450 new_alignment
= sizeof (void *);
451 #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA)
452 memkind
= GOMP_MEMKIND_NONE
;
454 #ifdef LIBGOMP_USE_MEMKIND
455 if (allocator
== omp_high_bw_mem_alloc
)
456 memkind
= GOMP_MEMKIND_HBW_PREFERRED
;
457 else if (allocator
== omp_large_cap_mem_alloc
)
458 memkind
= GOMP_MEMKIND_DAX_KMEM_ALL
;
461 struct gomp_memkind_data
*memkind_data
= gomp_get_memkind ();
462 if (!memkind_data
->kinds
[memkind
])
463 memkind
= GOMP_MEMKIND_NONE
;
468 new_size
= sizeof (struct omp_mem_header
);
469 if (new_alignment
> sizeof (void *))
470 new_size
+= new_alignment
- sizeof (void *);
471 if (__builtin_add_overflow (size
, new_size
, &new_size
))
474 if (__builtin_expect (allocator_data
475 && allocator_data
->pool_size
< ~(uintptr_t) 0, 0))
477 uintptr_t used_pool_size
;
478 if (new_size
> allocator_data
->pool_size
)
480 #ifdef HAVE_SYNC_BUILTINS
481 used_pool_size
= __atomic_load_n (&allocator_data
->used_pool_size
,
485 uintptr_t new_pool_size
;
486 if (__builtin_add_overflow (used_pool_size
, new_size
,
488 || new_pool_size
> allocator_data
->pool_size
)
490 if (__atomic_compare_exchange_n (&allocator_data
->used_pool_size
,
491 &used_pool_size
, new_pool_size
,
492 true, MEMMODEL_RELAXED
,
498 gomp_mutex_lock (&allocator_data
->lock
);
499 if (__builtin_add_overflow (allocator_data
->used_pool_size
, new_size
,
501 || used_pool_size
> allocator_data
->pool_size
)
503 gomp_mutex_unlock (&allocator_data
->lock
);
506 allocator_data
->used_pool_size
= used_pool_size
;
507 gomp_mutex_unlock (&allocator_data
->lock
);
509 #ifdef LIBGOMP_USE_LIBNUMA
510 if (memkind
== GOMP_MEMKIND_LIBNUMA
)
511 ptr
= libnuma_data
->numa_alloc_local (new_size
);
512 # ifdef LIBGOMP_USE_MEMKIND
516 #ifdef LIBGOMP_USE_MEMKIND
519 struct gomp_memkind_data
*memkind_data
= gomp_get_memkind ();
520 void *kind
= *memkind_data
->kinds
[memkind
];
521 ptr
= memkind_data
->memkind_malloc (kind
, new_size
);
525 ptr
= malloc (new_size
);
528 #ifdef HAVE_SYNC_BUILTINS
529 __atomic_add_fetch (&allocator_data
->used_pool_size
, -new_size
,
532 gomp_mutex_lock (&allocator_data
->lock
);
533 allocator_data
->used_pool_size
-= new_size
;
534 gomp_mutex_unlock (&allocator_data
->lock
);
541 #ifdef LIBGOMP_USE_LIBNUMA
542 if (memkind
== GOMP_MEMKIND_LIBNUMA
)
543 ptr
= libnuma_data
->numa_alloc_local (new_size
);
544 # ifdef LIBGOMP_USE_MEMKIND
548 #ifdef LIBGOMP_USE_MEMKIND
551 struct gomp_memkind_data
*memkind_data
= gomp_get_memkind ();
552 void *kind
= *memkind_data
->kinds
[memkind
];
553 ptr
= memkind_data
->memkind_malloc (kind
, new_size
);
557 ptr
= malloc (new_size
);
562 if (new_alignment
> sizeof (void *))
563 ret
= (void *) (((uintptr_t) ptr
564 + sizeof (struct omp_mem_header
)
565 + new_alignment
- sizeof (void *))
566 & ~(new_alignment
- 1));
568 ret
= (char *) ptr
+ sizeof (struct omp_mem_header
);
569 ((struct omp_mem_header
*) ret
)[-1].ptr
= ptr
;
570 ((struct omp_mem_header
*) ret
)[-1].size
= new_size
;
571 ((struct omp_mem_header
*) ret
)[-1].allocator
= allocator
;
577 switch (allocator_data
->fallback
)
579 case omp_atv_default_mem_fb
:
580 if ((new_alignment
> sizeof (void *) && new_alignment
> alignment
)
581 #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA)
585 && allocator_data
->pool_size
< ~(uintptr_t) 0))
587 allocator
= omp_default_mem_alloc
;
590 /* Otherwise, we've already performed default mem allocation
591 and if that failed, it won't succeed again (unless it was
592 intermittent. Return NULL then, as that is the fallback. */
594 case omp_atv_null_fb
:
597 case omp_atv_abort_fb
:
598 gomp_fatal ("Out of memory allocating %lu bytes",
599 (unsigned long) size
);
600 case omp_atv_allocator_fb
:
601 allocator
= allocator_data
->fb_data
;
608 ialias (omp_aligned_alloc
)
611 omp_alloc (size_t size
, omp_allocator_handle_t allocator
)
613 return ialias_call (omp_aligned_alloc
) (1, size
, allocator
);
616 /* Like omp_aligned_alloc, but apply on top of that:
617 "For allocations that arise from this ... the null_fb value of the
618 fallback allocator trait behaves as if the abort_fb had been specified." */
621 GOMP_alloc (size_t alignment
, size_t size
, uintptr_t allocator
)
624 = ialias_call (omp_aligned_alloc
) (alignment
, size
,
625 (omp_allocator_handle_t
) allocator
);
626 if (__builtin_expect (ret
== NULL
, 0) && size
)
627 gomp_fatal ("Out of memory allocating %lu bytes",
628 (unsigned long) size
);
633 omp_free (void *ptr
, omp_allocator_handle_t allocator
)
635 struct omp_mem_header
*data
;
640 data
= &((struct omp_mem_header
*) ptr
)[-1];
641 if (data
->allocator
> omp_max_predefined_alloc
)
643 struct omp_allocator_data
*allocator_data
644 = (struct omp_allocator_data
*) (data
->allocator
);
645 if (allocator_data
->pool_size
< ~(uintptr_t) 0)
647 #ifdef HAVE_SYNC_BUILTINS
648 __atomic_add_fetch (&allocator_data
->used_pool_size
, -data
->size
,
651 gomp_mutex_lock (&allocator_data
->lock
);
652 allocator_data
->used_pool_size
-= data
->size
;
653 gomp_mutex_unlock (&allocator_data
->lock
);
656 #ifdef LIBGOMP_USE_LIBNUMA
657 if (allocator_data
->memkind
== GOMP_MEMKIND_LIBNUMA
)
659 libnuma_data
->numa_free (data
->ptr
, data
->size
);
662 # ifdef LIBGOMP_USE_MEMKIND
666 #ifdef LIBGOMP_USE_MEMKIND
667 if (allocator_data
->memkind
)
669 struct gomp_memkind_data
*memkind_data
= gomp_get_memkind ();
670 void *kind
= *memkind_data
->kinds
[allocator_data
->memkind
];
671 memkind_data
->memkind_free (kind
, data
->ptr
);
676 #ifdef LIBGOMP_USE_MEMKIND
679 enum gomp_numa_memkind_kind memkind
= GOMP_MEMKIND_NONE
;
680 if (data
->allocator
== omp_high_bw_mem_alloc
)
681 memkind
= GOMP_MEMKIND_HBW_PREFERRED
;
682 else if (data
->allocator
== omp_large_cap_mem_alloc
)
683 memkind
= GOMP_MEMKIND_DAX_KMEM_ALL
;
686 struct gomp_memkind_data
*memkind_data
= gomp_get_memkind ();
687 if (memkind_data
->kinds
[memkind
])
689 void *kind
= *memkind_data
->kinds
[memkind
];
690 memkind_data
->memkind_free (kind
, data
->ptr
);
702 GOMP_free (void *ptr
, uintptr_t allocator
)
704 return ialias_call (omp_free
) (ptr
, (omp_allocator_handle_t
) allocator
);
708 omp_aligned_calloc (size_t alignment
, size_t nmemb
, size_t size
,
709 omp_allocator_handle_t allocator
)
711 struct omp_allocator_data
*allocator_data
;
712 size_t new_size
, size_temp
, new_alignment
;
714 #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA)
715 enum gomp_numa_memkind_kind memkind
;
718 if (__builtin_expect (size
== 0 || nmemb
== 0, 0))
722 new_alignment
= alignment
;
723 if (allocator
== omp_null_allocator
)
725 struct gomp_thread
*thr
= gomp_thread ();
726 if (thr
->ts
.def_allocator
== omp_null_allocator
)
727 thr
->ts
.def_allocator
= gomp_def_allocator
;
728 allocator
= (omp_allocator_handle_t
) thr
->ts
.def_allocator
;
731 if (allocator
> omp_max_predefined_alloc
)
733 allocator_data
= (struct omp_allocator_data
*) allocator
;
734 if (new_alignment
< allocator_data
->alignment
)
735 new_alignment
= allocator_data
->alignment
;
736 #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA)
737 memkind
= allocator_data
->memkind
;
742 allocator_data
= NULL
;
743 if (new_alignment
< sizeof (void *))
744 new_alignment
= sizeof (void *);
745 #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA)
746 memkind
= GOMP_MEMKIND_NONE
;
748 #ifdef LIBGOMP_USE_MEMKIND
749 if (allocator
== omp_high_bw_mem_alloc
)
750 memkind
= GOMP_MEMKIND_HBW_PREFERRED
;
751 else if (allocator
== omp_large_cap_mem_alloc
)
752 memkind
= GOMP_MEMKIND_DAX_KMEM_ALL
;
755 struct gomp_memkind_data
*memkind_data
= gomp_get_memkind ();
756 if (!memkind_data
->kinds
[memkind
])
757 memkind
= GOMP_MEMKIND_NONE
;
762 new_size
= sizeof (struct omp_mem_header
);
763 if (new_alignment
> sizeof (void *))
764 new_size
+= new_alignment
- sizeof (void *);
765 if (__builtin_mul_overflow (size
, nmemb
, &size_temp
))
767 if (__builtin_add_overflow (size_temp
, new_size
, &new_size
))
770 if (__builtin_expect (allocator_data
771 && allocator_data
->pool_size
< ~(uintptr_t) 0, 0))
773 uintptr_t used_pool_size
;
774 if (new_size
> allocator_data
->pool_size
)
776 #ifdef HAVE_SYNC_BUILTINS
777 used_pool_size
= __atomic_load_n (&allocator_data
->used_pool_size
,
781 uintptr_t new_pool_size
;
782 if (__builtin_add_overflow (used_pool_size
, new_size
,
784 || new_pool_size
> allocator_data
->pool_size
)
786 if (__atomic_compare_exchange_n (&allocator_data
->used_pool_size
,
787 &used_pool_size
, new_pool_size
,
788 true, MEMMODEL_RELAXED
,
794 gomp_mutex_lock (&allocator_data
->lock
);
795 if (__builtin_add_overflow (allocator_data
->used_pool_size
, new_size
,
797 || used_pool_size
> allocator_data
->pool_size
)
799 gomp_mutex_unlock (&allocator_data
->lock
);
802 allocator_data
->used_pool_size
= used_pool_size
;
803 gomp_mutex_unlock (&allocator_data
->lock
);
805 #ifdef LIBGOMP_USE_LIBNUMA
806 if (memkind
== GOMP_MEMKIND_LIBNUMA
)
807 /* numa_alloc_local uses mmap with MAP_ANONYMOUS, returning
808 memory that is initialized to zero. */
809 ptr
= libnuma_data
->numa_alloc_local (new_size
);
810 # ifdef LIBGOMP_USE_MEMKIND
814 #ifdef LIBGOMP_USE_MEMKIND
817 struct gomp_memkind_data
*memkind_data
= gomp_get_memkind ();
818 void *kind
= *memkind_data
->kinds
[memkind
];
819 ptr
= memkind_data
->memkind_calloc (kind
, 1, new_size
);
823 ptr
= calloc (1, new_size
);
826 #ifdef HAVE_SYNC_BUILTINS
827 __atomic_add_fetch (&allocator_data
->used_pool_size
, -new_size
,
830 gomp_mutex_lock (&allocator_data
->lock
);
831 allocator_data
->used_pool_size
-= new_size
;
832 gomp_mutex_unlock (&allocator_data
->lock
);
839 #ifdef LIBGOMP_USE_LIBNUMA
840 if (memkind
== GOMP_MEMKIND_LIBNUMA
)
841 /* numa_alloc_local uses mmap with MAP_ANONYMOUS, returning
842 memory that is initialized to zero. */
843 ptr
= libnuma_data
->numa_alloc_local (new_size
);
844 # ifdef LIBGOMP_USE_MEMKIND
848 #ifdef LIBGOMP_USE_MEMKIND
851 struct gomp_memkind_data
*memkind_data
= gomp_get_memkind ();
852 void *kind
= *memkind_data
->kinds
[memkind
];
853 ptr
= memkind_data
->memkind_calloc (kind
, 1, new_size
);
857 ptr
= calloc (1, new_size
);
862 if (new_alignment
> sizeof (void *))
863 ret
= (void *) (((uintptr_t) ptr
864 + sizeof (struct omp_mem_header
)
865 + new_alignment
- sizeof (void *))
866 & ~(new_alignment
- 1));
868 ret
= (char *) ptr
+ sizeof (struct omp_mem_header
);
869 ((struct omp_mem_header
*) ret
)[-1].ptr
= ptr
;
870 ((struct omp_mem_header
*) ret
)[-1].size
= new_size
;
871 ((struct omp_mem_header
*) ret
)[-1].allocator
= allocator
;
877 switch (allocator_data
->fallback
)
879 case omp_atv_default_mem_fb
:
880 if ((new_alignment
> sizeof (void *) && new_alignment
> alignment
)
881 #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA)
885 && allocator_data
->pool_size
< ~(uintptr_t) 0))
887 allocator
= omp_default_mem_alloc
;
890 /* Otherwise, we've already performed default mem allocation
891 and if that failed, it won't succeed again (unless it was
892 intermittent. Return NULL then, as that is the fallback. */
894 case omp_atv_null_fb
:
897 case omp_atv_abort_fb
:
898 gomp_fatal ("Out of memory allocating %lu bytes",
899 (unsigned long) (size
* nmemb
));
900 case omp_atv_allocator_fb
:
901 allocator
= allocator_data
->fb_data
;
908 ialias (omp_aligned_calloc
)
911 omp_calloc (size_t nmemb
, size_t size
, omp_allocator_handle_t allocator
)
913 return ialias_call (omp_aligned_calloc
) (1, nmemb
, size
, allocator
);
917 omp_realloc (void *ptr
, size_t size
, omp_allocator_handle_t allocator
,
918 omp_allocator_handle_t free_allocator
)
920 struct omp_allocator_data
*allocator_data
, *free_allocator_data
;
921 size_t new_size
, old_size
, new_alignment
, old_alignment
;
923 struct omp_mem_header
*data
;
924 #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA)
925 enum gomp_numa_memkind_kind memkind
, free_memkind
;
928 if (__builtin_expect (ptr
== NULL
, 0))
929 return ialias_call (omp_aligned_alloc
) (1, size
, allocator
);
931 if (__builtin_expect (size
== 0, 0))
933 ialias_call (omp_free
) (ptr
, free_allocator
);
937 data
= &((struct omp_mem_header
*) ptr
)[-1];
938 free_allocator
= data
->allocator
;
941 new_alignment
= sizeof (void *);
942 if (allocator
== omp_null_allocator
)
943 allocator
= free_allocator
;
945 if (allocator
> omp_max_predefined_alloc
)
947 allocator_data
= (struct omp_allocator_data
*) allocator
;
948 if (new_alignment
< allocator_data
->alignment
)
949 new_alignment
= allocator_data
->alignment
;
950 #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA)
951 memkind
= allocator_data
->memkind
;
956 allocator_data
= NULL
;
957 #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA)
958 memkind
= GOMP_MEMKIND_NONE
;
960 #ifdef LIBGOMP_USE_MEMKIND
961 if (allocator
== omp_high_bw_mem_alloc
)
962 memkind
= GOMP_MEMKIND_HBW_PREFERRED
;
963 else if (allocator
== omp_large_cap_mem_alloc
)
964 memkind
= GOMP_MEMKIND_DAX_KMEM_ALL
;
967 struct gomp_memkind_data
*memkind_data
= gomp_get_memkind ();
968 if (!memkind_data
->kinds
[memkind
])
969 memkind
= GOMP_MEMKIND_NONE
;
973 if (free_allocator
> omp_max_predefined_alloc
)
975 free_allocator_data
= (struct omp_allocator_data
*) free_allocator
;
976 #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA)
977 free_memkind
= free_allocator_data
->memkind
;
982 free_allocator_data
= NULL
;
983 #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA)
984 free_memkind
= GOMP_MEMKIND_NONE
;
986 #ifdef LIBGOMP_USE_MEMKIND
987 if (free_allocator
== omp_high_bw_mem_alloc
)
988 free_memkind
= GOMP_MEMKIND_HBW_PREFERRED
;
989 else if (free_allocator
== omp_large_cap_mem_alloc
)
990 free_memkind
= GOMP_MEMKIND_DAX_KMEM_ALL
;
993 struct gomp_memkind_data
*memkind_data
= gomp_get_memkind ();
994 if (!memkind_data
->kinds
[free_memkind
])
995 free_memkind
= GOMP_MEMKIND_NONE
;
999 old_alignment
= (uintptr_t) ptr
- (uintptr_t) (data
->ptr
);
1001 new_size
= sizeof (struct omp_mem_header
);
1002 if (new_alignment
> sizeof (void *))
1003 new_size
+= new_alignment
- sizeof (void *);
1004 if (__builtin_add_overflow (size
, new_size
, &new_size
))
1006 old_size
= data
->size
;
1008 if (__builtin_expect (allocator_data
1009 && allocator_data
->pool_size
< ~(uintptr_t) 0, 0))
1011 uintptr_t used_pool_size
;
1012 size_t prev_size
= 0;
1013 /* Check if we can use realloc. Don't use it if extra alignment
1014 was used previously or newly, because realloc might return a pointer
1015 with different alignment and then we'd need to memmove the data
1017 if (free_allocator_data
1018 && free_allocator_data
== allocator_data
1019 && new_alignment
== sizeof (void *)
1020 && old_alignment
== sizeof (struct omp_mem_header
))
1021 prev_size
= old_size
;
1022 if (new_size
> prev_size
1023 && new_size
- prev_size
> allocator_data
->pool_size
)
1025 #ifdef HAVE_SYNC_BUILTINS
1026 used_pool_size
= __atomic_load_n (&allocator_data
->used_pool_size
,
1030 uintptr_t new_pool_size
;
1031 if (new_size
> prev_size
)
1033 if (__builtin_add_overflow (used_pool_size
, new_size
- prev_size
,
1035 || new_pool_size
> allocator_data
->pool_size
)
1039 new_pool_size
= used_pool_size
+ new_size
- prev_size
;
1040 if (__atomic_compare_exchange_n (&allocator_data
->used_pool_size
,
1041 &used_pool_size
, new_pool_size
,
1042 true, MEMMODEL_RELAXED
,
1048 gomp_mutex_lock (&allocator_data
->lock
);
1049 if (new_size
> prev_size
)
1051 if (__builtin_add_overflow (allocator_data
->used_pool_size
,
1052 new_size
- prev_size
,
1054 || used_pool_size
> allocator_data
->pool_size
)
1056 gomp_mutex_unlock (&allocator_data
->lock
);
1061 used_pool_size
= (allocator_data
->used_pool_size
1062 + new_size
- prev_size
);
1063 allocator_data
->used_pool_size
= used_pool_size
;
1064 gomp_mutex_unlock (&allocator_data
->lock
);
1066 #ifdef LIBGOMP_USE_LIBNUMA
1067 if (memkind
== GOMP_MEMKIND_LIBNUMA
)
1070 new_ptr
= libnuma_data
->numa_realloc (data
->ptr
, data
->size
,
1073 new_ptr
= libnuma_data
->numa_alloc_local (new_size
);
1075 # ifdef LIBGOMP_USE_MEMKIND
1079 #ifdef LIBGOMP_USE_MEMKIND
1082 struct gomp_memkind_data
*memkind_data
= gomp_get_memkind ();
1083 void *kind
= *memkind_data
->kinds
[memkind
];
1085 new_ptr
= memkind_data
->memkind_realloc (kind
, data
->ptr
,
1088 new_ptr
= memkind_data
->memkind_malloc (kind
, new_size
);
1093 new_ptr
= realloc (data
->ptr
, new_size
);
1095 new_ptr
= malloc (new_size
);
1096 if (new_ptr
== NULL
)
1098 #ifdef HAVE_SYNC_BUILTINS
1099 __atomic_add_fetch (&allocator_data
->used_pool_size
,
1100 prev_size
- new_size
,
1103 gomp_mutex_lock (&allocator_data
->lock
);
1104 allocator_data
->used_pool_size
-= new_size
- prev_size
;
1105 gomp_mutex_unlock (&allocator_data
->lock
);
1111 ret
= (char *) new_ptr
+ sizeof (struct omp_mem_header
);
1112 ((struct omp_mem_header
*) ret
)[-1].ptr
= new_ptr
;
1113 ((struct omp_mem_header
*) ret
)[-1].size
= new_size
;
1114 ((struct omp_mem_header
*) ret
)[-1].allocator
= allocator
;
1118 else if (new_alignment
== sizeof (void *)
1119 && old_alignment
== sizeof (struct omp_mem_header
)
1120 #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA)
1121 && memkind
== free_memkind
1123 && (free_allocator_data
== NULL
1124 || free_allocator_data
->pool_size
== ~(uintptr_t) 0))
1126 #ifdef LIBGOMP_USE_LIBNUMA
1127 if (memkind
== GOMP_MEMKIND_LIBNUMA
)
1128 new_ptr
= libnuma_data
->numa_realloc (data
->ptr
, data
->size
, new_size
);
1129 # ifdef LIBGOMP_USE_MEMKIND
1133 #ifdef LIBGOMP_USE_MEMKIND
1136 struct gomp_memkind_data
*memkind_data
= gomp_get_memkind ();
1137 void *kind
= *memkind_data
->kinds
[memkind
];
1138 new_ptr
= memkind_data
->memkind_realloc (kind
, data
->ptr
,
1143 new_ptr
= realloc (data
->ptr
, new_size
);
1144 if (new_ptr
== NULL
)
1146 ret
= (char *) new_ptr
+ sizeof (struct omp_mem_header
);
1147 ((struct omp_mem_header
*) ret
)[-1].ptr
= new_ptr
;
1148 ((struct omp_mem_header
*) ret
)[-1].size
= new_size
;
1149 ((struct omp_mem_header
*) ret
)[-1].allocator
= allocator
;
1154 #ifdef LIBGOMP_USE_LIBNUMA
1155 if (memkind
== GOMP_MEMKIND_LIBNUMA
)
1156 new_ptr
= libnuma_data
->numa_alloc_local (new_size
);
1157 # ifdef LIBGOMP_USE_MEMKIND
1161 #ifdef LIBGOMP_USE_MEMKIND
1164 struct gomp_memkind_data
*memkind_data
= gomp_get_memkind ();
1165 void *kind
= *memkind_data
->kinds
[memkind
];
1166 new_ptr
= memkind_data
->memkind_malloc (kind
, new_size
);
1170 new_ptr
= malloc (new_size
);
1171 if (new_ptr
== NULL
)
1175 if (new_alignment
> sizeof (void *))
1176 ret
= (void *) (((uintptr_t) new_ptr
1177 + sizeof (struct omp_mem_header
)
1178 + new_alignment
- sizeof (void *))
1179 & ~(new_alignment
- 1));
1181 ret
= (char *) new_ptr
+ sizeof (struct omp_mem_header
);
1182 ((struct omp_mem_header
*) ret
)[-1].ptr
= new_ptr
;
1183 ((struct omp_mem_header
*) ret
)[-1].size
= new_size
;
1184 ((struct omp_mem_header
*) ret
)[-1].allocator
= allocator
;
1185 if (old_size
- old_alignment
< size
)
1186 size
= old_size
- old_alignment
;
1187 memcpy (ret
, ptr
, size
);
1188 if (__builtin_expect (free_allocator_data
1189 && free_allocator_data
->pool_size
< ~(uintptr_t) 0, 0))
1191 #ifdef HAVE_SYNC_BUILTINS
1192 __atomic_add_fetch (&free_allocator_data
->used_pool_size
, -data
->size
,
1195 gomp_mutex_lock (&free_allocator_data
->lock
);
1196 free_allocator_data
->used_pool_size
-= data
->size
;
1197 gomp_mutex_unlock (&free_allocator_data
->lock
);
1200 #ifdef LIBGOMP_USE_LIBNUMA
1201 if (free_memkind
== GOMP_MEMKIND_LIBNUMA
)
1203 libnuma_data
->numa_free (data
->ptr
, data
->size
);
1206 # ifdef LIBGOMP_USE_MEMKIND
1210 #ifdef LIBGOMP_USE_MEMKIND
1213 struct gomp_memkind_data
*memkind_data
= gomp_get_memkind ();
1214 void *kind
= *memkind_data
->kinds
[free_memkind
];
1215 memkind_data
->memkind_free (kind
, data
->ptr
);
1225 switch (allocator_data
->fallback
)
1227 case omp_atv_default_mem_fb
:
1228 if (new_alignment
> sizeof (void *)
1229 #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA)
1233 && allocator_data
->pool_size
< ~(uintptr_t) 0))
1235 allocator
= omp_default_mem_alloc
;
1238 /* Otherwise, we've already performed default mem allocation
1239 and if that failed, it won't succeed again (unless it was
1240 intermittent. Return NULL then, as that is the fallback. */
1242 case omp_atv_null_fb
:
1245 case omp_atv_abort_fb
:
1246 gomp_fatal ("Out of memory allocating %lu bytes",
1247 (unsigned long) size
);
1248 case omp_atv_allocator_fb
:
1249 allocator
= allocator_data
->fb_data
;