1 1.1.1.2 mrg /* Copyright (C) 2020-2024 Free Software Foundation, Inc. 2 1.1 mrg Contributed by Jakub Jelinek <jakub (at) redhat.com>. 3 1.1 mrg 4 1.1 mrg This file is part of the GNU Offloading and Multi Processing Library 5 1.1 mrg (libgomp). 6 1.1 mrg 7 1.1 mrg Libgomp is free software; you can redistribute it and/or modify it 8 1.1 mrg under the terms of the GNU General Public License as published by 9 1.1 mrg the Free Software Foundation; either version 3, or (at your option) 10 1.1 mrg any later version. 11 1.1 mrg 12 1.1 mrg Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY 13 1.1 mrg WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 14 1.1 mrg FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15 1.1 mrg more details. 16 1.1 mrg 17 1.1 mrg Under Section 7 of GPL version 3, you are granted additional 18 1.1 mrg permissions described in the GCC Runtime Library Exception, version 19 1.1 mrg 3.1, as published by the Free Software Foundation. 20 1.1 mrg 21 1.1 mrg You should have received a copy of the GNU General Public License and 22 1.1 mrg a copy of the GCC Runtime Library Exception along with this program; 23 1.1 mrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 24 1.1 mrg <http://www.gnu.org/licenses/>. */ 25 1.1 mrg 26 1.1 mrg /* This file contains wrappers for the system allocation routines. Most 27 1.1 mrg places in the OpenMP API do not make any provision for failure, so in 28 1.1 mrg general we cannot allow memory allocation to fail. */ 29 1.1 mrg 30 1.1 mrg #define _GNU_SOURCE 31 1.1 mrg #include "libgomp.h" 32 1.1 mrg #include <stdlib.h> 33 1.1 mrg #include <string.h> 34 1.1.1.2 mrg #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA) 35 1.1.1.2 mrg #include <dlfcn.h> 36 1.1.1.2 mrg #endif 37 1.1.1.2 mrg 38 1.1.1.2 mrg /* Keeping track whether a Fortran scalar allocatable/pointer has been 39 1.1.1.2 mrg allocated via 'omp allocators'/'omp allocate'. */ 40 1.1.1.2 mrg 41 1.1.1.2 mrg struct fort_alloc_splay_tree_key_s { 42 1.1.1.2 mrg void *ptr; 43 1.1.1.2 mrg }; 44 1.1.1.2 mrg 45 1.1.1.2 mrg typedef struct fort_alloc_splay_tree_node_s *fort_alloc_splay_tree_node; 46 1.1.1.2 mrg typedef struct fort_alloc_splay_tree_s *fort_alloc_splay_tree; 47 1.1.1.2 mrg typedef struct fort_alloc_splay_tree_key_s *fort_alloc_splay_tree_key; 48 1.1.1.2 mrg 49 1.1.1.2 mrg static inline int 50 1.1.1.2 mrg fort_alloc_splay_compare (fort_alloc_splay_tree_key x, fort_alloc_splay_tree_key y) 51 1.1.1.2 mrg { 52 1.1.1.2 mrg if (x->ptr < y->ptr) 53 1.1.1.2 mrg return -1; 54 1.1.1.2 mrg if (x->ptr > y->ptr) 55 1.1.1.2 mrg return 1; 56 1.1.1.2 mrg return 0; 57 1.1.1.2 mrg } 58 1.1.1.2 mrg #define splay_tree_prefix fort_alloc 59 1.1.1.2 mrg #define splay_tree_static 60 1.1.1.2 mrg #include "splay-tree.h" 61 1.1.1.2 mrg 62 1.1.1.2 mrg #define splay_tree_prefix fort_alloc 63 1.1.1.2 mrg #define splay_tree_static 64 1.1.1.2 mrg #define splay_tree_c 65 1.1.1.2 mrg #include "splay-tree.h" 66 1.1.1.2 mrg 67 1.1.1.2 mrg static struct fort_alloc_splay_tree_s fort_alloc_scalars; 68 1.1.1.2 mrg 69 1.1.1.2 mrg /* Add pointer as being alloced by GOMP_alloc. */ 70 1.1.1.2 mrg void 71 1.1.1.2 mrg GOMP_add_alloc (void *ptr) 72 1.1.1.2 mrg { 73 1.1.1.2 mrg if (ptr == NULL) 74 1.1.1.2 mrg return; 75 1.1.1.2 mrg fort_alloc_splay_tree_node item; 76 1.1.1.2 mrg item = gomp_malloc (sizeof (struct splay_tree_node_s)); 77 1.1.1.2 mrg item->key.ptr = ptr; 78 1.1.1.2 mrg item->left = NULL; 79 1.1.1.2 mrg item->right = NULL; 80 1.1.1.2 mrg fort_alloc_splay_tree_insert (&fort_alloc_scalars, item); 81 1.1.1.2 mrg } 82 1.1.1.2 mrg 83 1.1.1.2 mrg /* Remove pointer, either called by FREE or by REALLOC, 84 1.1.1.2 mrg either of them can change the allocation status. */ 85 1.1.1.2 mrg bool 86 1.1.1.2 mrg GOMP_is_alloc (void *ptr) 87 1.1.1.2 mrg { 88 1.1.1.2 mrg struct fort_alloc_splay_tree_key_s needle; 89 1.1.1.2 mrg fort_alloc_splay_tree_node n; 90 1.1.1.2 mrg needle.ptr = ptr; 91 1.1.1.2 mrg n = fort_alloc_splay_tree_lookup_node (&fort_alloc_scalars, &needle); 92 1.1.1.2 mrg if (n) 93 1.1.1.2 mrg { 94 1.1.1.2 mrg fort_alloc_splay_tree_remove (&fort_alloc_scalars, &n->key); 95 1.1.1.2 mrg free (n); 96 1.1.1.2 mrg } 97 1.1.1.2 mrg return n != NULL; 98 1.1.1.2 mrg } 99 1.1.1.2 mrg 100 1.1 mrg 101 1.1 mrg #define omp_max_predefined_alloc omp_thread_mem_alloc 102 1.1 mrg 103 1.1.1.2 mrg /* These macros may be overridden in config/<target>/allocator.c. 104 1.1.1.2 mrg The defaults (no override) are to return NULL for pinned memory requests 105 1.1.1.2 mrg and pass through to the regular OS calls otherwise. 106 1.1.1.2 mrg The following definitions (ab)use comma operators to avoid unused 107 1.1.1.2 mrg variable errors. */ 108 1.1.1.2 mrg #ifndef MEMSPACE_ALLOC 109 1.1.1.2 mrg #define MEMSPACE_ALLOC(MEMSPACE, SIZE, PIN) \ 110 1.1.1.2 mrg (PIN ? NULL : malloc (((void)(MEMSPACE), (SIZE)))) 111 1.1.1.2 mrg #endif 112 1.1.1.2 mrg #ifndef MEMSPACE_CALLOC 113 1.1.1.2 mrg #define MEMSPACE_CALLOC(MEMSPACE, SIZE, PIN) \ 114 1.1.1.2 mrg (PIN ? NULL : calloc (1, (((void)(MEMSPACE), (SIZE))))) 115 1.1.1.2 mrg #endif 116 1.1.1.2 mrg #ifndef MEMSPACE_REALLOC 117 1.1.1.2 mrg #define MEMSPACE_REALLOC(MEMSPACE, ADDR, OLDSIZE, SIZE, OLDPIN, PIN) \ 118 1.1.1.2 mrg ((PIN) || (OLDPIN) ? NULL \ 119 1.1.1.2 mrg : realloc (ADDR, (((void)(MEMSPACE), (void)(OLDSIZE), (SIZE))))) 120 1.1.1.2 mrg #endif 121 1.1.1.2 mrg #ifndef MEMSPACE_FREE 122 1.1.1.2 mrg #define MEMSPACE_FREE(MEMSPACE, ADDR, SIZE, PIN) \ 123 1.1.1.2 mrg if (PIN) free (((void)(MEMSPACE), (void)(SIZE), (ADDR))) 124 1.1.1.2 mrg #endif 125 1.1.1.2 mrg #ifndef MEMSPACE_VALIDATE 126 1.1.1.2 mrg #define MEMSPACE_VALIDATE(MEMSPACE, ACCESS, PIN) \ 127 1.1.1.2 mrg (PIN ? 0 : ((void)(MEMSPACE), (void)(ACCESS), 1)) 128 1.1.1.2 mrg #endif 129 1.1.1.2 mrg 130 1.1.1.2 mrg /* Map the predefined allocators to the correct memory space. 131 1.1.1.2 mrg The index to this table is the omp_allocator_handle_t enum value. 132 1.1.1.2 mrg When the user calls omp_alloc with a predefined allocator this 133 1.1.1.2 mrg table determines what memory they get. */ 134 1.1.1.2 mrg static const omp_memspace_handle_t predefined_alloc_mapping[] = { 135 1.1.1.2 mrg omp_default_mem_space, /* omp_null_allocator doesn't actually use this. */ 136 1.1.1.2 mrg omp_default_mem_space, /* omp_default_mem_alloc. */ 137 1.1.1.2 mrg omp_large_cap_mem_space, /* omp_large_cap_mem_alloc. */ 138 1.1.1.2 mrg omp_const_mem_space, /* omp_const_mem_alloc. */ 139 1.1.1.2 mrg omp_high_bw_mem_space, /* omp_high_bw_mem_alloc. */ 140 1.1.1.2 mrg omp_low_lat_mem_space, /* omp_low_lat_mem_alloc. */ 141 1.1.1.2 mrg omp_low_lat_mem_space, /* omp_cgroup_mem_alloc (implementation defined). */ 142 1.1.1.2 mrg omp_low_lat_mem_space, /* omp_pteam_mem_alloc (implementation defined). */ 143 1.1.1.2 mrg omp_low_lat_mem_space, /* omp_thread_mem_alloc (implementation defined). */ 144 1.1.1.2 mrg }; 145 1.1.1.2 mrg 146 1.1.1.2 mrg #define ARRAY_SIZE(A) (sizeof (A) / sizeof ((A)[0])) 147 1.1.1.2 mrg _Static_assert (ARRAY_SIZE (predefined_alloc_mapping) 148 1.1.1.2 mrg == omp_max_predefined_alloc + 1, 149 1.1.1.2 mrg "predefined_alloc_mapping must match omp_memspace_handle_t"); 150 1.1.1.2 mrg 151 1.1.1.2 mrg enum gomp_numa_memkind_kind 152 1.1.1.2 mrg { 153 1.1.1.2 mrg GOMP_MEMKIND_NONE = 0, 154 1.1.1.2 mrg #define GOMP_MEMKIND_KINDS \ 155 1.1.1.2 mrg GOMP_MEMKIND_KIND (HBW_INTERLEAVE), \ 156 1.1.1.2 mrg GOMP_MEMKIND_KIND (HBW_PREFERRED), \ 157 1.1.1.2 mrg GOMP_MEMKIND_KIND (DAX_KMEM_ALL), \ 158 1.1.1.2 mrg GOMP_MEMKIND_KIND (DAX_KMEM), \ 159 1.1.1.2 mrg GOMP_MEMKIND_KIND (INTERLEAVE), \ 160 1.1.1.2 mrg GOMP_MEMKIND_KIND (DEFAULT) 161 1.1.1.2 mrg #define GOMP_MEMKIND_KIND(kind) GOMP_MEMKIND_##kind 162 1.1.1.2 mrg GOMP_MEMKIND_KINDS, 163 1.1.1.2 mrg #undef GOMP_MEMKIND_KIND 164 1.1.1.2 mrg GOMP_MEMKIND_COUNT, 165 1.1.1.2 mrg GOMP_MEMKIND_LIBNUMA = GOMP_MEMKIND_COUNT 166 1.1.1.2 mrg }; 167 1.1.1.2 mrg 168 1.1 mrg struct omp_allocator_data 169 1.1 mrg { 170 1.1 mrg omp_memspace_handle_t memspace; 171 1.1 mrg omp_uintptr_t alignment; 172 1.1 mrg omp_uintptr_t pool_size; 173 1.1 mrg omp_uintptr_t used_pool_size; 174 1.1 mrg omp_allocator_handle_t fb_data; 175 1.1 mrg unsigned int sync_hint : 8; 176 1.1 mrg unsigned int access : 8; 177 1.1 mrg unsigned int fallback : 8; 178 1.1 mrg unsigned int pinned : 1; 179 1.1 mrg unsigned int partition : 7; 180 1.1.1.2 mrg #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA) 181 1.1.1.2 mrg unsigned int memkind : 8; 182 1.1.1.2 mrg #endif 183 1.1 mrg #ifndef HAVE_SYNC_BUILTINS 184 1.1 mrg gomp_mutex_t lock; 185 1.1 mrg #endif 186 1.1 mrg }; 187 1.1 mrg 188 1.1 mrg struct omp_mem_header 189 1.1 mrg { 190 1.1 mrg void *ptr; 191 1.1 mrg size_t size; 192 1.1 mrg omp_allocator_handle_t allocator; 193 1.1 mrg void *pad; 194 1.1 mrg }; 195 1.1 mrg 196 1.1.1.2 mrg struct gomp_libnuma_data 197 1.1.1.2 mrg { 198 1.1.1.2 mrg void *numa_handle; 199 1.1.1.2 mrg void *(*numa_alloc_local) (size_t); 200 1.1.1.2 mrg void *(*numa_realloc) (void *, size_t, size_t); 201 1.1.1.2 mrg void (*numa_free) (void *, size_t); 202 1.1.1.2 mrg }; 203 1.1.1.2 mrg 204 1.1.1.2 mrg struct gomp_memkind_data 205 1.1.1.2 mrg { 206 1.1.1.2 mrg void *memkind_handle; 207 1.1.1.2 mrg void *(*memkind_malloc) (void *, size_t); 208 1.1.1.2 mrg void *(*memkind_calloc) (void *, size_t, size_t); 209 1.1.1.2 mrg void *(*memkind_realloc) (void *, void *, size_t); 210 1.1.1.2 mrg void (*memkind_free) (void *, void *); 211 1.1.1.2 mrg int (*memkind_check_available) (void *); 212 1.1.1.2 mrg void **kinds[GOMP_MEMKIND_COUNT]; 213 1.1.1.2 mrg }; 214 1.1.1.2 mrg 215 1.1.1.2 mrg #ifdef LIBGOMP_USE_LIBNUMA 216 1.1.1.2 mrg static struct gomp_libnuma_data *libnuma_data; 217 1.1.1.2 mrg static pthread_once_t libnuma_data_once = PTHREAD_ONCE_INIT; 218 1.1.1.2 mrg 219 1.1.1.2 mrg static void 220 1.1.1.2 mrg gomp_init_libnuma (void) 221 1.1.1.2 mrg { 222 1.1.1.2 mrg void *handle = dlopen ("libnuma.so.1", RTLD_LAZY); 223 1.1.1.2 mrg struct gomp_libnuma_data *data; 224 1.1.1.2 mrg 225 1.1.1.2 mrg data = calloc (1, sizeof (struct gomp_libnuma_data)); 226 1.1.1.2 mrg if (data == NULL) 227 1.1.1.2 mrg { 228 1.1.1.2 mrg if (handle) 229 1.1.1.2 mrg dlclose (handle); 230 1.1.1.2 mrg return; 231 1.1.1.2 mrg } 232 1.1.1.2 mrg if (handle) 233 1.1.1.2 mrg { 234 1.1.1.2 mrg int (*numa_available) (void); 235 1.1.1.2 mrg numa_available 236 1.1.1.2 mrg = (__typeof (numa_available)) dlsym (handle, "numa_available"); 237 1.1.1.2 mrg if (!numa_available || numa_available () != 0) 238 1.1.1.2 mrg { 239 1.1.1.2 mrg dlclose (handle); 240 1.1.1.2 mrg handle = NULL; 241 1.1.1.2 mrg } 242 1.1.1.2 mrg } 243 1.1.1.2 mrg if (!handle) 244 1.1.1.2 mrg { 245 1.1.1.2 mrg __atomic_store_n (&libnuma_data, data, MEMMODEL_RELEASE); 246 1.1.1.2 mrg return; 247 1.1.1.2 mrg } 248 1.1.1.2 mrg data->numa_handle = handle; 249 1.1.1.2 mrg data->numa_alloc_local 250 1.1.1.2 mrg = (__typeof (data->numa_alloc_local)) dlsym (handle, "numa_alloc_local"); 251 1.1.1.2 mrg data->numa_realloc 252 1.1.1.2 mrg = (__typeof (data->numa_realloc)) dlsym (handle, "numa_realloc"); 253 1.1.1.2 mrg data->numa_free 254 1.1.1.2 mrg = (__typeof (data->numa_free)) dlsym (handle, "numa_free"); 255 1.1.1.2 mrg __atomic_store_n (&libnuma_data, data, MEMMODEL_RELEASE); 256 1.1.1.2 mrg } 257 1.1.1.2 mrg 258 1.1.1.2 mrg static struct gomp_libnuma_data * 259 1.1.1.2 mrg gomp_get_libnuma (void) 260 1.1.1.2 mrg { 261 1.1.1.2 mrg struct gomp_libnuma_data *data 262 1.1.1.2 mrg = __atomic_load_n (&libnuma_data, MEMMODEL_ACQUIRE); 263 1.1.1.2 mrg if (data) 264 1.1.1.2 mrg return data; 265 1.1.1.2 mrg pthread_once (&libnuma_data_once, gomp_init_libnuma); 266 1.1.1.2 mrg return __atomic_load_n (&libnuma_data, MEMMODEL_ACQUIRE); 267 1.1.1.2 mrg } 268 1.1.1.2 mrg #endif 269 1.1.1.2 mrg 270 1.1.1.2 mrg #ifdef LIBGOMP_USE_MEMKIND 271 1.1.1.2 mrg static struct gomp_memkind_data *memkind_data; 272 1.1.1.2 mrg static pthread_once_t memkind_data_once = PTHREAD_ONCE_INIT; 273 1.1.1.2 mrg 274 1.1.1.2 mrg static void 275 1.1.1.2 mrg gomp_init_memkind (void) 276 1.1.1.2 mrg { 277 1.1.1.2 mrg void *handle = dlopen ("libmemkind.so.0", RTLD_LAZY); 278 1.1.1.2 mrg struct gomp_memkind_data *data; 279 1.1.1.2 mrg int i; 280 1.1.1.2 mrg static const char *kinds[] = { 281 1.1.1.2 mrg NULL, 282 1.1.1.2 mrg #define GOMP_MEMKIND_KIND(kind) "MEMKIND_" #kind 283 1.1.1.2 mrg GOMP_MEMKIND_KINDS 284 1.1.1.2 mrg #undef GOMP_MEMKIND_KIND 285 1.1.1.2 mrg }; 286 1.1.1.2 mrg 287 1.1.1.2 mrg data = calloc (1, sizeof (struct gomp_memkind_data)); 288 1.1.1.2 mrg if (data == NULL) 289 1.1.1.2 mrg { 290 1.1.1.2 mrg if (handle) 291 1.1.1.2 mrg dlclose (handle); 292 1.1.1.2 mrg return; 293 1.1.1.2 mrg } 294 1.1.1.2 mrg if (!handle) 295 1.1.1.2 mrg { 296 1.1.1.2 mrg __atomic_store_n (&memkind_data, data, MEMMODEL_RELEASE); 297 1.1.1.2 mrg return; 298 1.1.1.2 mrg } 299 1.1.1.2 mrg data->memkind_handle = handle; 300 1.1.1.2 mrg data->memkind_malloc 301 1.1.1.2 mrg = (__typeof (data->memkind_malloc)) dlsym (handle, "memkind_malloc"); 302 1.1.1.2 mrg data->memkind_calloc 303 1.1.1.2 mrg = (__typeof (data->memkind_calloc)) dlsym (handle, "memkind_calloc"); 304 1.1.1.2 mrg data->memkind_realloc 305 1.1.1.2 mrg = (__typeof (data->memkind_realloc)) dlsym (handle, "memkind_realloc"); 306 1.1.1.2 mrg data->memkind_free 307 1.1.1.2 mrg = (__typeof (data->memkind_free)) dlsym (handle, "memkind_free"); 308 1.1.1.2 mrg data->memkind_check_available 309 1.1.1.2 mrg = (__typeof (data->memkind_check_available)) 310 1.1.1.2 mrg dlsym (handle, "memkind_check_available"); 311 1.1.1.2 mrg if (data->memkind_malloc 312 1.1.1.2 mrg && data->memkind_calloc 313 1.1.1.2 mrg && data->memkind_realloc 314 1.1.1.2 mrg && data->memkind_free 315 1.1.1.2 mrg && data->memkind_check_available) 316 1.1.1.2 mrg for (i = 1; i < GOMP_MEMKIND_COUNT; ++i) 317 1.1.1.2 mrg { 318 1.1.1.2 mrg data->kinds[i] = (void **) dlsym (handle, kinds[i]); 319 1.1.1.2 mrg if (data->kinds[i] && data->memkind_check_available (*data->kinds[i])) 320 1.1.1.2 mrg data->kinds[i] = NULL; 321 1.1.1.2 mrg } 322 1.1.1.2 mrg __atomic_store_n (&memkind_data, data, MEMMODEL_RELEASE); 323 1.1.1.2 mrg } 324 1.1.1.2 mrg 325 1.1.1.2 mrg static struct gomp_memkind_data * 326 1.1.1.2 mrg gomp_get_memkind (void) 327 1.1.1.2 mrg { 328 1.1.1.2 mrg struct gomp_memkind_data *data 329 1.1.1.2 mrg = __atomic_load_n (&memkind_data, MEMMODEL_ACQUIRE); 330 1.1.1.2 mrg if (data) 331 1.1.1.2 mrg return data; 332 1.1.1.2 mrg pthread_once (&memkind_data_once, gomp_init_memkind); 333 1.1.1.2 mrg return __atomic_load_n (&memkind_data, MEMMODEL_ACQUIRE); 334 1.1.1.2 mrg } 335 1.1.1.2 mrg #endif 336 1.1.1.2 mrg 337 1.1 mrg omp_allocator_handle_t 338 1.1 mrg omp_init_allocator (omp_memspace_handle_t memspace, int ntraits, 339 1.1 mrg const omp_alloctrait_t traits[]) 340 1.1 mrg { 341 1.1 mrg struct omp_allocator_data data 342 1.1 mrg = { memspace, 1, ~(uintptr_t) 0, 0, 0, omp_atv_contended, omp_atv_all, 343 1.1.1.2 mrg omp_atv_default_mem_fb, omp_atv_false, omp_atv_environment, 344 1.1.1.2 mrg #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA) 345 1.1.1.2 mrg GOMP_MEMKIND_NONE 346 1.1.1.2 mrg #endif 347 1.1.1.2 mrg }; 348 1.1 mrg struct omp_allocator_data *ret; 349 1.1 mrg int i; 350 1.1 mrg 351 1.1 mrg if (memspace > omp_low_lat_mem_space) 352 1.1 mrg return omp_null_allocator; 353 1.1 mrg for (i = 0; i < ntraits; i++) 354 1.1 mrg switch (traits[i].key) 355 1.1 mrg { 356 1.1 mrg case omp_atk_sync_hint: 357 1.1 mrg switch (traits[i].value) 358 1.1 mrg { 359 1.1 mrg case omp_atv_default: 360 1.1 mrg data.sync_hint = omp_atv_contended; 361 1.1 mrg break; 362 1.1 mrg case omp_atv_contended: 363 1.1 mrg case omp_atv_uncontended: 364 1.1 mrg case omp_atv_serialized: 365 1.1 mrg case omp_atv_private: 366 1.1 mrg data.sync_hint = traits[i].value; 367 1.1 mrg break; 368 1.1 mrg default: 369 1.1 mrg return omp_null_allocator; 370 1.1 mrg } 371 1.1 mrg break; 372 1.1 mrg case omp_atk_alignment: 373 1.1 mrg if (traits[i].value == omp_atv_default) 374 1.1 mrg { 375 1.1 mrg data.alignment = 1; 376 1.1 mrg break; 377 1.1 mrg } 378 1.1 mrg if ((traits[i].value & (traits[i].value - 1)) != 0 379 1.1 mrg || !traits[i].value) 380 1.1 mrg return omp_null_allocator; 381 1.1 mrg data.alignment = traits[i].value; 382 1.1 mrg break; 383 1.1 mrg case omp_atk_access: 384 1.1 mrg switch (traits[i].value) 385 1.1 mrg { 386 1.1 mrg case omp_atv_default: 387 1.1 mrg data.access = omp_atv_all; 388 1.1 mrg break; 389 1.1 mrg case omp_atv_all: 390 1.1 mrg case omp_atv_cgroup: 391 1.1 mrg case omp_atv_pteam: 392 1.1 mrg case omp_atv_thread: 393 1.1 mrg data.access = traits[i].value; 394 1.1 mrg break; 395 1.1 mrg default: 396 1.1 mrg return omp_null_allocator; 397 1.1 mrg } 398 1.1 mrg break; 399 1.1 mrg case omp_atk_pool_size: 400 1.1 mrg if (traits[i].value == omp_atv_default) 401 1.1 mrg data.pool_size = ~(uintptr_t) 0; 402 1.1 mrg else 403 1.1 mrg data.pool_size = traits[i].value; 404 1.1 mrg break; 405 1.1 mrg case omp_atk_fallback: 406 1.1 mrg switch (traits[i].value) 407 1.1 mrg { 408 1.1 mrg case omp_atv_default: 409 1.1 mrg data.fallback = omp_atv_default_mem_fb; 410 1.1 mrg break; 411 1.1 mrg case omp_atv_default_mem_fb: 412 1.1 mrg case omp_atv_null_fb: 413 1.1 mrg case omp_atv_abort_fb: 414 1.1 mrg case omp_atv_allocator_fb: 415 1.1 mrg data.fallback = traits[i].value; 416 1.1 mrg break; 417 1.1 mrg default: 418 1.1 mrg return omp_null_allocator; 419 1.1 mrg } 420 1.1 mrg break; 421 1.1 mrg case omp_atk_fb_data: 422 1.1 mrg data.fb_data = traits[i].value; 423 1.1 mrg break; 424 1.1 mrg case omp_atk_pinned: 425 1.1 mrg switch (traits[i].value) 426 1.1 mrg { 427 1.1 mrg case omp_atv_default: 428 1.1 mrg case omp_atv_false: 429 1.1 mrg data.pinned = omp_atv_false; 430 1.1 mrg break; 431 1.1 mrg case omp_atv_true: 432 1.1 mrg data.pinned = omp_atv_true; 433 1.1 mrg break; 434 1.1 mrg default: 435 1.1 mrg return omp_null_allocator; 436 1.1 mrg } 437 1.1 mrg break; 438 1.1 mrg case omp_atk_partition: 439 1.1 mrg switch (traits[i].value) 440 1.1 mrg { 441 1.1 mrg case omp_atv_default: 442 1.1 mrg data.partition = omp_atv_environment; 443 1.1 mrg break; 444 1.1 mrg case omp_atv_environment: 445 1.1 mrg case omp_atv_nearest: 446 1.1 mrg case omp_atv_blocked: 447 1.1 mrg case omp_atv_interleaved: 448 1.1 mrg data.partition = traits[i].value; 449 1.1 mrg break; 450 1.1 mrg default: 451 1.1 mrg return omp_null_allocator; 452 1.1 mrg } 453 1.1 mrg break; 454 1.1 mrg default: 455 1.1 mrg return omp_null_allocator; 456 1.1 mrg } 457 1.1 mrg 458 1.1 mrg if (data.alignment < sizeof (void *)) 459 1.1 mrg data.alignment = sizeof (void *); 460 1.1 mrg 461 1.1.1.2 mrg switch (memspace) 462 1.1.1.2 mrg { 463 1.1.1.2 mrg #ifdef LIBGOMP_USE_MEMKIND 464 1.1.1.2 mrg case omp_high_bw_mem_space: 465 1.1.1.2 mrg struct gomp_memkind_data *memkind_data; 466 1.1.1.2 mrg memkind_data = gomp_get_memkind (); 467 1.1.1.2 mrg if (data.partition == omp_atv_interleaved 468 1.1.1.2 mrg && memkind_data->kinds[GOMP_MEMKIND_HBW_INTERLEAVE]) 469 1.1.1.2 mrg { 470 1.1.1.2 mrg data.memkind = GOMP_MEMKIND_HBW_INTERLEAVE; 471 1.1.1.2 mrg break; 472 1.1.1.2 mrg } 473 1.1.1.2 mrg else if (memkind_data->kinds[GOMP_MEMKIND_HBW_PREFERRED]) 474 1.1.1.2 mrg { 475 1.1.1.2 mrg data.memkind = GOMP_MEMKIND_HBW_PREFERRED; 476 1.1.1.2 mrg break; 477 1.1.1.2 mrg } 478 1.1.1.2 mrg break; 479 1.1.1.2 mrg case omp_large_cap_mem_space: 480 1.1.1.2 mrg memkind_data = gomp_get_memkind (); 481 1.1.1.2 mrg if (memkind_data->kinds[GOMP_MEMKIND_DAX_KMEM_ALL]) 482 1.1.1.2 mrg data.memkind = GOMP_MEMKIND_DAX_KMEM_ALL; 483 1.1.1.2 mrg else if (memkind_data->kinds[GOMP_MEMKIND_DAX_KMEM]) 484 1.1.1.2 mrg data.memkind = GOMP_MEMKIND_DAX_KMEM; 485 1.1.1.2 mrg break; 486 1.1.1.2 mrg #endif 487 1.1.1.2 mrg default: 488 1.1.1.2 mrg #ifdef LIBGOMP_USE_MEMKIND 489 1.1.1.2 mrg if (data.partition == omp_atv_interleaved) 490 1.1.1.2 mrg { 491 1.1.1.2 mrg memkind_data = gomp_get_memkind (); 492 1.1.1.2 mrg if (memkind_data->kinds[GOMP_MEMKIND_INTERLEAVE]) 493 1.1.1.2 mrg data.memkind = GOMP_MEMKIND_INTERLEAVE; 494 1.1.1.2 mrg } 495 1.1.1.2 mrg #endif 496 1.1.1.2 mrg break; 497 1.1.1.2 mrg } 498 1.1.1.2 mrg 499 1.1.1.2 mrg #ifdef LIBGOMP_USE_LIBNUMA 500 1.1.1.2 mrg if (data.memkind == GOMP_MEMKIND_NONE && data.partition == omp_atv_nearest) 501 1.1.1.2 mrg { 502 1.1.1.2 mrg libnuma_data = gomp_get_libnuma (); 503 1.1.1.2 mrg if (libnuma_data->numa_alloc_local != NULL) 504 1.1.1.2 mrg data.memkind = GOMP_MEMKIND_LIBNUMA; 505 1.1.1.2 mrg } 506 1.1.1.2 mrg #endif 507 1.1.1.2 mrg 508 1.1.1.2 mrg /* Reject unsupported memory spaces. */ 509 1.1.1.2 mrg if (!MEMSPACE_VALIDATE (data.memspace, data.access, data.pinned)) 510 1.1 mrg return omp_null_allocator; 511 1.1 mrg 512 1.1 mrg ret = gomp_malloc (sizeof (struct omp_allocator_data)); 513 1.1 mrg *ret = data; 514 1.1 mrg #ifndef HAVE_SYNC_BUILTINS 515 1.1 mrg gomp_mutex_init (&ret->lock); 516 1.1 mrg #endif 517 1.1 mrg return (omp_allocator_handle_t) ret; 518 1.1 mrg } 519 1.1 mrg 520 1.1 mrg void 521 1.1 mrg omp_destroy_allocator (omp_allocator_handle_t allocator) 522 1.1 mrg { 523 1.1 mrg if (allocator != omp_null_allocator) 524 1.1 mrg { 525 1.1 mrg #ifndef HAVE_SYNC_BUILTINS 526 1.1 mrg gomp_mutex_destroy (&((struct omp_allocator_data *) allocator)->lock); 527 1.1 mrg #endif 528 1.1 mrg free ((void *) allocator); 529 1.1 mrg } 530 1.1 mrg } 531 1.1 mrg 532 1.1 mrg ialias (omp_init_allocator) 533 1.1 mrg ialias (omp_destroy_allocator) 534 1.1 mrg 535 1.1 mrg void * 536 1.1 mrg omp_aligned_alloc (size_t alignment, size_t size, 537 1.1 mrg omp_allocator_handle_t allocator) 538 1.1 mrg { 539 1.1 mrg struct omp_allocator_data *allocator_data; 540 1.1 mrg size_t new_size, new_alignment; 541 1.1 mrg void *ptr, *ret; 542 1.1.1.2 mrg #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA) 543 1.1.1.2 mrg enum gomp_numa_memkind_kind memkind; 544 1.1.1.2 mrg #endif 545 1.1 mrg 546 1.1 mrg if (__builtin_expect (size == 0, 0)) 547 1.1 mrg return NULL; 548 1.1 mrg 549 1.1 mrg retry: 550 1.1 mrg new_alignment = alignment; 551 1.1 mrg if (allocator == omp_null_allocator) 552 1.1 mrg { 553 1.1 mrg struct gomp_thread *thr = gomp_thread (); 554 1.1 mrg if (thr->ts.def_allocator == omp_null_allocator) 555 1.1 mrg thr->ts.def_allocator = gomp_def_allocator; 556 1.1 mrg allocator = (omp_allocator_handle_t) thr->ts.def_allocator; 557 1.1 mrg } 558 1.1 mrg 559 1.1 mrg if (allocator > omp_max_predefined_alloc) 560 1.1 mrg { 561 1.1 mrg allocator_data = (struct omp_allocator_data *) allocator; 562 1.1 mrg if (new_alignment < allocator_data->alignment) 563 1.1 mrg new_alignment = allocator_data->alignment; 564 1.1.1.2 mrg #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA) 565 1.1.1.2 mrg memkind = allocator_data->memkind; 566 1.1.1.2 mrg #endif 567 1.1 mrg } 568 1.1 mrg else 569 1.1 mrg { 570 1.1 mrg allocator_data = NULL; 571 1.1 mrg if (new_alignment < sizeof (void *)) 572 1.1 mrg new_alignment = sizeof (void *); 573 1.1.1.2 mrg #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA) 574 1.1.1.2 mrg memkind = GOMP_MEMKIND_NONE; 575 1.1.1.2 mrg #endif 576 1.1.1.2 mrg #ifdef LIBGOMP_USE_MEMKIND 577 1.1.1.2 mrg if (allocator == omp_high_bw_mem_alloc) 578 1.1.1.2 mrg memkind = GOMP_MEMKIND_HBW_PREFERRED; 579 1.1.1.2 mrg else if (allocator == omp_large_cap_mem_alloc) 580 1.1.1.2 mrg memkind = GOMP_MEMKIND_DAX_KMEM_ALL; 581 1.1.1.2 mrg if (memkind) 582 1.1.1.2 mrg { 583 1.1.1.2 mrg struct gomp_memkind_data *memkind_data = gomp_get_memkind (); 584 1.1.1.2 mrg if (!memkind_data->kinds[memkind]) 585 1.1.1.2 mrg memkind = GOMP_MEMKIND_NONE; 586 1.1.1.2 mrg } 587 1.1.1.2 mrg #endif 588 1.1 mrg } 589 1.1 mrg 590 1.1 mrg new_size = sizeof (struct omp_mem_header); 591 1.1 mrg if (new_alignment > sizeof (void *)) 592 1.1 mrg new_size += new_alignment - sizeof (void *); 593 1.1 mrg if (__builtin_add_overflow (size, new_size, &new_size)) 594 1.1 mrg goto fail; 595 1.1.1.2 mrg #ifdef OMP_LOW_LAT_MEM_ALLOC_INVALID 596 1.1.1.2 mrg if (allocator == omp_low_lat_mem_alloc) 597 1.1.1.2 mrg goto fail; 598 1.1.1.2 mrg #endif 599 1.1 mrg 600 1.1 mrg if (__builtin_expect (allocator_data 601 1.1 mrg && allocator_data->pool_size < ~(uintptr_t) 0, 0)) 602 1.1 mrg { 603 1.1 mrg uintptr_t used_pool_size; 604 1.1 mrg if (new_size > allocator_data->pool_size) 605 1.1 mrg goto fail; 606 1.1 mrg #ifdef HAVE_SYNC_BUILTINS 607 1.1 mrg used_pool_size = __atomic_load_n (&allocator_data->used_pool_size, 608 1.1 mrg MEMMODEL_RELAXED); 609 1.1 mrg do 610 1.1 mrg { 611 1.1 mrg uintptr_t new_pool_size; 612 1.1 mrg if (__builtin_add_overflow (used_pool_size, new_size, 613 1.1 mrg &new_pool_size) 614 1.1 mrg || new_pool_size > allocator_data->pool_size) 615 1.1 mrg goto fail; 616 1.1 mrg if (__atomic_compare_exchange_n (&allocator_data->used_pool_size, 617 1.1 mrg &used_pool_size, new_pool_size, 618 1.1 mrg true, MEMMODEL_RELAXED, 619 1.1 mrg MEMMODEL_RELAXED)) 620 1.1 mrg break; 621 1.1 mrg } 622 1.1 mrg while (1); 623 1.1 mrg #else 624 1.1 mrg gomp_mutex_lock (&allocator_data->lock); 625 1.1 mrg if (__builtin_add_overflow (allocator_data->used_pool_size, new_size, 626 1.1 mrg &used_pool_size) 627 1.1 mrg || used_pool_size > allocator_data->pool_size) 628 1.1 mrg { 629 1.1 mrg gomp_mutex_unlock (&allocator_data->lock); 630 1.1 mrg goto fail; 631 1.1 mrg } 632 1.1 mrg allocator_data->used_pool_size = used_pool_size; 633 1.1 mrg gomp_mutex_unlock (&allocator_data->lock); 634 1.1 mrg #endif 635 1.1.1.2 mrg #ifdef LIBGOMP_USE_LIBNUMA 636 1.1.1.2 mrg if (memkind == GOMP_MEMKIND_LIBNUMA) 637 1.1.1.2 mrg ptr = libnuma_data->numa_alloc_local (new_size); 638 1.1.1.2 mrg # ifdef LIBGOMP_USE_MEMKIND 639 1.1.1.2 mrg else 640 1.1.1.2 mrg # endif 641 1.1.1.2 mrg #endif 642 1.1.1.2 mrg #ifdef LIBGOMP_USE_MEMKIND 643 1.1.1.2 mrg if (memkind) 644 1.1.1.2 mrg { 645 1.1.1.2 mrg struct gomp_memkind_data *memkind_data = gomp_get_memkind (); 646 1.1.1.2 mrg void *kind = *memkind_data->kinds[memkind]; 647 1.1.1.2 mrg ptr = memkind_data->memkind_malloc (kind, new_size); 648 1.1.1.2 mrg } 649 1.1.1.2 mrg else 650 1.1.1.2 mrg #endif 651 1.1.1.2 mrg ptr = MEMSPACE_ALLOC (allocator_data->memspace, new_size, 652 1.1.1.2 mrg allocator_data->pinned); 653 1.1 mrg if (ptr == NULL) 654 1.1 mrg { 655 1.1 mrg #ifdef HAVE_SYNC_BUILTINS 656 1.1 mrg __atomic_add_fetch (&allocator_data->used_pool_size, -new_size, 657 1.1 mrg MEMMODEL_RELAXED); 658 1.1 mrg #else 659 1.1 mrg gomp_mutex_lock (&allocator_data->lock); 660 1.1 mrg allocator_data->used_pool_size -= new_size; 661 1.1 mrg gomp_mutex_unlock (&allocator_data->lock); 662 1.1 mrg #endif 663 1.1 mrg goto fail; 664 1.1 mrg } 665 1.1 mrg } 666 1.1 mrg else 667 1.1 mrg { 668 1.1.1.2 mrg #ifdef LIBGOMP_USE_LIBNUMA 669 1.1.1.2 mrg if (memkind == GOMP_MEMKIND_LIBNUMA) 670 1.1.1.2 mrg ptr = libnuma_data->numa_alloc_local (new_size); 671 1.1.1.2 mrg # ifdef LIBGOMP_USE_MEMKIND 672 1.1.1.2 mrg else 673 1.1.1.2 mrg # endif 674 1.1.1.2 mrg #endif 675 1.1.1.2 mrg #ifdef LIBGOMP_USE_MEMKIND 676 1.1.1.2 mrg if (memkind) 677 1.1.1.2 mrg { 678 1.1.1.2 mrg struct gomp_memkind_data *memkind_data = gomp_get_memkind (); 679 1.1.1.2 mrg void *kind = *memkind_data->kinds[memkind]; 680 1.1.1.2 mrg ptr = memkind_data->memkind_malloc (kind, new_size); 681 1.1.1.2 mrg } 682 1.1.1.2 mrg else 683 1.1.1.2 mrg #endif 684 1.1.1.2 mrg { 685 1.1.1.2 mrg omp_memspace_handle_t memspace; 686 1.1.1.2 mrg memspace = (allocator_data 687 1.1.1.2 mrg ? allocator_data->memspace 688 1.1.1.2 mrg : predefined_alloc_mapping[allocator]); 689 1.1.1.2 mrg ptr = MEMSPACE_ALLOC (memspace, new_size, 690 1.1.1.2 mrg allocator_data && allocator_data->pinned); 691 1.1.1.2 mrg } 692 1.1 mrg if (ptr == NULL) 693 1.1 mrg goto fail; 694 1.1 mrg } 695 1.1 mrg 696 1.1 mrg if (new_alignment > sizeof (void *)) 697 1.1 mrg ret = (void *) (((uintptr_t) ptr 698 1.1 mrg + sizeof (struct omp_mem_header) 699 1.1 mrg + new_alignment - sizeof (void *)) 700 1.1 mrg & ~(new_alignment - 1)); 701 1.1 mrg else 702 1.1 mrg ret = (char *) ptr + sizeof (struct omp_mem_header); 703 1.1 mrg ((struct omp_mem_header *) ret)[-1].ptr = ptr; 704 1.1 mrg ((struct omp_mem_header *) ret)[-1].size = new_size; 705 1.1 mrg ((struct omp_mem_header *) ret)[-1].allocator = allocator; 706 1.1 mrg return ret; 707 1.1 mrg 708 1.1.1.2 mrg fail:; 709 1.1.1.2 mrg int fallback = (allocator_data 710 1.1.1.2 mrg ? allocator_data->fallback 711 1.1.1.2 mrg : allocator == omp_default_mem_alloc 712 1.1.1.2 mrg ? omp_atv_null_fb 713 1.1.1.2 mrg : omp_atv_default_mem_fb); 714 1.1.1.2 mrg switch (fallback) 715 1.1.1.2 mrg { 716 1.1.1.2 mrg case omp_atv_default_mem_fb: 717 1.1.1.2 mrg allocator = omp_default_mem_alloc; 718 1.1.1.2 mrg goto retry; 719 1.1.1.2 mrg case omp_atv_null_fb: 720 1.1.1.2 mrg break; 721 1.1.1.2 mrg default: 722 1.1.1.2 mrg case omp_atv_abort_fb: 723 1.1.1.2 mrg gomp_fatal ("Out of memory allocating %lu bytes", 724 1.1.1.2 mrg (unsigned long) size); 725 1.1.1.2 mrg case omp_atv_allocator_fb: 726 1.1.1.2 mrg allocator = allocator_data->fb_data; 727 1.1.1.2 mrg goto retry; 728 1.1 mrg } 729 1.1 mrg return NULL; 730 1.1 mrg } 731 1.1 mrg 732 1.1 mrg ialias (omp_aligned_alloc) 733 1.1 mrg 734 1.1 mrg void * 735 1.1 mrg omp_alloc (size_t size, omp_allocator_handle_t allocator) 736 1.1 mrg { 737 1.1 mrg return ialias_call (omp_aligned_alloc) (1, size, allocator); 738 1.1 mrg } 739 1.1 mrg 740 1.1 mrg /* Like omp_aligned_alloc, but apply on top of that: 741 1.1 mrg "For allocations that arise from this ... the null_fb value of the 742 1.1 mrg fallback allocator trait behaves as if the abort_fb had been specified." */ 743 1.1 mrg 744 1.1 mrg void * 745 1.1 mrg GOMP_alloc (size_t alignment, size_t size, uintptr_t allocator) 746 1.1 mrg { 747 1.1 mrg void *ret 748 1.1 mrg = ialias_call (omp_aligned_alloc) (alignment, size, 749 1.1 mrg (omp_allocator_handle_t) allocator); 750 1.1 mrg if (__builtin_expect (ret == NULL, 0) && size) 751 1.1 mrg gomp_fatal ("Out of memory allocating %lu bytes", 752 1.1 mrg (unsigned long) size); 753 1.1 mrg return ret; 754 1.1 mrg } 755 1.1 mrg 756 1.1 mrg void 757 1.1 mrg omp_free (void *ptr, omp_allocator_handle_t allocator) 758 1.1 mrg { 759 1.1 mrg struct omp_mem_header *data; 760 1.1.1.2 mrg omp_memspace_handle_t memspace = omp_default_mem_space; 761 1.1.1.2 mrg int pinned = false; 762 1.1 mrg 763 1.1 mrg if (ptr == NULL) 764 1.1 mrg return; 765 1.1 mrg (void) allocator; 766 1.1 mrg data = &((struct omp_mem_header *) ptr)[-1]; 767 1.1 mrg if (data->allocator > omp_max_predefined_alloc) 768 1.1 mrg { 769 1.1 mrg struct omp_allocator_data *allocator_data 770 1.1 mrg = (struct omp_allocator_data *) (data->allocator); 771 1.1 mrg if (allocator_data->pool_size < ~(uintptr_t) 0) 772 1.1 mrg { 773 1.1 mrg #ifdef HAVE_SYNC_BUILTINS 774 1.1 mrg __atomic_add_fetch (&allocator_data->used_pool_size, -data->size, 775 1.1 mrg MEMMODEL_RELAXED); 776 1.1 mrg #else 777 1.1 mrg gomp_mutex_lock (&allocator_data->lock); 778 1.1 mrg allocator_data->used_pool_size -= data->size; 779 1.1 mrg gomp_mutex_unlock (&allocator_data->lock); 780 1.1 mrg #endif 781 1.1 mrg } 782 1.1.1.2 mrg #ifdef LIBGOMP_USE_LIBNUMA 783 1.1.1.2 mrg if (allocator_data->memkind == GOMP_MEMKIND_LIBNUMA) 784 1.1.1.2 mrg { 785 1.1.1.2 mrg libnuma_data->numa_free (data->ptr, data->size); 786 1.1.1.2 mrg return; 787 1.1.1.2 mrg } 788 1.1.1.2 mrg # ifdef LIBGOMP_USE_MEMKIND 789 1.1.1.2 mrg else 790 1.1.1.2 mrg # endif 791 1.1.1.2 mrg #endif 792 1.1.1.2 mrg #ifdef LIBGOMP_USE_MEMKIND 793 1.1.1.2 mrg if (allocator_data->memkind) 794 1.1.1.2 mrg { 795 1.1.1.2 mrg struct gomp_memkind_data *memkind_data = gomp_get_memkind (); 796 1.1.1.2 mrg void *kind = *memkind_data->kinds[allocator_data->memkind]; 797 1.1.1.2 mrg memkind_data->memkind_free (kind, data->ptr); 798 1.1.1.2 mrg return; 799 1.1.1.2 mrg } 800 1.1.1.2 mrg #endif 801 1.1.1.2 mrg 802 1.1.1.2 mrg memspace = allocator_data->memspace; 803 1.1.1.2 mrg pinned = allocator_data->pinned; 804 1.1.1.2 mrg } 805 1.1.1.2 mrg else 806 1.1.1.2 mrg { 807 1.1.1.2 mrg #ifdef LIBGOMP_USE_MEMKIND 808 1.1.1.2 mrg enum gomp_numa_memkind_kind memkind = GOMP_MEMKIND_NONE; 809 1.1.1.2 mrg if (data->allocator == omp_high_bw_mem_alloc) 810 1.1.1.2 mrg memkind = GOMP_MEMKIND_HBW_PREFERRED; 811 1.1.1.2 mrg else if (data->allocator == omp_large_cap_mem_alloc) 812 1.1.1.2 mrg memkind = GOMP_MEMKIND_DAX_KMEM_ALL; 813 1.1.1.2 mrg if (memkind) 814 1.1.1.2 mrg { 815 1.1.1.2 mrg struct gomp_memkind_data *memkind_data = gomp_get_memkind (); 816 1.1.1.2 mrg if (memkind_data->kinds[memkind]) 817 1.1.1.2 mrg { 818 1.1.1.2 mrg void *kind = *memkind_data->kinds[memkind]; 819 1.1.1.2 mrg memkind_data->memkind_free (kind, data->ptr); 820 1.1.1.2 mrg return; 821 1.1.1.2 mrg } 822 1.1.1.2 mrg } 823 1.1.1.2 mrg #endif 824 1.1.1.2 mrg 825 1.1.1.2 mrg memspace = predefined_alloc_mapping[data->allocator]; 826 1.1 mrg } 827 1.1.1.2 mrg 828 1.1.1.2 mrg MEMSPACE_FREE (memspace, data->ptr, data->size, pinned); 829 1.1 mrg } 830 1.1 mrg 831 1.1 mrg ialias (omp_free) 832 1.1 mrg 833 1.1 mrg void 834 1.1 mrg GOMP_free (void *ptr, uintptr_t allocator) 835 1.1 mrg { 836 1.1 mrg return ialias_call (omp_free) (ptr, (omp_allocator_handle_t) allocator); 837 1.1 mrg } 838 1.1 mrg 839 1.1 mrg void * 840 1.1 mrg omp_aligned_calloc (size_t alignment, size_t nmemb, size_t size, 841 1.1 mrg omp_allocator_handle_t allocator) 842 1.1 mrg { 843 1.1 mrg struct omp_allocator_data *allocator_data; 844 1.1 mrg size_t new_size, size_temp, new_alignment; 845 1.1 mrg void *ptr, *ret; 846 1.1.1.2 mrg #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA) 847 1.1.1.2 mrg enum gomp_numa_memkind_kind memkind; 848 1.1.1.2 mrg #endif 849 1.1 mrg 850 1.1 mrg if (__builtin_expect (size == 0 || nmemb == 0, 0)) 851 1.1 mrg return NULL; 852 1.1 mrg 853 1.1 mrg retry: 854 1.1 mrg new_alignment = alignment; 855 1.1 mrg if (allocator == omp_null_allocator) 856 1.1 mrg { 857 1.1 mrg struct gomp_thread *thr = gomp_thread (); 858 1.1 mrg if (thr->ts.def_allocator == omp_null_allocator) 859 1.1 mrg thr->ts.def_allocator = gomp_def_allocator; 860 1.1 mrg allocator = (omp_allocator_handle_t) thr->ts.def_allocator; 861 1.1 mrg } 862 1.1 mrg 863 1.1 mrg if (allocator > omp_max_predefined_alloc) 864 1.1 mrg { 865 1.1 mrg allocator_data = (struct omp_allocator_data *) allocator; 866 1.1 mrg if (new_alignment < allocator_data->alignment) 867 1.1 mrg new_alignment = allocator_data->alignment; 868 1.1.1.2 mrg #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA) 869 1.1.1.2 mrg memkind = allocator_data->memkind; 870 1.1.1.2 mrg #endif 871 1.1 mrg } 872 1.1 mrg else 873 1.1 mrg { 874 1.1 mrg allocator_data = NULL; 875 1.1 mrg if (new_alignment < sizeof (void *)) 876 1.1 mrg new_alignment = sizeof (void *); 877 1.1.1.2 mrg #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA) 878 1.1.1.2 mrg memkind = GOMP_MEMKIND_NONE; 879 1.1.1.2 mrg #endif 880 1.1.1.2 mrg #ifdef LIBGOMP_USE_MEMKIND 881 1.1.1.2 mrg if (allocator == omp_high_bw_mem_alloc) 882 1.1.1.2 mrg memkind = GOMP_MEMKIND_HBW_PREFERRED; 883 1.1.1.2 mrg else if (allocator == omp_large_cap_mem_alloc) 884 1.1.1.2 mrg memkind = GOMP_MEMKIND_DAX_KMEM_ALL; 885 1.1.1.2 mrg if (memkind) 886 1.1.1.2 mrg { 887 1.1.1.2 mrg struct gomp_memkind_data *memkind_data = gomp_get_memkind (); 888 1.1.1.2 mrg if (!memkind_data->kinds[memkind]) 889 1.1.1.2 mrg memkind = GOMP_MEMKIND_NONE; 890 1.1.1.2 mrg } 891 1.1.1.2 mrg #endif 892 1.1 mrg } 893 1.1 mrg 894 1.1 mrg new_size = sizeof (struct omp_mem_header); 895 1.1 mrg if (new_alignment > sizeof (void *)) 896 1.1 mrg new_size += new_alignment - sizeof (void *); 897 1.1 mrg if (__builtin_mul_overflow (size, nmemb, &size_temp)) 898 1.1 mrg goto fail; 899 1.1 mrg if (__builtin_add_overflow (size_temp, new_size, &new_size)) 900 1.1 mrg goto fail; 901 1.1.1.2 mrg #ifdef OMP_LOW_LAT_MEM_ALLOC_INVALID 902 1.1.1.2 mrg if (allocator == omp_low_lat_mem_alloc) 903 1.1.1.2 mrg goto fail; 904 1.1.1.2 mrg #endif 905 1.1 mrg 906 1.1 mrg if (__builtin_expect (allocator_data 907 1.1 mrg && allocator_data->pool_size < ~(uintptr_t) 0, 0)) 908 1.1 mrg { 909 1.1 mrg uintptr_t used_pool_size; 910 1.1 mrg if (new_size > allocator_data->pool_size) 911 1.1 mrg goto fail; 912 1.1 mrg #ifdef HAVE_SYNC_BUILTINS 913 1.1 mrg used_pool_size = __atomic_load_n (&allocator_data->used_pool_size, 914 1.1 mrg MEMMODEL_RELAXED); 915 1.1 mrg do 916 1.1 mrg { 917 1.1 mrg uintptr_t new_pool_size; 918 1.1 mrg if (__builtin_add_overflow (used_pool_size, new_size, 919 1.1 mrg &new_pool_size) 920 1.1 mrg || new_pool_size > allocator_data->pool_size) 921 1.1 mrg goto fail; 922 1.1 mrg if (__atomic_compare_exchange_n (&allocator_data->used_pool_size, 923 1.1 mrg &used_pool_size, new_pool_size, 924 1.1 mrg true, MEMMODEL_RELAXED, 925 1.1 mrg MEMMODEL_RELAXED)) 926 1.1 mrg break; 927 1.1 mrg } 928 1.1 mrg while (1); 929 1.1 mrg #else 930 1.1 mrg gomp_mutex_lock (&allocator_data->lock); 931 1.1 mrg if (__builtin_add_overflow (allocator_data->used_pool_size, new_size, 932 1.1 mrg &used_pool_size) 933 1.1 mrg || used_pool_size > allocator_data->pool_size) 934 1.1 mrg { 935 1.1 mrg gomp_mutex_unlock (&allocator_data->lock); 936 1.1 mrg goto fail; 937 1.1 mrg } 938 1.1 mrg allocator_data->used_pool_size = used_pool_size; 939 1.1 mrg gomp_mutex_unlock (&allocator_data->lock); 940 1.1 mrg #endif 941 1.1.1.2 mrg #ifdef LIBGOMP_USE_LIBNUMA 942 1.1.1.2 mrg if (memkind == GOMP_MEMKIND_LIBNUMA) 943 1.1.1.2 mrg /* numa_alloc_local uses mmap with MAP_ANONYMOUS, returning 944 1.1.1.2 mrg memory that is initialized to zero. */ 945 1.1.1.2 mrg ptr = libnuma_data->numa_alloc_local (new_size); 946 1.1.1.2 mrg # ifdef LIBGOMP_USE_MEMKIND 947 1.1.1.2 mrg else 948 1.1.1.2 mrg # endif 949 1.1.1.2 mrg #endif 950 1.1.1.2 mrg #ifdef LIBGOMP_USE_MEMKIND 951 1.1.1.2 mrg if (memkind) 952 1.1.1.2 mrg { 953 1.1.1.2 mrg struct gomp_memkind_data *memkind_data = gomp_get_memkind (); 954 1.1.1.2 mrg void *kind = *memkind_data->kinds[memkind]; 955 1.1.1.2 mrg ptr = memkind_data->memkind_calloc (kind, 1, new_size); 956 1.1.1.2 mrg } 957 1.1.1.2 mrg else 958 1.1.1.2 mrg #endif 959 1.1.1.2 mrg ptr = MEMSPACE_CALLOC (allocator_data->memspace, new_size, 960 1.1.1.2 mrg allocator_data->pinned); 961 1.1 mrg if (ptr == NULL) 962 1.1 mrg { 963 1.1 mrg #ifdef HAVE_SYNC_BUILTINS 964 1.1 mrg __atomic_add_fetch (&allocator_data->used_pool_size, -new_size, 965 1.1 mrg MEMMODEL_RELAXED); 966 1.1 mrg #else 967 1.1 mrg gomp_mutex_lock (&allocator_data->lock); 968 1.1 mrg allocator_data->used_pool_size -= new_size; 969 1.1 mrg gomp_mutex_unlock (&allocator_data->lock); 970 1.1 mrg #endif 971 1.1 mrg goto fail; 972 1.1 mrg } 973 1.1 mrg } 974 1.1 mrg else 975 1.1 mrg { 976 1.1.1.2 mrg #ifdef LIBGOMP_USE_LIBNUMA 977 1.1.1.2 mrg if (memkind == GOMP_MEMKIND_LIBNUMA) 978 1.1.1.2 mrg /* numa_alloc_local uses mmap with MAP_ANONYMOUS, returning 979 1.1.1.2 mrg memory that is initialized to zero. */ 980 1.1.1.2 mrg ptr = libnuma_data->numa_alloc_local (new_size); 981 1.1.1.2 mrg # ifdef LIBGOMP_USE_MEMKIND 982 1.1.1.2 mrg else 983 1.1.1.2 mrg # endif 984 1.1.1.2 mrg #endif 985 1.1.1.2 mrg #ifdef LIBGOMP_USE_MEMKIND 986 1.1.1.2 mrg if (memkind) 987 1.1.1.2 mrg { 988 1.1.1.2 mrg struct gomp_memkind_data *memkind_data = gomp_get_memkind (); 989 1.1.1.2 mrg void *kind = *memkind_data->kinds[memkind]; 990 1.1.1.2 mrg ptr = memkind_data->memkind_calloc (kind, 1, new_size); 991 1.1.1.2 mrg } 992 1.1.1.2 mrg else 993 1.1.1.2 mrg #endif 994 1.1.1.2 mrg { 995 1.1.1.2 mrg omp_memspace_handle_t memspace; 996 1.1.1.2 mrg memspace = (allocator_data 997 1.1.1.2 mrg ? allocator_data->memspace 998 1.1.1.2 mrg : predefined_alloc_mapping[allocator]); 999 1.1.1.2 mrg ptr = MEMSPACE_CALLOC (memspace, new_size, 1000 1.1.1.2 mrg allocator_data && allocator_data->pinned); 1001 1.1.1.2 mrg } 1002 1.1 mrg if (ptr == NULL) 1003 1.1 mrg goto fail; 1004 1.1 mrg } 1005 1.1 mrg 1006 1.1 mrg if (new_alignment > sizeof (void *)) 1007 1.1 mrg ret = (void *) (((uintptr_t) ptr 1008 1.1 mrg + sizeof (struct omp_mem_header) 1009 1.1 mrg + new_alignment - sizeof (void *)) 1010 1.1 mrg & ~(new_alignment - 1)); 1011 1.1 mrg else 1012 1.1 mrg ret = (char *) ptr + sizeof (struct omp_mem_header); 1013 1.1 mrg ((struct omp_mem_header *) ret)[-1].ptr = ptr; 1014 1.1 mrg ((struct omp_mem_header *) ret)[-1].size = new_size; 1015 1.1 mrg ((struct omp_mem_header *) ret)[-1].allocator = allocator; 1016 1.1 mrg return ret; 1017 1.1 mrg 1018 1.1.1.2 mrg fail:; 1019 1.1.1.2 mrg int fallback = (allocator_data 1020 1.1.1.2 mrg ? allocator_data->fallback 1021 1.1.1.2 mrg : allocator == omp_default_mem_alloc 1022 1.1.1.2 mrg ? omp_atv_null_fb 1023 1.1.1.2 mrg : omp_atv_default_mem_fb); 1024 1.1.1.2 mrg switch (fallback) 1025 1.1.1.2 mrg { 1026 1.1.1.2 mrg case omp_atv_default_mem_fb: 1027 1.1.1.2 mrg allocator = omp_default_mem_alloc; 1028 1.1.1.2 mrg goto retry; 1029 1.1.1.2 mrg case omp_atv_null_fb: 1030 1.1.1.2 mrg break; 1031 1.1.1.2 mrg default: 1032 1.1.1.2 mrg case omp_atv_abort_fb: 1033 1.1.1.2 mrg gomp_fatal ("Out of memory allocating %lu bytes", 1034 1.1.1.2 mrg (unsigned long) (size * nmemb)); 1035 1.1.1.2 mrg case omp_atv_allocator_fb: 1036 1.1.1.2 mrg allocator = allocator_data->fb_data; 1037 1.1.1.2 mrg goto retry; 1038 1.1 mrg } 1039 1.1 mrg return NULL; 1040 1.1 mrg } 1041 1.1 mrg 1042 1.1 mrg ialias (omp_aligned_calloc) 1043 1.1 mrg 1044 1.1 mrg void * 1045 1.1 mrg omp_calloc (size_t nmemb, size_t size, omp_allocator_handle_t allocator) 1046 1.1 mrg { 1047 1.1 mrg return ialias_call (omp_aligned_calloc) (1, nmemb, size, allocator); 1048 1.1 mrg } 1049 1.1 mrg 1050 1.1 mrg void * 1051 1.1 mrg omp_realloc (void *ptr, size_t size, omp_allocator_handle_t allocator, 1052 1.1 mrg omp_allocator_handle_t free_allocator) 1053 1.1 mrg { 1054 1.1 mrg struct omp_allocator_data *allocator_data, *free_allocator_data; 1055 1.1 mrg size_t new_size, old_size, new_alignment, old_alignment; 1056 1.1 mrg void *new_ptr, *ret; 1057 1.1 mrg struct omp_mem_header *data; 1058 1.1.1.2 mrg #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA) 1059 1.1.1.2 mrg enum gomp_numa_memkind_kind memkind, free_memkind; 1060 1.1.1.2 mrg #endif 1061 1.1 mrg 1062 1.1 mrg if (__builtin_expect (ptr == NULL, 0)) 1063 1.1 mrg return ialias_call (omp_aligned_alloc) (1, size, allocator); 1064 1.1 mrg 1065 1.1 mrg if (__builtin_expect (size == 0, 0)) 1066 1.1 mrg { 1067 1.1 mrg ialias_call (omp_free) (ptr, free_allocator); 1068 1.1 mrg return NULL; 1069 1.1 mrg } 1070 1.1 mrg 1071 1.1 mrg data = &((struct omp_mem_header *) ptr)[-1]; 1072 1.1 mrg free_allocator = data->allocator; 1073 1.1 mrg 1074 1.1 mrg retry: 1075 1.1 mrg new_alignment = sizeof (void *); 1076 1.1 mrg if (allocator == omp_null_allocator) 1077 1.1 mrg allocator = free_allocator; 1078 1.1 mrg 1079 1.1 mrg if (allocator > omp_max_predefined_alloc) 1080 1.1 mrg { 1081 1.1 mrg allocator_data = (struct omp_allocator_data *) allocator; 1082 1.1 mrg if (new_alignment < allocator_data->alignment) 1083 1.1 mrg new_alignment = allocator_data->alignment; 1084 1.1.1.2 mrg #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA) 1085 1.1.1.2 mrg memkind = allocator_data->memkind; 1086 1.1.1.2 mrg #endif 1087 1.1 mrg } 1088 1.1 mrg else 1089 1.1.1.2 mrg { 1090 1.1.1.2 mrg allocator_data = NULL; 1091 1.1.1.2 mrg #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA) 1092 1.1.1.2 mrg memkind = GOMP_MEMKIND_NONE; 1093 1.1.1.2 mrg #endif 1094 1.1.1.2 mrg #ifdef LIBGOMP_USE_MEMKIND 1095 1.1.1.2 mrg if (allocator == omp_high_bw_mem_alloc) 1096 1.1.1.2 mrg memkind = GOMP_MEMKIND_HBW_PREFERRED; 1097 1.1.1.2 mrg else if (allocator == omp_large_cap_mem_alloc) 1098 1.1.1.2 mrg memkind = GOMP_MEMKIND_DAX_KMEM_ALL; 1099 1.1.1.2 mrg if (memkind) 1100 1.1.1.2 mrg { 1101 1.1.1.2 mrg struct gomp_memkind_data *memkind_data = gomp_get_memkind (); 1102 1.1.1.2 mrg if (!memkind_data->kinds[memkind]) 1103 1.1.1.2 mrg memkind = GOMP_MEMKIND_NONE; 1104 1.1.1.2 mrg } 1105 1.1.1.2 mrg #endif 1106 1.1.1.2 mrg } 1107 1.1 mrg if (free_allocator > omp_max_predefined_alloc) 1108 1.1.1.2 mrg { 1109 1.1.1.2 mrg free_allocator_data = (struct omp_allocator_data *) free_allocator; 1110 1.1.1.2 mrg #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA) 1111 1.1.1.2 mrg free_memkind = free_allocator_data->memkind; 1112 1.1.1.2 mrg #endif 1113 1.1.1.2 mrg } 1114 1.1 mrg else 1115 1.1.1.2 mrg { 1116 1.1.1.2 mrg free_allocator_data = NULL; 1117 1.1.1.2 mrg #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA) 1118 1.1.1.2 mrg free_memkind = GOMP_MEMKIND_NONE; 1119 1.1.1.2 mrg #endif 1120 1.1.1.2 mrg #ifdef LIBGOMP_USE_MEMKIND 1121 1.1.1.2 mrg if (free_allocator == omp_high_bw_mem_alloc) 1122 1.1.1.2 mrg free_memkind = GOMP_MEMKIND_HBW_PREFERRED; 1123 1.1.1.2 mrg else if (free_allocator == omp_large_cap_mem_alloc) 1124 1.1.1.2 mrg free_memkind = GOMP_MEMKIND_DAX_KMEM_ALL; 1125 1.1.1.2 mrg if (free_memkind) 1126 1.1.1.2 mrg { 1127 1.1.1.2 mrg struct gomp_memkind_data *memkind_data = gomp_get_memkind (); 1128 1.1.1.2 mrg if (!memkind_data->kinds[free_memkind]) 1129 1.1.1.2 mrg free_memkind = GOMP_MEMKIND_NONE; 1130 1.1.1.2 mrg } 1131 1.1.1.2 mrg #endif 1132 1.1.1.2 mrg } 1133 1.1 mrg old_alignment = (uintptr_t) ptr - (uintptr_t) (data->ptr); 1134 1.1 mrg 1135 1.1 mrg new_size = sizeof (struct omp_mem_header); 1136 1.1 mrg if (new_alignment > sizeof (void *)) 1137 1.1 mrg new_size += new_alignment - sizeof (void *); 1138 1.1 mrg if (__builtin_add_overflow (size, new_size, &new_size)) 1139 1.1 mrg goto fail; 1140 1.1 mrg old_size = data->size; 1141 1.1.1.2 mrg #ifdef OMP_LOW_LAT_MEM_ALLOC_INVALID 1142 1.1.1.2 mrg if (allocator == omp_low_lat_mem_alloc) 1143 1.1.1.2 mrg goto fail; 1144 1.1.1.2 mrg #endif 1145 1.1 mrg 1146 1.1 mrg if (__builtin_expect (allocator_data 1147 1.1 mrg && allocator_data->pool_size < ~(uintptr_t) 0, 0)) 1148 1.1 mrg { 1149 1.1 mrg uintptr_t used_pool_size; 1150 1.1 mrg size_t prev_size = 0; 1151 1.1 mrg /* Check if we can use realloc. Don't use it if extra alignment 1152 1.1 mrg was used previously or newly, because realloc might return a pointer 1153 1.1 mrg with different alignment and then we'd need to memmove the data 1154 1.1 mrg again. */ 1155 1.1 mrg if (free_allocator_data 1156 1.1 mrg && free_allocator_data == allocator_data 1157 1.1 mrg && new_alignment == sizeof (void *) 1158 1.1 mrg && old_alignment == sizeof (struct omp_mem_header)) 1159 1.1 mrg prev_size = old_size; 1160 1.1 mrg if (new_size > prev_size 1161 1.1 mrg && new_size - prev_size > allocator_data->pool_size) 1162 1.1 mrg goto fail; 1163 1.1 mrg #ifdef HAVE_SYNC_BUILTINS 1164 1.1 mrg used_pool_size = __atomic_load_n (&allocator_data->used_pool_size, 1165 1.1 mrg MEMMODEL_RELAXED); 1166 1.1 mrg do 1167 1.1 mrg { 1168 1.1 mrg uintptr_t new_pool_size; 1169 1.1 mrg if (new_size > prev_size) 1170 1.1 mrg { 1171 1.1 mrg if (__builtin_add_overflow (used_pool_size, new_size - prev_size, 1172 1.1 mrg &new_pool_size) 1173 1.1 mrg || new_pool_size > allocator_data->pool_size) 1174 1.1 mrg goto fail; 1175 1.1 mrg } 1176 1.1 mrg else 1177 1.1 mrg new_pool_size = used_pool_size + new_size - prev_size; 1178 1.1 mrg if (__atomic_compare_exchange_n (&allocator_data->used_pool_size, 1179 1.1 mrg &used_pool_size, new_pool_size, 1180 1.1 mrg true, MEMMODEL_RELAXED, 1181 1.1 mrg MEMMODEL_RELAXED)) 1182 1.1 mrg break; 1183 1.1 mrg } 1184 1.1 mrg while (1); 1185 1.1 mrg #else 1186 1.1 mrg gomp_mutex_lock (&allocator_data->lock); 1187 1.1 mrg if (new_size > prev_size) 1188 1.1 mrg { 1189 1.1 mrg if (__builtin_add_overflow (allocator_data->used_pool_size, 1190 1.1 mrg new_size - prev_size, 1191 1.1 mrg &used_pool_size) 1192 1.1 mrg || used_pool_size > allocator_data->pool_size) 1193 1.1 mrg { 1194 1.1 mrg gomp_mutex_unlock (&allocator_data->lock); 1195 1.1 mrg goto fail; 1196 1.1 mrg } 1197 1.1 mrg } 1198 1.1 mrg else 1199 1.1 mrg used_pool_size = (allocator_data->used_pool_size 1200 1.1 mrg + new_size - prev_size); 1201 1.1 mrg allocator_data->used_pool_size = used_pool_size; 1202 1.1 mrg gomp_mutex_unlock (&allocator_data->lock); 1203 1.1 mrg #endif 1204 1.1.1.2 mrg #ifdef LIBGOMP_USE_LIBNUMA 1205 1.1.1.2 mrg if (memkind == GOMP_MEMKIND_LIBNUMA) 1206 1.1.1.2 mrg { 1207 1.1.1.2 mrg if (prev_size) 1208 1.1.1.2 mrg new_ptr = libnuma_data->numa_realloc (data->ptr, data->size, 1209 1.1.1.2 mrg new_size); 1210 1.1.1.2 mrg else 1211 1.1.1.2 mrg new_ptr = libnuma_data->numa_alloc_local (new_size); 1212 1.1.1.2 mrg } 1213 1.1.1.2 mrg # ifdef LIBGOMP_USE_MEMKIND 1214 1.1.1.2 mrg else 1215 1.1.1.2 mrg # endif 1216 1.1.1.2 mrg #endif 1217 1.1.1.2 mrg #ifdef LIBGOMP_USE_MEMKIND 1218 1.1.1.2 mrg if (memkind) 1219 1.1.1.2 mrg { 1220 1.1.1.2 mrg struct gomp_memkind_data *memkind_data = gomp_get_memkind (); 1221 1.1.1.2 mrg void *kind = *memkind_data->kinds[memkind]; 1222 1.1.1.2 mrg if (prev_size) 1223 1.1.1.2 mrg new_ptr = memkind_data->memkind_realloc (kind, data->ptr, 1224 1.1.1.2 mrg new_size); 1225 1.1.1.2 mrg else 1226 1.1.1.2 mrg new_ptr = memkind_data->memkind_malloc (kind, new_size); 1227 1.1.1.2 mrg } 1228 1.1.1.2 mrg else 1229 1.1.1.2 mrg #endif 1230 1.1 mrg if (prev_size) 1231 1.1.1.2 mrg new_ptr = MEMSPACE_REALLOC (allocator_data->memspace, data->ptr, 1232 1.1.1.2 mrg data->size, new_size, 1233 1.1.1.2 mrg (free_allocator_data 1234 1.1.1.2 mrg && free_allocator_data->pinned), 1235 1.1.1.2 mrg allocator_data->pinned); 1236 1.1 mrg else 1237 1.1.1.2 mrg new_ptr = MEMSPACE_ALLOC (allocator_data->memspace, new_size, 1238 1.1.1.2 mrg allocator_data->pinned); 1239 1.1 mrg if (new_ptr == NULL) 1240 1.1 mrg { 1241 1.1 mrg #ifdef HAVE_SYNC_BUILTINS 1242 1.1 mrg __atomic_add_fetch (&allocator_data->used_pool_size, 1243 1.1 mrg prev_size - new_size, 1244 1.1 mrg MEMMODEL_RELAXED); 1245 1.1 mrg #else 1246 1.1 mrg gomp_mutex_lock (&allocator_data->lock); 1247 1.1 mrg allocator_data->used_pool_size -= new_size - prev_size; 1248 1.1 mrg gomp_mutex_unlock (&allocator_data->lock); 1249 1.1 mrg #endif 1250 1.1 mrg goto fail; 1251 1.1 mrg } 1252 1.1 mrg else if (prev_size) 1253 1.1 mrg { 1254 1.1 mrg ret = (char *) new_ptr + sizeof (struct omp_mem_header); 1255 1.1 mrg ((struct omp_mem_header *) ret)[-1].ptr = new_ptr; 1256 1.1 mrg ((struct omp_mem_header *) ret)[-1].size = new_size; 1257 1.1 mrg ((struct omp_mem_header *) ret)[-1].allocator = allocator; 1258 1.1 mrg return ret; 1259 1.1 mrg } 1260 1.1 mrg } 1261 1.1 mrg else if (new_alignment == sizeof (void *) 1262 1.1 mrg && old_alignment == sizeof (struct omp_mem_header) 1263 1.1.1.2 mrg #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA) 1264 1.1.1.2 mrg && memkind == free_memkind 1265 1.1.1.2 mrg #endif 1266 1.1 mrg && (free_allocator_data == NULL 1267 1.1 mrg || free_allocator_data->pool_size == ~(uintptr_t) 0)) 1268 1.1 mrg { 1269 1.1.1.2 mrg #ifdef LIBGOMP_USE_LIBNUMA 1270 1.1.1.2 mrg if (memkind == GOMP_MEMKIND_LIBNUMA) 1271 1.1.1.2 mrg new_ptr = libnuma_data->numa_realloc (data->ptr, data->size, new_size); 1272 1.1.1.2 mrg # ifdef LIBGOMP_USE_MEMKIND 1273 1.1.1.2 mrg else 1274 1.1.1.2 mrg # endif 1275 1.1.1.2 mrg #endif 1276 1.1.1.2 mrg #ifdef LIBGOMP_USE_MEMKIND 1277 1.1.1.2 mrg if (memkind) 1278 1.1.1.2 mrg { 1279 1.1.1.2 mrg struct gomp_memkind_data *memkind_data = gomp_get_memkind (); 1280 1.1.1.2 mrg void *kind = *memkind_data->kinds[memkind]; 1281 1.1.1.2 mrg new_ptr = memkind_data->memkind_realloc (kind, data->ptr, 1282 1.1.1.2 mrg new_size); 1283 1.1.1.2 mrg } 1284 1.1.1.2 mrg else 1285 1.1.1.2 mrg #endif 1286 1.1.1.2 mrg { 1287 1.1.1.2 mrg omp_memspace_handle_t memspace; 1288 1.1.1.2 mrg memspace = (allocator_data 1289 1.1.1.2 mrg ? allocator_data->memspace 1290 1.1.1.2 mrg : predefined_alloc_mapping[allocator]); 1291 1.1.1.2 mrg new_ptr = MEMSPACE_REALLOC (memspace, data->ptr, data->size, new_size, 1292 1.1.1.2 mrg (free_allocator_data 1293 1.1.1.2 mrg && free_allocator_data->pinned), 1294 1.1.1.2 mrg allocator_data && allocator_data->pinned); 1295 1.1.1.2 mrg } 1296 1.1 mrg if (new_ptr == NULL) 1297 1.1 mrg goto fail; 1298 1.1.1.2 mrg 1299 1.1 mrg ret = (char *) new_ptr + sizeof (struct omp_mem_header); 1300 1.1 mrg ((struct omp_mem_header *) ret)[-1].ptr = new_ptr; 1301 1.1 mrg ((struct omp_mem_header *) ret)[-1].size = new_size; 1302 1.1 mrg ((struct omp_mem_header *) ret)[-1].allocator = allocator; 1303 1.1 mrg return ret; 1304 1.1 mrg } 1305 1.1 mrg else 1306 1.1 mrg { 1307 1.1.1.2 mrg #ifdef LIBGOMP_USE_LIBNUMA 1308 1.1.1.2 mrg if (memkind == GOMP_MEMKIND_LIBNUMA) 1309 1.1.1.2 mrg new_ptr = libnuma_data->numa_alloc_local (new_size); 1310 1.1.1.2 mrg # ifdef LIBGOMP_USE_MEMKIND 1311 1.1.1.2 mrg else 1312 1.1.1.2 mrg # endif 1313 1.1.1.2 mrg #endif 1314 1.1.1.2 mrg #ifdef LIBGOMP_USE_MEMKIND 1315 1.1.1.2 mrg if (memkind) 1316 1.1.1.2 mrg { 1317 1.1.1.2 mrg struct gomp_memkind_data *memkind_data = gomp_get_memkind (); 1318 1.1.1.2 mrg void *kind = *memkind_data->kinds[memkind]; 1319 1.1.1.2 mrg new_ptr = memkind_data->memkind_malloc (kind, new_size); 1320 1.1.1.2 mrg } 1321 1.1.1.2 mrg else 1322 1.1.1.2 mrg #endif 1323 1.1.1.2 mrg { 1324 1.1.1.2 mrg omp_memspace_handle_t memspace; 1325 1.1.1.2 mrg memspace = (allocator_data 1326 1.1.1.2 mrg ? allocator_data->memspace 1327 1.1.1.2 mrg : predefined_alloc_mapping[allocator]); 1328 1.1.1.2 mrg new_ptr = MEMSPACE_ALLOC (memspace, new_size, 1329 1.1.1.2 mrg allocator_data && allocator_data->pinned); 1330 1.1.1.2 mrg } 1331 1.1 mrg if (new_ptr == NULL) 1332 1.1 mrg goto fail; 1333 1.1 mrg } 1334 1.1 mrg 1335 1.1 mrg if (new_alignment > sizeof (void *)) 1336 1.1 mrg ret = (void *) (((uintptr_t) new_ptr 1337 1.1 mrg + sizeof (struct omp_mem_header) 1338 1.1 mrg + new_alignment - sizeof (void *)) 1339 1.1 mrg & ~(new_alignment - 1)); 1340 1.1 mrg else 1341 1.1 mrg ret = (char *) new_ptr + sizeof (struct omp_mem_header); 1342 1.1 mrg ((struct omp_mem_header *) ret)[-1].ptr = new_ptr; 1343 1.1 mrg ((struct omp_mem_header *) ret)[-1].size = new_size; 1344 1.1 mrg ((struct omp_mem_header *) ret)[-1].allocator = allocator; 1345 1.1 mrg if (old_size - old_alignment < size) 1346 1.1 mrg size = old_size - old_alignment; 1347 1.1 mrg memcpy (ret, ptr, size); 1348 1.1 mrg if (__builtin_expect (free_allocator_data 1349 1.1 mrg && free_allocator_data->pool_size < ~(uintptr_t) 0, 0)) 1350 1.1 mrg { 1351 1.1 mrg #ifdef HAVE_SYNC_BUILTINS 1352 1.1 mrg __atomic_add_fetch (&free_allocator_data->used_pool_size, -data->size, 1353 1.1 mrg MEMMODEL_RELAXED); 1354 1.1 mrg #else 1355 1.1 mrg gomp_mutex_lock (&free_allocator_data->lock); 1356 1.1 mrg free_allocator_data->used_pool_size -= data->size; 1357 1.1 mrg gomp_mutex_unlock (&free_allocator_data->lock); 1358 1.1 mrg #endif 1359 1.1 mrg } 1360 1.1.1.2 mrg #ifdef LIBGOMP_USE_LIBNUMA 1361 1.1.1.2 mrg if (free_memkind == GOMP_MEMKIND_LIBNUMA) 1362 1.1.1.2 mrg { 1363 1.1.1.2 mrg libnuma_data->numa_free (data->ptr, data->size); 1364 1.1.1.2 mrg return ret; 1365 1.1.1.2 mrg } 1366 1.1.1.2 mrg # ifdef LIBGOMP_USE_MEMKIND 1367 1.1.1.2 mrg else 1368 1.1.1.2 mrg # endif 1369 1.1.1.2 mrg #endif 1370 1.1.1.2 mrg #ifdef LIBGOMP_USE_MEMKIND 1371 1.1.1.2 mrg if (free_memkind) 1372 1.1.1.2 mrg { 1373 1.1.1.2 mrg struct gomp_memkind_data *memkind_data = gomp_get_memkind (); 1374 1.1.1.2 mrg void *kind = *memkind_data->kinds[free_memkind]; 1375 1.1.1.2 mrg memkind_data->memkind_free (kind, data->ptr); 1376 1.1.1.2 mrg return ret; 1377 1.1.1.2 mrg } 1378 1.1.1.2 mrg #endif 1379 1.1.1.2 mrg { 1380 1.1.1.2 mrg omp_memspace_handle_t was_memspace; 1381 1.1.1.2 mrg was_memspace = (free_allocator_data 1382 1.1.1.2 mrg ? free_allocator_data->memspace 1383 1.1.1.2 mrg : predefined_alloc_mapping[free_allocator]); 1384 1.1.1.2 mrg int was_pinned = (free_allocator_data && free_allocator_data->pinned); 1385 1.1.1.2 mrg MEMSPACE_FREE (was_memspace, data->ptr, data->size, was_pinned); 1386 1.1.1.2 mrg } 1387 1.1 mrg return ret; 1388 1.1 mrg 1389 1.1.1.2 mrg fail:; 1390 1.1.1.2 mrg int fallback = (allocator_data 1391 1.1.1.2 mrg ? allocator_data->fallback 1392 1.1.1.2 mrg : allocator == omp_default_mem_alloc 1393 1.1.1.2 mrg ? omp_atv_null_fb 1394 1.1.1.2 mrg : omp_atv_default_mem_fb); 1395 1.1.1.2 mrg switch (fallback) 1396 1.1.1.2 mrg { 1397 1.1.1.2 mrg case omp_atv_default_mem_fb: 1398 1.1.1.2 mrg allocator = omp_default_mem_alloc; 1399 1.1.1.2 mrg goto retry; 1400 1.1.1.2 mrg case omp_atv_null_fb: 1401 1.1.1.2 mrg break; 1402 1.1.1.2 mrg default: 1403 1.1.1.2 mrg case omp_atv_abort_fb: 1404 1.1.1.2 mrg gomp_fatal ("Out of memory allocating %lu bytes", 1405 1.1.1.2 mrg (unsigned long) size); 1406 1.1.1.2 mrg case omp_atv_allocator_fb: 1407 1.1.1.2 mrg allocator = allocator_data->fb_data; 1408 1.1.1.2 mrg goto retry; 1409 1.1 mrg } 1410 1.1 mrg return NULL; 1411 1.1 mrg } 1412