17cc577a4SJonathan Peyton /* 2de4749b7SJonathan Peyton * kmp_alloc.cpp -- private/shared dynamic memory allocation and management 37cc577a4SJonathan Peyton */ 47cc577a4SJonathan Peyton 57cc577a4SJonathan Peyton //===----------------------------------------------------------------------===// 67cc577a4SJonathan Peyton // 757b08b09SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 857b08b09SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 957b08b09SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 107cc577a4SJonathan Peyton // 117cc577a4SJonathan Peyton //===----------------------------------------------------------------------===// 127cc577a4SJonathan Peyton 137cc577a4SJonathan Peyton #include "kmp.h" 147cc577a4SJonathan Peyton #include "kmp_io.h" 153041982dSJonathan Peyton #include "kmp_wrapper_malloc.h" 167cc577a4SJonathan Peyton 177cc577a4SJonathan Peyton // Disable bget when it is not used 187cc577a4SJonathan Peyton #if KMP_USE_BGET 197cc577a4SJonathan Peyton 207cc577a4SJonathan Peyton /* Thread private buffer management code */ 217cc577a4SJonathan Peyton 227cc577a4SJonathan Peyton typedef int (*bget_compact_t)(size_t, int); 237cc577a4SJonathan Peyton typedef void *(*bget_acquire_t)(size_t); 247cc577a4SJonathan Peyton typedef void (*bget_release_t)(void *); 257cc577a4SJonathan Peyton 267cc577a4SJonathan Peyton /* NOTE: bufsize must be a signed datatype */ 277cc577a4SJonathan Peyton 287cc577a4SJonathan Peyton #if KMP_OS_WINDOWS 297cc577a4SJonathan Peyton #if KMP_ARCH_X86 || KMP_ARCH_ARM 307cc577a4SJonathan Peyton typedef kmp_int32 bufsize; 317cc577a4SJonathan Peyton #else 327cc577a4SJonathan Peyton typedef kmp_int64 bufsize; 337cc577a4SJonathan Peyton #endif 347cc577a4SJonathan Peyton #else 357cc577a4SJonathan Peyton typedef ssize_t bufsize; 36e4b4f994SJonathan Peyton #endif // KMP_OS_WINDOWS 377cc577a4SJonathan Peyton 387cc577a4SJonathan Peyton /* The three modes of operation are, fifo search, lifo search, and best-fit */ 397cc577a4SJonathan Peyton 407cc577a4SJonathan Peyton typedef enum bget_mode { 417cc577a4SJonathan Peyton bget_mode_fifo = 0, 427cc577a4SJonathan Peyton bget_mode_lifo = 1, 437cc577a4SJonathan Peyton bget_mode_best = 2 447cc577a4SJonathan Peyton } bget_mode_t; 457cc577a4SJonathan Peyton 467cc577a4SJonathan Peyton static void bpool(kmp_info_t *th, void *buffer, bufsize len); 477cc577a4SJonathan Peyton static void *bget(kmp_info_t *th, bufsize size); 487cc577a4SJonathan Peyton static void *bgetz(kmp_info_t *th, bufsize size); 497cc577a4SJonathan Peyton static void *bgetr(kmp_info_t *th, void *buffer, bufsize newsize); 507cc577a4SJonathan Peyton static void brel(kmp_info_t *th, void *buf); 513041982dSJonathan Peyton static void bectl(kmp_info_t *th, bget_compact_t compact, 523041982dSJonathan Peyton bget_acquire_t acquire, bget_release_t release, 533041982dSJonathan Peyton bufsize pool_incr); 547cc577a4SJonathan Peyton 557cc577a4SJonathan Peyton /* BGET CONFIGURATION */ 563041982dSJonathan Peyton /* Buffer allocation size quantum: all buffers allocated are a 573041982dSJonathan Peyton multiple of this size. This MUST be a power of two. */ 587cc577a4SJonathan Peyton 593041982dSJonathan Peyton /* On IA-32 architecture with Linux* OS, malloc() does not 60ed5fe645SKelvin Li ensure 16 byte alignment */ 617cc577a4SJonathan Peyton 627cc577a4SJonathan Peyton #if KMP_ARCH_X86 || !KMP_HAVE_QUAD 637cc577a4SJonathan Peyton 647cc577a4SJonathan Peyton #define SizeQuant 8 657cc577a4SJonathan Peyton #define AlignType double 667cc577a4SJonathan Peyton 677cc577a4SJonathan Peyton #else 687cc577a4SJonathan Peyton 697cc577a4SJonathan Peyton #define SizeQuant 16 707cc577a4SJonathan Peyton #define AlignType _Quad 717cc577a4SJonathan Peyton 727cc577a4SJonathan Peyton #endif 737cc577a4SJonathan Peyton 743041982dSJonathan Peyton // Define this symbol to enable the bstats() function which calculates the 753041982dSJonathan Peyton // total free space in the buffer pool, the largest available buffer, and the 763041982dSJonathan Peyton // total space currently allocated. 773041982dSJonathan Peyton #define BufStats 1 787cc577a4SJonathan Peyton 797cc577a4SJonathan Peyton #ifdef KMP_DEBUG 807cc577a4SJonathan Peyton 813041982dSJonathan Peyton // Define this symbol to enable the bpoold() function which dumps the buffers 823041982dSJonathan Peyton // in a buffer pool. 833041982dSJonathan Peyton #define BufDump 1 847cc577a4SJonathan Peyton 853041982dSJonathan Peyton // Define this symbol to enable the bpoolv() function for validating a buffer 863041982dSJonathan Peyton // pool. 873041982dSJonathan Peyton #define BufValid 1 887cc577a4SJonathan Peyton 893041982dSJonathan Peyton // Define this symbol to enable the bufdump() function which allows dumping the 903041982dSJonathan Peyton // contents of an allocated or free buffer. 913041982dSJonathan Peyton #define DumpData 1 923041982dSJonathan Peyton 937cc577a4SJonathan Peyton #ifdef NOT_USED_NOW 947cc577a4SJonathan Peyton 953041982dSJonathan Peyton // Wipe free buffers to a guaranteed pattern of garbage to trip up miscreants 963041982dSJonathan Peyton // who attempt to use pointers into released buffers. 973041982dSJonathan Peyton #define FreeWipe 1 987cc577a4SJonathan Peyton 993041982dSJonathan Peyton // Use a best fit algorithm when searching for space for an allocation request. 1003041982dSJonathan Peyton // This uses memory more efficiently, but allocation will be much slower. 1013041982dSJonathan Peyton #define BestFit 1 1023041982dSJonathan Peyton 1037cc577a4SJonathan Peyton #endif /* NOT_USED_NOW */ 1047cc577a4SJonathan Peyton #endif /* KMP_DEBUG */ 1057cc577a4SJonathan Peyton 1067cc577a4SJonathan Peyton static bufsize bget_bin_size[] = { 1077cc577a4SJonathan Peyton 0, 1087cc577a4SJonathan Peyton // 1 << 6, /* .5 Cache line */ 1097cc577a4SJonathan Peyton 1 << 7, /* 1 Cache line, new */ 1107cc577a4SJonathan Peyton 1 << 8, /* 2 Cache lines */ 1117cc577a4SJonathan Peyton 1 << 9, /* 4 Cache lines, new */ 1127cc577a4SJonathan Peyton 1 << 10, /* 8 Cache lines */ 1137cc577a4SJonathan Peyton 1 << 11, /* 16 Cache lines, new */ 1143041982dSJonathan Peyton 1 << 12, 1 << 13, /* new */ 1153041982dSJonathan Peyton 1 << 14, 1 << 15, /* new */ 1163041982dSJonathan Peyton 1 << 16, 1 << 17, 1 << 18, 1 << 19, 1 << 20, /* 1MB */ 1177cc577a4SJonathan Peyton 1 << 21, /* 2MB */ 1187cc577a4SJonathan Peyton 1 << 22, /* 4MB */ 1197cc577a4SJonathan Peyton 1 << 23, /* 8MB */ 1207cc577a4SJonathan Peyton 1 << 24, /* 16MB */ 1217cc577a4SJonathan Peyton 1 << 25, /* 32MB */ 1227cc577a4SJonathan Peyton }; 1237cc577a4SJonathan Peyton 1247cc577a4SJonathan Peyton #define MAX_BGET_BINS (int)(sizeof(bget_bin_size) / sizeof(bufsize)) 1257cc577a4SJonathan Peyton 1267cc577a4SJonathan Peyton struct bfhead; 1277cc577a4SJonathan Peyton 1283041982dSJonathan Peyton // Declare the interface, including the requested buffer size type, bufsize. 1297cc577a4SJonathan Peyton 1307cc577a4SJonathan Peyton /* Queue links */ 1317cc577a4SJonathan Peyton typedef struct qlinks { 1327cc577a4SJonathan Peyton struct bfhead *flink; /* Forward link */ 1337cc577a4SJonathan Peyton struct bfhead *blink; /* Backward link */ 1347cc577a4SJonathan Peyton } qlinks_t; 1357cc577a4SJonathan Peyton 1367cc577a4SJonathan Peyton /* Header in allocated and free buffers */ 1377cc577a4SJonathan Peyton typedef struct bhead2 { 1387cc577a4SJonathan Peyton kmp_info_t *bthr; /* The thread which owns the buffer pool */ 1393041982dSJonathan Peyton bufsize prevfree; /* Relative link back to previous free buffer in memory or 1403041982dSJonathan Peyton 0 if previous buffer is allocated. */ 1413041982dSJonathan Peyton bufsize bsize; /* Buffer size: positive if free, negative if allocated. */ 1427cc577a4SJonathan Peyton } bhead2_t; 1437cc577a4SJonathan Peyton 1447cc577a4SJonathan Peyton /* Make sure the bhead structure is a multiple of SizeQuant in size. */ 1457cc577a4SJonathan Peyton typedef union bhead { 1467cc577a4SJonathan Peyton KMP_ALIGN(SizeQuant) 1477cc577a4SJonathan Peyton AlignType b_align; 1487cc577a4SJonathan Peyton char b_pad[sizeof(bhead2_t) + (SizeQuant - (sizeof(bhead2_t) % SizeQuant))]; 1497cc577a4SJonathan Peyton bhead2_t bb; 1507cc577a4SJonathan Peyton } bhead_t; 1517cc577a4SJonathan Peyton #define BH(p) ((bhead_t *)(p)) 1527cc577a4SJonathan Peyton 1537cc577a4SJonathan Peyton /* Header in directly allocated buffers (by acqfcn) */ 1543041982dSJonathan Peyton typedef struct bdhead { 1557cc577a4SJonathan Peyton bufsize tsize; /* Total size, including overhead */ 1567cc577a4SJonathan Peyton bhead_t bh; /* Common header */ 1577cc577a4SJonathan Peyton } bdhead_t; 1587cc577a4SJonathan Peyton #define BDH(p) ((bdhead_t *)(p)) 1597cc577a4SJonathan Peyton 1607cc577a4SJonathan Peyton /* Header in free buffers */ 1617cc577a4SJonathan Peyton typedef struct bfhead { 1627cc577a4SJonathan Peyton bhead_t bh; /* Common allocated/free header */ 1637cc577a4SJonathan Peyton qlinks_t ql; /* Links on free list */ 1647cc577a4SJonathan Peyton } bfhead_t; 1657cc577a4SJonathan Peyton #define BFH(p) ((bfhead_t *)(p)) 1667cc577a4SJonathan Peyton 1677cc577a4SJonathan Peyton typedef struct thr_data { 1687cc577a4SJonathan Peyton bfhead_t freelist[MAX_BGET_BINS]; 1697cc577a4SJonathan Peyton #if BufStats 1707cc577a4SJonathan Peyton size_t totalloc; /* Total space currently allocated */ 1717cc577a4SJonathan Peyton long numget, numrel; /* Number of bget() and brel() calls */ 1727cc577a4SJonathan Peyton long numpblk; /* Number of pool blocks */ 1737cc577a4SJonathan Peyton long numpget, numprel; /* Number of block gets and rels */ 1747cc577a4SJonathan Peyton long numdget, numdrel; /* Number of direct gets and rels */ 1757cc577a4SJonathan Peyton #endif /* BufStats */ 1767cc577a4SJonathan Peyton 1777cc577a4SJonathan Peyton /* Automatic expansion block management functions */ 1787cc577a4SJonathan Peyton bget_compact_t compfcn; 1797cc577a4SJonathan Peyton bget_acquire_t acqfcn; 1807cc577a4SJonathan Peyton bget_release_t relfcn; 1817cc577a4SJonathan Peyton 1827cc577a4SJonathan Peyton bget_mode_t mode; /* what allocation mode to use? */ 1837cc577a4SJonathan Peyton 1847cc577a4SJonathan Peyton bufsize exp_incr; /* Expansion block size */ 1857cc577a4SJonathan Peyton bufsize pool_len; /* 0: no bpool calls have been made 1863041982dSJonathan Peyton -1: not all pool blocks are the same size 1873041982dSJonathan Peyton >0: (common) block size for all bpool calls made so far 1887cc577a4SJonathan Peyton */ 18942016791SKazuaki Ishizaki bfhead_t *last_pool; /* Last pool owned by this thread (delay deallocation) */ 1907cc577a4SJonathan Peyton } thr_data_t; 1917cc577a4SJonathan Peyton 1927cc577a4SJonathan Peyton /* Minimum allocation quantum: */ 1937cc577a4SJonathan Peyton #define QLSize (sizeof(qlinks_t)) 1947cc577a4SJonathan Peyton #define SizeQ ((SizeQuant > QLSize) ? SizeQuant : QLSize) 1953041982dSJonathan Peyton #define MaxSize \ 1963041982dSJonathan Peyton (bufsize)( \ 1973041982dSJonathan Peyton ~(((bufsize)(1) << (sizeof(bufsize) * CHAR_BIT - 1)) | (SizeQuant - 1))) 19842016791SKazuaki Ishizaki // Maximum for the requested size. 1997cc577a4SJonathan Peyton 2007cc577a4SJonathan Peyton /* End sentinel: value placed in bsize field of dummy block delimiting 2017cc577a4SJonathan Peyton end of pool block. The most negative number which will fit in a 2027cc577a4SJonathan Peyton bufsize, defined in a way that the compiler will accept. */ 2037cc577a4SJonathan Peyton 2043041982dSJonathan Peyton #define ESent \ 2053041982dSJonathan Peyton ((bufsize)(-(((((bufsize)1) << ((int)sizeof(bufsize) * 8 - 2)) - 1) * 2) - 2)) 2067cc577a4SJonathan Peyton 2077cc577a4SJonathan Peyton /* Thread Data management routines */ 2083041982dSJonathan Peyton static int bget_get_bin(bufsize size) { 2097cc577a4SJonathan Peyton // binary chop bins 2107cc577a4SJonathan Peyton int lo = 0, hi = MAX_BGET_BINS - 1; 2117cc577a4SJonathan Peyton 2127cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(size > 0); 2137cc577a4SJonathan Peyton 2147cc577a4SJonathan Peyton while ((hi - lo) > 1) { 2157cc577a4SJonathan Peyton int mid = (lo + hi) >> 1; 2167cc577a4SJonathan Peyton if (size < bget_bin_size[mid]) 2177cc577a4SJonathan Peyton hi = mid - 1; 2187cc577a4SJonathan Peyton else 2197cc577a4SJonathan Peyton lo = mid; 2207cc577a4SJonathan Peyton } 2217cc577a4SJonathan Peyton 2227cc577a4SJonathan Peyton KMP_DEBUG_ASSERT((lo >= 0) && (lo < MAX_BGET_BINS)); 2237cc577a4SJonathan Peyton 2247cc577a4SJonathan Peyton return lo; 2257cc577a4SJonathan Peyton } 2267cc577a4SJonathan Peyton 2273041982dSJonathan Peyton static void set_thr_data(kmp_info_t *th) { 2287cc577a4SJonathan Peyton int i; 2297cc577a4SJonathan Peyton thr_data_t *data; 2307cc577a4SJonathan Peyton 2313041982dSJonathan Peyton data = (thr_data_t *)((!th->th.th_local.bget_data) 2323041982dSJonathan Peyton ? __kmp_allocate(sizeof(*data)) 2333041982dSJonathan Peyton : th->th.th_local.bget_data); 2347cc577a4SJonathan Peyton 2357cc577a4SJonathan Peyton memset(data, '\0', sizeof(*data)); 2367cc577a4SJonathan Peyton 2377cc577a4SJonathan Peyton for (i = 0; i < MAX_BGET_BINS; ++i) { 2387cc577a4SJonathan Peyton data->freelist[i].ql.flink = &data->freelist[i]; 2397cc577a4SJonathan Peyton data->freelist[i].ql.blink = &data->freelist[i]; 2407cc577a4SJonathan Peyton } 2417cc577a4SJonathan Peyton 2427cc577a4SJonathan Peyton th->th.th_local.bget_data = data; 2437cc577a4SJonathan Peyton th->th.th_local.bget_list = 0; 2447cc577a4SJonathan Peyton #if !USE_CMP_XCHG_FOR_BGET 2457cc577a4SJonathan Peyton #ifdef USE_QUEUING_LOCK_FOR_BGET 2467cc577a4SJonathan Peyton __kmp_init_lock(&th->th.th_local.bget_lock); 2477cc577a4SJonathan Peyton #else 2487cc577a4SJonathan Peyton __kmp_init_bootstrap_lock(&th->th.th_local.bget_lock); 2497cc577a4SJonathan Peyton #endif /* USE_LOCK_FOR_BGET */ 2507cc577a4SJonathan Peyton #endif /* ! USE_CMP_XCHG_FOR_BGET */ 2517cc577a4SJonathan Peyton } 2527cc577a4SJonathan Peyton 2533041982dSJonathan Peyton static thr_data_t *get_thr_data(kmp_info_t *th) { 2547cc577a4SJonathan Peyton thr_data_t *data; 2557cc577a4SJonathan Peyton 2567cc577a4SJonathan Peyton data = (thr_data_t *)th->th.th_local.bget_data; 2577cc577a4SJonathan Peyton 2587cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(data != 0); 2597cc577a4SJonathan Peyton 2607cc577a4SJonathan Peyton return data; 2617cc577a4SJonathan Peyton } 2627cc577a4SJonathan Peyton 2637cc577a4SJonathan Peyton /* Walk the free list and release the enqueued buffers */ 2643041982dSJonathan Peyton static void __kmp_bget_dequeue(kmp_info_t *th) { 2657cc577a4SJonathan Peyton void *p = TCR_SYNC_PTR(th->th.th_local.bget_list); 2667cc577a4SJonathan Peyton 2677cc577a4SJonathan Peyton if (p != 0) { 2687cc577a4SJonathan Peyton #if USE_CMP_XCHG_FOR_BGET 2697cc577a4SJonathan Peyton { 2707cc577a4SJonathan Peyton volatile void *old_value = TCR_SYNC_PTR(th->th.th_local.bget_list); 271c47afcd9SAndrey Churbanov while (!KMP_COMPARE_AND_STORE_PTR(&th->th.th_local.bget_list, 2725ba90c79SAndrey Churbanov CCAST(void *, old_value), nullptr)) { 2737cc577a4SJonathan Peyton KMP_CPU_PAUSE(); 2747cc577a4SJonathan Peyton old_value = TCR_SYNC_PTR(th->th.th_local.bget_list); 2757cc577a4SJonathan Peyton } 276c47afcd9SAndrey Churbanov p = CCAST(void *, old_value); 2777cc577a4SJonathan Peyton } 2787cc577a4SJonathan Peyton #else /* ! USE_CMP_XCHG_FOR_BGET */ 2797cc577a4SJonathan Peyton #ifdef USE_QUEUING_LOCK_FOR_BGET 2803041982dSJonathan Peyton __kmp_acquire_lock(&th->th.th_local.bget_lock, __kmp_gtid_from_thread(th)); 2817cc577a4SJonathan Peyton #else 2827cc577a4SJonathan Peyton __kmp_acquire_bootstrap_lock(&th->th.th_local.bget_lock); 2837cc577a4SJonathan Peyton #endif /* USE_QUEUING_LOCK_FOR_BGET */ 2847cc577a4SJonathan Peyton 2857cc577a4SJonathan Peyton p = (void *)th->th.th_local.bget_list; 2867cc577a4SJonathan Peyton th->th.th_local.bget_list = 0; 2877cc577a4SJonathan Peyton 2887cc577a4SJonathan Peyton #ifdef USE_QUEUING_LOCK_FOR_BGET 2893041982dSJonathan Peyton __kmp_release_lock(&th->th.th_local.bget_lock, __kmp_gtid_from_thread(th)); 2907cc577a4SJonathan Peyton #else 2917cc577a4SJonathan Peyton __kmp_release_bootstrap_lock(&th->th.th_local.bget_lock); 2927cc577a4SJonathan Peyton #endif 2937cc577a4SJonathan Peyton #endif /* USE_CMP_XCHG_FOR_BGET */ 2947cc577a4SJonathan Peyton 2957cc577a4SJonathan Peyton /* Check again to make sure the list is not empty */ 2967cc577a4SJonathan Peyton while (p != 0) { 2977cc577a4SJonathan Peyton void *buf = p; 2987cc577a4SJonathan Peyton bfhead_t *b = BFH(((char *)p) - sizeof(bhead_t)); 2997cc577a4SJonathan Peyton 3007cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(b->bh.bb.bsize != 0); 3017cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(((kmp_uintptr_t)TCR_PTR(b->bh.bb.bthr) & ~1) == 3027cc577a4SJonathan Peyton (kmp_uintptr_t)th); // clear possible mark 3037cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(b->ql.blink == 0); 3047cc577a4SJonathan Peyton 3057cc577a4SJonathan Peyton p = (void *)b->ql.flink; 3067cc577a4SJonathan Peyton 3077cc577a4SJonathan Peyton brel(th, buf); 3087cc577a4SJonathan Peyton } 3097cc577a4SJonathan Peyton } 3107cc577a4SJonathan Peyton } 3117cc577a4SJonathan Peyton 3127cc577a4SJonathan Peyton /* Chain together the free buffers by using the thread owner field */ 3133041982dSJonathan Peyton static void __kmp_bget_enqueue(kmp_info_t *th, void *buf 3147cc577a4SJonathan Peyton #ifdef USE_QUEUING_LOCK_FOR_BGET 3153041982dSJonathan Peyton , 3163041982dSJonathan Peyton kmp_int32 rel_gtid 3177cc577a4SJonathan Peyton #endif 3183041982dSJonathan Peyton ) { 3197cc577a4SJonathan Peyton bfhead_t *b = BFH(((char *)buf) - sizeof(bhead_t)); 3207cc577a4SJonathan Peyton 3217cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(b->bh.bb.bsize != 0); 3227cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(((kmp_uintptr_t)TCR_PTR(b->bh.bb.bthr) & ~1) == 3237cc577a4SJonathan Peyton (kmp_uintptr_t)th); // clear possible mark 3247cc577a4SJonathan Peyton 3257cc577a4SJonathan Peyton b->ql.blink = 0; 3267cc577a4SJonathan Peyton 3277cc577a4SJonathan Peyton KC_TRACE(10, ("__kmp_bget_enqueue: moving buffer to T#%d list\n", 3287cc577a4SJonathan Peyton __kmp_gtid_from_thread(th))); 3297cc577a4SJonathan Peyton 3307cc577a4SJonathan Peyton #if USE_CMP_XCHG_FOR_BGET 3317cc577a4SJonathan Peyton { 3327cc577a4SJonathan Peyton volatile void *old_value = TCR_PTR(th->th.th_local.bget_list); 3337cc577a4SJonathan Peyton /* the next pointer must be set before setting bget_list to buf to avoid 3347cc577a4SJonathan Peyton exposing a broken list to other threads, even for an instant. */ 335c47afcd9SAndrey Churbanov b->ql.flink = BFH(CCAST(void *, old_value)); 3367cc577a4SJonathan Peyton 337c47afcd9SAndrey Churbanov while (!KMP_COMPARE_AND_STORE_PTR(&th->th.th_local.bget_list, 338c47afcd9SAndrey Churbanov CCAST(void *, old_value), buf)) { 3397cc577a4SJonathan Peyton KMP_CPU_PAUSE(); 3407cc577a4SJonathan Peyton old_value = TCR_PTR(th->th.th_local.bget_list); 3417cc577a4SJonathan Peyton /* the next pointer must be set before setting bget_list to buf to avoid 3427cc577a4SJonathan Peyton exposing a broken list to other threads, even for an instant. */ 343c47afcd9SAndrey Churbanov b->ql.flink = BFH(CCAST(void *, old_value)); 3447cc577a4SJonathan Peyton } 3457cc577a4SJonathan Peyton } 3467cc577a4SJonathan Peyton #else /* ! USE_CMP_XCHG_FOR_BGET */ 3477cc577a4SJonathan Peyton #ifdef USE_QUEUING_LOCK_FOR_BGET 3487cc577a4SJonathan Peyton __kmp_acquire_lock(&th->th.th_local.bget_lock, rel_gtid); 3497cc577a4SJonathan Peyton #else 3507cc577a4SJonathan Peyton __kmp_acquire_bootstrap_lock(&th->th.th_local.bget_lock); 3517cc577a4SJonathan Peyton #endif 3527cc577a4SJonathan Peyton 3537cc577a4SJonathan Peyton b->ql.flink = BFH(th->th.th_local.bget_list); 3547cc577a4SJonathan Peyton th->th.th_local.bget_list = (void *)buf; 3557cc577a4SJonathan Peyton 3567cc577a4SJonathan Peyton #ifdef USE_QUEUING_LOCK_FOR_BGET 3577cc577a4SJonathan Peyton __kmp_release_lock(&th->th.th_local.bget_lock, rel_gtid); 3587cc577a4SJonathan Peyton #else 3597cc577a4SJonathan Peyton __kmp_release_bootstrap_lock(&th->th.th_local.bget_lock); 3607cc577a4SJonathan Peyton #endif 3617cc577a4SJonathan Peyton #endif /* USE_CMP_XCHG_FOR_BGET */ 3627cc577a4SJonathan Peyton } 3637cc577a4SJonathan Peyton 3647cc577a4SJonathan Peyton /* insert buffer back onto a new freelist */ 3653041982dSJonathan Peyton static void __kmp_bget_insert_into_freelist(thr_data_t *thr, bfhead_t *b) { 3667cc577a4SJonathan Peyton int bin; 3677cc577a4SJonathan Peyton 3687cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(((size_t)b) % SizeQuant == 0); 3697cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(b->bh.bb.bsize % SizeQuant == 0); 3707cc577a4SJonathan Peyton 3717cc577a4SJonathan Peyton bin = bget_get_bin(b->bh.bb.bsize); 3727cc577a4SJonathan Peyton 3733041982dSJonathan Peyton KMP_DEBUG_ASSERT(thr->freelist[bin].ql.blink->ql.flink == 3743041982dSJonathan Peyton &thr->freelist[bin]); 3753041982dSJonathan Peyton KMP_DEBUG_ASSERT(thr->freelist[bin].ql.flink->ql.blink == 3763041982dSJonathan Peyton &thr->freelist[bin]); 3777cc577a4SJonathan Peyton 3787cc577a4SJonathan Peyton b->ql.flink = &thr->freelist[bin]; 3797cc577a4SJonathan Peyton b->ql.blink = thr->freelist[bin].ql.blink; 3807cc577a4SJonathan Peyton 3817cc577a4SJonathan Peyton thr->freelist[bin].ql.blink = b; 3827cc577a4SJonathan Peyton b->ql.blink->ql.flink = b; 3837cc577a4SJonathan Peyton } 3847cc577a4SJonathan Peyton 3857cc577a4SJonathan Peyton /* unlink the buffer from the old freelist */ 3863041982dSJonathan Peyton static void __kmp_bget_remove_from_freelist(bfhead_t *b) { 3877cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(b->ql.blink->ql.flink == b); 3887cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(b->ql.flink->ql.blink == b); 3897cc577a4SJonathan Peyton 3907cc577a4SJonathan Peyton b->ql.blink->ql.flink = b->ql.flink; 3917cc577a4SJonathan Peyton b->ql.flink->ql.blink = b->ql.blink; 3927cc577a4SJonathan Peyton } 3937cc577a4SJonathan Peyton 3947cc577a4SJonathan Peyton /* GET STATS -- check info on free list */ 3953041982dSJonathan Peyton static void bcheck(kmp_info_t *th, bufsize *max_free, bufsize *total_free) { 3967cc577a4SJonathan Peyton thr_data_t *thr = get_thr_data(th); 3977cc577a4SJonathan Peyton int bin; 3987cc577a4SJonathan Peyton 3997cc577a4SJonathan Peyton *total_free = *max_free = 0; 4007cc577a4SJonathan Peyton 4017cc577a4SJonathan Peyton for (bin = 0; bin < MAX_BGET_BINS; ++bin) { 4027cc577a4SJonathan Peyton bfhead_t *b, *best; 4037cc577a4SJonathan Peyton 4047cc577a4SJonathan Peyton best = &thr->freelist[bin]; 4057cc577a4SJonathan Peyton b = best->ql.flink; 4067cc577a4SJonathan Peyton 4077cc577a4SJonathan Peyton while (b != &thr->freelist[bin]) { 4087cc577a4SJonathan Peyton *total_free += (b->bh.bb.bsize - sizeof(bhead_t)); 4097cc577a4SJonathan Peyton if ((best == &thr->freelist[bin]) || (b->bh.bb.bsize < best->bh.bb.bsize)) 4107cc577a4SJonathan Peyton best = b; 4117cc577a4SJonathan Peyton 4127cc577a4SJonathan Peyton /* Link to next buffer */ 4137cc577a4SJonathan Peyton b = b->ql.flink; 4147cc577a4SJonathan Peyton } 4157cc577a4SJonathan Peyton 4167cc577a4SJonathan Peyton if (*max_free < best->bh.bb.bsize) 4177cc577a4SJonathan Peyton *max_free = best->bh.bb.bsize; 4187cc577a4SJonathan Peyton } 4197cc577a4SJonathan Peyton 4207cc577a4SJonathan Peyton if (*max_free > (bufsize)sizeof(bhead_t)) 4217cc577a4SJonathan Peyton *max_free -= sizeof(bhead_t); 4227cc577a4SJonathan Peyton } 4237cc577a4SJonathan Peyton 4247cc577a4SJonathan Peyton /* BGET -- Allocate a buffer. */ 4253041982dSJonathan Peyton static void *bget(kmp_info_t *th, bufsize requested_size) { 4267cc577a4SJonathan Peyton thr_data_t *thr = get_thr_data(th); 4277cc577a4SJonathan Peyton bufsize size = requested_size; 4287cc577a4SJonathan Peyton bfhead_t *b; 4297cc577a4SJonathan Peyton void *buf; 4307cc577a4SJonathan Peyton int compactseq = 0; 4317cc577a4SJonathan Peyton int use_blink = 0; 4327cc577a4SJonathan Peyton /* For BestFit */ 4337cc577a4SJonathan Peyton bfhead_t *best; 4347cc577a4SJonathan Peyton 4357cc577a4SJonathan Peyton if (size < 0 || size + sizeof(bhead_t) > MaxSize) { 4367cc577a4SJonathan Peyton return NULL; 437bd3a7633SJonathan Peyton } 4387cc577a4SJonathan Peyton 4397cc577a4SJonathan Peyton __kmp_bget_dequeue(th); /* Release any queued buffers */ 4407cc577a4SJonathan Peyton 4413041982dSJonathan Peyton if (size < (bufsize)SizeQ) { // Need at least room for the queue links. 4423041982dSJonathan Peyton size = SizeQ; 4437cc577a4SJonathan Peyton } 4447cc577a4SJonathan Peyton #if defined(SizeQuant) && (SizeQuant > 1) 4457cc577a4SJonathan Peyton size = (size + (SizeQuant - 1)) & (~(SizeQuant - 1)); 4467cc577a4SJonathan Peyton #endif 4477cc577a4SJonathan Peyton 4483041982dSJonathan Peyton size += sizeof(bhead_t); // Add overhead in allocated buffer to size required. 4497cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(size >= 0); 4507cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(size % SizeQuant == 0); 4517cc577a4SJonathan Peyton 4527cc577a4SJonathan Peyton use_blink = (thr->mode == bget_mode_lifo); 4537cc577a4SJonathan Peyton 4547cc577a4SJonathan Peyton /* If a compact function was provided in the call to bectl(), wrap 4557cc577a4SJonathan Peyton a loop around the allocation process to allow compaction to 4567cc577a4SJonathan Peyton intervene in case we don't find a suitable buffer in the chain. */ 4577cc577a4SJonathan Peyton 4587cc577a4SJonathan Peyton for (;;) { 4597cc577a4SJonathan Peyton int bin; 4607cc577a4SJonathan Peyton 4617cc577a4SJonathan Peyton for (bin = bget_get_bin(size); bin < MAX_BGET_BINS; ++bin) { 4627cc577a4SJonathan Peyton /* Link to next buffer */ 4633041982dSJonathan Peyton b = (use_blink ? thr->freelist[bin].ql.blink 4643041982dSJonathan Peyton : thr->freelist[bin].ql.flink); 4657cc577a4SJonathan Peyton 4667cc577a4SJonathan Peyton if (thr->mode == bget_mode_best) { 4677cc577a4SJonathan Peyton best = &thr->freelist[bin]; 4687cc577a4SJonathan Peyton 4697cc577a4SJonathan Peyton /* Scan the free list searching for the first buffer big enough 4707cc577a4SJonathan Peyton to hold the requested size buffer. */ 4717cc577a4SJonathan Peyton while (b != &thr->freelist[bin]) { 4727cc577a4SJonathan Peyton if (b->bh.bb.bsize >= (bufsize)size) { 4733041982dSJonathan Peyton if ((best == &thr->freelist[bin]) || 4743041982dSJonathan Peyton (b->bh.bb.bsize < best->bh.bb.bsize)) { 4757cc577a4SJonathan Peyton best = b; 4767cc577a4SJonathan Peyton } 4777cc577a4SJonathan Peyton } 4787cc577a4SJonathan Peyton 4797cc577a4SJonathan Peyton /* Link to next buffer */ 4807cc577a4SJonathan Peyton b = (use_blink ? b->ql.blink : b->ql.flink); 4817cc577a4SJonathan Peyton } 4827cc577a4SJonathan Peyton b = best; 4837cc577a4SJonathan Peyton } 4847cc577a4SJonathan Peyton 4857cc577a4SJonathan Peyton while (b != &thr->freelist[bin]) { 4867cc577a4SJonathan Peyton if ((bufsize)b->bh.bb.bsize >= (bufsize)size) { 4877cc577a4SJonathan Peyton 4883041982dSJonathan Peyton // Buffer is big enough to satisfy the request. Allocate it to the 4893041982dSJonathan Peyton // caller. We must decide whether the buffer is large enough to split 4903041982dSJonathan Peyton // into the part given to the caller and a free buffer that remains 4913041982dSJonathan Peyton // on the free list, or whether the entire buffer should be removed 4923041982dSJonathan Peyton // from the free list and given to the caller in its entirety. We 4933041982dSJonathan Peyton // only split the buffer if enough room remains for a header plus the 4943041982dSJonathan Peyton // minimum quantum of allocation. 4953041982dSJonathan Peyton if ((b->bh.bb.bsize - (bufsize)size) > 4963041982dSJonathan Peyton (bufsize)(SizeQ + (sizeof(bhead_t)))) { 4977cc577a4SJonathan Peyton bhead_t *ba, *bn; 4987cc577a4SJonathan Peyton 4997cc577a4SJonathan Peyton ba = BH(((char *)b) + (b->bh.bb.bsize - (bufsize)size)); 5007cc577a4SJonathan Peyton bn = BH(((char *)ba) + size); 5017cc577a4SJonathan Peyton 5027cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(bn->bb.prevfree == b->bh.bb.bsize); 5037cc577a4SJonathan Peyton 5047cc577a4SJonathan Peyton /* Subtract size from length of free block. */ 5057cc577a4SJonathan Peyton b->bh.bb.bsize -= (bufsize)size; 5067cc577a4SJonathan Peyton 5077cc577a4SJonathan Peyton /* Link allocated buffer to the previous free buffer. */ 5087cc577a4SJonathan Peyton ba->bb.prevfree = b->bh.bb.bsize; 5097cc577a4SJonathan Peyton 5107cc577a4SJonathan Peyton /* Plug negative size into user buffer. */ 5117cc577a4SJonathan Peyton ba->bb.bsize = -size; 5127cc577a4SJonathan Peyton 5137cc577a4SJonathan Peyton /* Mark this buffer as owned by this thread. */ 5143041982dSJonathan Peyton TCW_PTR(ba->bb.bthr, 5153041982dSJonathan Peyton th); // not an allocated address (do not mark it) 5167cc577a4SJonathan Peyton /* Mark buffer after this one not preceded by free block. */ 5177cc577a4SJonathan Peyton bn->bb.prevfree = 0; 5187cc577a4SJonathan Peyton 5193041982dSJonathan Peyton // unlink buffer from old freelist, and reinsert into new freelist 5207cc577a4SJonathan Peyton __kmp_bget_remove_from_freelist(b); 5217cc577a4SJonathan Peyton __kmp_bget_insert_into_freelist(thr, b); 5227cc577a4SJonathan Peyton #if BufStats 5237cc577a4SJonathan Peyton thr->totalloc += (size_t)size; 5247cc577a4SJonathan Peyton thr->numget++; /* Increment number of bget() calls */ 5257cc577a4SJonathan Peyton #endif 5267cc577a4SJonathan Peyton buf = (void *)((((char *)ba) + sizeof(bhead_t))); 5277cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(((size_t)buf) % SizeQuant == 0); 5287cc577a4SJonathan Peyton return buf; 5297cc577a4SJonathan Peyton } else { 5307cc577a4SJonathan Peyton bhead_t *ba; 5317cc577a4SJonathan Peyton 5327cc577a4SJonathan Peyton ba = BH(((char *)b) + b->bh.bb.bsize); 5337cc577a4SJonathan Peyton 5347cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(ba->bb.prevfree == b->bh.bb.bsize); 5357cc577a4SJonathan Peyton 5367cc577a4SJonathan Peyton /* The buffer isn't big enough to split. Give the whole 5377cc577a4SJonathan Peyton shebang to the caller and remove it from the free list. */ 5387cc577a4SJonathan Peyton 5397cc577a4SJonathan Peyton __kmp_bget_remove_from_freelist(b); 5407cc577a4SJonathan Peyton #if BufStats 5417cc577a4SJonathan Peyton thr->totalloc += (size_t)b->bh.bb.bsize; 5427cc577a4SJonathan Peyton thr->numget++; /* Increment number of bget() calls */ 5437cc577a4SJonathan Peyton #endif 5447cc577a4SJonathan Peyton /* Negate size to mark buffer allocated. */ 5457cc577a4SJonathan Peyton b->bh.bb.bsize = -(b->bh.bb.bsize); 5467cc577a4SJonathan Peyton 5477cc577a4SJonathan Peyton /* Mark this buffer as owned by this thread. */ 5483041982dSJonathan Peyton TCW_PTR(ba->bb.bthr, th); // not an allocated address (do not mark) 5497cc577a4SJonathan Peyton /* Zero the back pointer in the next buffer in memory 5507cc577a4SJonathan Peyton to indicate that this buffer is allocated. */ 5517cc577a4SJonathan Peyton ba->bb.prevfree = 0; 5527cc577a4SJonathan Peyton 5537cc577a4SJonathan Peyton /* Give user buffer starting at queue links. */ 5547cc577a4SJonathan Peyton buf = (void *)&(b->ql); 5557cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(((size_t)buf) % SizeQuant == 0); 5567cc577a4SJonathan Peyton return buf; 5577cc577a4SJonathan Peyton } 5587cc577a4SJonathan Peyton } 5597cc577a4SJonathan Peyton 5607cc577a4SJonathan Peyton /* Link to next buffer */ 5617cc577a4SJonathan Peyton b = (use_blink ? b->ql.blink : b->ql.flink); 5627cc577a4SJonathan Peyton } 5637cc577a4SJonathan Peyton } 5647cc577a4SJonathan Peyton 5653041982dSJonathan Peyton /* We failed to find a buffer. If there's a compact function defined, 5663041982dSJonathan Peyton notify it of the size requested. If it returns TRUE, try the allocation 5673041982dSJonathan Peyton again. */ 5687cc577a4SJonathan Peyton 5697cc577a4SJonathan Peyton if ((thr->compfcn == 0) || (!(*thr->compfcn)(size, ++compactseq))) { 5707cc577a4SJonathan Peyton break; 5717cc577a4SJonathan Peyton } 5727cc577a4SJonathan Peyton } 5737cc577a4SJonathan Peyton 5747cc577a4SJonathan Peyton /* No buffer available with requested size free. */ 5757cc577a4SJonathan Peyton 5767cc577a4SJonathan Peyton /* Don't give up yet -- look in the reserve supply. */ 5777cc577a4SJonathan Peyton if (thr->acqfcn != 0) { 5787cc577a4SJonathan Peyton if (size > (bufsize)(thr->exp_incr - sizeof(bhead_t))) { 5793041982dSJonathan Peyton /* Request is too large to fit in a single expansion block. 58042016791SKazuaki Ishizaki Try to satisfy it by a direct buffer acquisition. */ 5817cc577a4SJonathan Peyton bdhead_t *bdh; 5827cc577a4SJonathan Peyton 5837cc577a4SJonathan Peyton size += sizeof(bdhead_t) - sizeof(bhead_t); 5847cc577a4SJonathan Peyton 5857cc577a4SJonathan Peyton KE_TRACE(10, ("%%%%%% MALLOC( %d )\n", (int)size)); 5867cc577a4SJonathan Peyton 5877cc577a4SJonathan Peyton /* richryan */ 5887cc577a4SJonathan Peyton bdh = BDH((*thr->acqfcn)((bufsize)size)); 5897cc577a4SJonathan Peyton if (bdh != NULL) { 5907cc577a4SJonathan Peyton 5913041982dSJonathan Peyton // Mark the buffer special by setting size field of its header to zero. 5927cc577a4SJonathan Peyton bdh->bh.bb.bsize = 0; 5937cc577a4SJonathan Peyton 5947cc577a4SJonathan Peyton /* Mark this buffer as owned by this thread. */ 5957cc577a4SJonathan Peyton TCW_PTR(bdh->bh.bb.bthr, th); // don't mark buffer as allocated, 5967cc577a4SJonathan Peyton // because direct buffer never goes to free list 5977cc577a4SJonathan Peyton bdh->bh.bb.prevfree = 0; 5987cc577a4SJonathan Peyton bdh->tsize = size; 5997cc577a4SJonathan Peyton #if BufStats 6007cc577a4SJonathan Peyton thr->totalloc += (size_t)size; 6017cc577a4SJonathan Peyton thr->numget++; /* Increment number of bget() calls */ 6027cc577a4SJonathan Peyton thr->numdget++; /* Direct bget() call count */ 6037cc577a4SJonathan Peyton #endif 6047cc577a4SJonathan Peyton buf = (void *)(bdh + 1); 6057cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(((size_t)buf) % SizeQuant == 0); 6067cc577a4SJonathan Peyton return buf; 6077cc577a4SJonathan Peyton } 6087cc577a4SJonathan Peyton 6097cc577a4SJonathan Peyton } else { 6107cc577a4SJonathan Peyton 6117cc577a4SJonathan Peyton /* Try to obtain a new expansion block */ 6127cc577a4SJonathan Peyton void *newpool; 6137cc577a4SJonathan Peyton 6147cc577a4SJonathan Peyton KE_TRACE(10, ("%%%%%% MALLOCB( %d )\n", (int)thr->exp_incr)); 6157cc577a4SJonathan Peyton 6167cc577a4SJonathan Peyton /* richryan */ 6177cc577a4SJonathan Peyton newpool = (*thr->acqfcn)((bufsize)thr->exp_incr); 6187cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(((size_t)newpool) % SizeQuant == 0); 6197cc577a4SJonathan Peyton if (newpool != NULL) { 6207cc577a4SJonathan Peyton bpool(th, newpool, thr->exp_incr); 6213041982dSJonathan Peyton buf = bget( 6223041982dSJonathan Peyton th, requested_size); /* This can't, I say, can't get into a loop. */ 6237cc577a4SJonathan Peyton return buf; 6247cc577a4SJonathan Peyton } 6257cc577a4SJonathan Peyton } 6267cc577a4SJonathan Peyton } 6277cc577a4SJonathan Peyton 6287cc577a4SJonathan Peyton /* Still no buffer available */ 6297cc577a4SJonathan Peyton 6307cc577a4SJonathan Peyton return NULL; 6317cc577a4SJonathan Peyton } 6327cc577a4SJonathan Peyton 6337cc577a4SJonathan Peyton /* BGETZ -- Allocate a buffer and clear its contents to zero. We clear 6347cc577a4SJonathan Peyton the entire contents of the buffer to zero, not just the 6357cc577a4SJonathan Peyton region requested by the caller. */ 6367cc577a4SJonathan Peyton 6373041982dSJonathan Peyton static void *bgetz(kmp_info_t *th, bufsize size) { 6387cc577a4SJonathan Peyton char *buf = (char *)bget(th, size); 6397cc577a4SJonathan Peyton 6407cc577a4SJonathan Peyton if (buf != NULL) { 6417cc577a4SJonathan Peyton bhead_t *b; 6427cc577a4SJonathan Peyton bufsize rsize; 6437cc577a4SJonathan Peyton 6447cc577a4SJonathan Peyton b = BH(buf - sizeof(bhead_t)); 6457cc577a4SJonathan Peyton rsize = -(b->bb.bsize); 6467cc577a4SJonathan Peyton if (rsize == 0) { 6477cc577a4SJonathan Peyton bdhead_t *bd; 6487cc577a4SJonathan Peyton 6497cc577a4SJonathan Peyton bd = BDH(buf - sizeof(bdhead_t)); 6507cc577a4SJonathan Peyton rsize = bd->tsize - (bufsize)sizeof(bdhead_t); 6517cc577a4SJonathan Peyton } else { 6527cc577a4SJonathan Peyton rsize -= sizeof(bhead_t); 6537cc577a4SJonathan Peyton } 6547cc577a4SJonathan Peyton 6557cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(rsize >= size); 6567cc577a4SJonathan Peyton 6577cc577a4SJonathan Peyton (void)memset(buf, 0, (bufsize)rsize); 6587cc577a4SJonathan Peyton } 6597cc577a4SJonathan Peyton return ((void *)buf); 6607cc577a4SJonathan Peyton } 6617cc577a4SJonathan Peyton 6627cc577a4SJonathan Peyton /* BGETR -- Reallocate a buffer. This is a minimal implementation, 6637cc577a4SJonathan Peyton simply in terms of brel() and bget(). It could be 6647cc577a4SJonathan Peyton enhanced to allow the buffer to grow into adjacent free 6657cc577a4SJonathan Peyton blocks and to avoid moving data unnecessarily. */ 6667cc577a4SJonathan Peyton 6673041982dSJonathan Peyton static void *bgetr(kmp_info_t *th, void *buf, bufsize size) { 6687cc577a4SJonathan Peyton void *nbuf; 6697cc577a4SJonathan Peyton bufsize osize; /* Old size of buffer */ 6707cc577a4SJonathan Peyton bhead_t *b; 6717cc577a4SJonathan Peyton 6727cc577a4SJonathan Peyton nbuf = bget(th, size); 6737cc577a4SJonathan Peyton if (nbuf == NULL) { /* Acquire new buffer */ 6747cc577a4SJonathan Peyton return NULL; 6757cc577a4SJonathan Peyton } 6767cc577a4SJonathan Peyton if (buf == NULL) { 6777cc577a4SJonathan Peyton return nbuf; 6787cc577a4SJonathan Peyton } 6797cc577a4SJonathan Peyton b = BH(((char *)buf) - sizeof(bhead_t)); 6807cc577a4SJonathan Peyton osize = -b->bb.bsize; 6817cc577a4SJonathan Peyton if (osize == 0) { 6827cc577a4SJonathan Peyton /* Buffer acquired directly through acqfcn. */ 6837cc577a4SJonathan Peyton bdhead_t *bd; 6847cc577a4SJonathan Peyton 6857cc577a4SJonathan Peyton bd = BDH(((char *)buf) - sizeof(bdhead_t)); 6867cc577a4SJonathan Peyton osize = bd->tsize - (bufsize)sizeof(bdhead_t); 6877cc577a4SJonathan Peyton } else { 6887cc577a4SJonathan Peyton osize -= sizeof(bhead_t); 689bd3a7633SJonathan Peyton } 6907cc577a4SJonathan Peyton 6917cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(osize > 0); 6927cc577a4SJonathan Peyton 6937cc577a4SJonathan Peyton (void)KMP_MEMCPY((char *)nbuf, (char *)buf, /* Copy the data */ 6947cc577a4SJonathan Peyton (size_t)((size < osize) ? size : osize)); 6957cc577a4SJonathan Peyton brel(th, buf); 6967cc577a4SJonathan Peyton 6977cc577a4SJonathan Peyton return nbuf; 6987cc577a4SJonathan Peyton } 6997cc577a4SJonathan Peyton 7007cc577a4SJonathan Peyton /* BREL -- Release a buffer. */ 7013041982dSJonathan Peyton static void brel(kmp_info_t *th, void *buf) { 7027cc577a4SJonathan Peyton thr_data_t *thr = get_thr_data(th); 7037cc577a4SJonathan Peyton bfhead_t *b, *bn; 7047cc577a4SJonathan Peyton kmp_info_t *bth; 7057cc577a4SJonathan Peyton 7067cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(buf != NULL); 7077cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(((size_t)buf) % SizeQuant == 0); 7087cc577a4SJonathan Peyton 7097cc577a4SJonathan Peyton b = BFH(((char *)buf) - sizeof(bhead_t)); 7107cc577a4SJonathan Peyton 7117cc577a4SJonathan Peyton if (b->bh.bb.bsize == 0) { /* Directly-acquired buffer? */ 7127cc577a4SJonathan Peyton bdhead_t *bdh; 7137cc577a4SJonathan Peyton 7147cc577a4SJonathan Peyton bdh = BDH(((char *)buf) - sizeof(bdhead_t)); 7157cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(b->bh.bb.prevfree == 0); 7167cc577a4SJonathan Peyton #if BufStats 7177cc577a4SJonathan Peyton thr->totalloc -= (size_t)bdh->tsize; 7187cc577a4SJonathan Peyton thr->numdrel++; /* Number of direct releases */ 7197cc577a4SJonathan Peyton thr->numrel++; /* Increment number of brel() calls */ 7207cc577a4SJonathan Peyton #endif /* BufStats */ 7217cc577a4SJonathan Peyton #ifdef FreeWipe 7223041982dSJonathan Peyton (void)memset((char *)buf, 0x55, (size_t)(bdh->tsize - sizeof(bdhead_t))); 7237cc577a4SJonathan Peyton #endif /* FreeWipe */ 7247cc577a4SJonathan Peyton 7257cc577a4SJonathan Peyton KE_TRACE(10, ("%%%%%% FREE( %p )\n", (void *)bdh)); 7267cc577a4SJonathan Peyton 7277cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(thr->relfcn != 0); 7287cc577a4SJonathan Peyton (*thr->relfcn)((void *)bdh); /* Release it directly. */ 7297cc577a4SJonathan Peyton return; 7307cc577a4SJonathan Peyton } 7317cc577a4SJonathan Peyton 7323041982dSJonathan Peyton bth = (kmp_info_t *)((kmp_uintptr_t)TCR_PTR(b->bh.bb.bthr) & 7333041982dSJonathan Peyton ~1); // clear possible mark before comparison 7347cc577a4SJonathan Peyton if (bth != th) { 7357cc577a4SJonathan Peyton /* Add this buffer to be released by the owning thread later */ 7367cc577a4SJonathan Peyton __kmp_bget_enqueue(bth, buf 7377cc577a4SJonathan Peyton #ifdef USE_QUEUING_LOCK_FOR_BGET 7383041982dSJonathan Peyton , 7393041982dSJonathan Peyton __kmp_gtid_from_thread(th) 7407cc577a4SJonathan Peyton #endif 7417cc577a4SJonathan Peyton ); 7427cc577a4SJonathan Peyton return; 7437cc577a4SJonathan Peyton } 7447cc577a4SJonathan Peyton 7453041982dSJonathan Peyton /* Buffer size must be negative, indicating that the buffer is allocated. */ 7467cc577a4SJonathan Peyton if (b->bh.bb.bsize >= 0) { 7477cc577a4SJonathan Peyton bn = NULL; 7487cc577a4SJonathan Peyton } 7497cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(b->bh.bb.bsize < 0); 7507cc577a4SJonathan Peyton 7513041982dSJonathan Peyton /* Back pointer in next buffer must be zero, indicating the same thing: */ 7527cc577a4SJonathan Peyton 7537cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(BH((char *)b - b->bh.bb.bsize)->bb.prevfree == 0); 7547cc577a4SJonathan Peyton 7557cc577a4SJonathan Peyton #if BufStats 7567cc577a4SJonathan Peyton thr->numrel++; /* Increment number of brel() calls */ 7577cc577a4SJonathan Peyton thr->totalloc += (size_t)b->bh.bb.bsize; 7587cc577a4SJonathan Peyton #endif 7597cc577a4SJonathan Peyton 7607cc577a4SJonathan Peyton /* If the back link is nonzero, the previous buffer is free. */ 7617cc577a4SJonathan Peyton 7627cc577a4SJonathan Peyton if (b->bh.bb.prevfree != 0) { 7633041982dSJonathan Peyton /* The previous buffer is free. Consolidate this buffer with it by adding 7643041982dSJonathan Peyton the length of this buffer to the previous free buffer. Note that we 7653041982dSJonathan Peyton subtract the size in the buffer being released, since it's negative to 7663041982dSJonathan Peyton indicate that the buffer is allocated. */ 767414544c9SEd Maste bufsize size = b->bh.bb.bsize; 7687cc577a4SJonathan Peyton 7697cc577a4SJonathan Peyton /* Make the previous buffer the one we're working on. */ 7703041982dSJonathan Peyton KMP_DEBUG_ASSERT(BH((char *)b - b->bh.bb.prevfree)->bb.bsize == 7713041982dSJonathan Peyton b->bh.bb.prevfree); 7727cc577a4SJonathan Peyton b = BFH(((char *)b) - b->bh.bb.prevfree); 7737cc577a4SJonathan Peyton b->bh.bb.bsize -= size; 7747cc577a4SJonathan Peyton 7757cc577a4SJonathan Peyton /* unlink the buffer from the old freelist */ 7767cc577a4SJonathan Peyton __kmp_bget_remove_from_freelist(b); 7773041982dSJonathan Peyton } else { 7783041982dSJonathan Peyton /* The previous buffer isn't allocated. Mark this buffer size as positive 7793041982dSJonathan Peyton (i.e. free) and fall through to place the buffer on the free list as an 7803041982dSJonathan Peyton isolated free block. */ 7817cc577a4SJonathan Peyton b->bh.bb.bsize = -b->bh.bb.bsize; 7827cc577a4SJonathan Peyton } 7837cc577a4SJonathan Peyton 7847cc577a4SJonathan Peyton /* insert buffer back onto a new freelist */ 7857cc577a4SJonathan Peyton __kmp_bget_insert_into_freelist(thr, b); 7867cc577a4SJonathan Peyton 7877cc577a4SJonathan Peyton /* Now we look at the next buffer in memory, located by advancing from 7887cc577a4SJonathan Peyton the start of this buffer by its size, to see if that buffer is 7897cc577a4SJonathan Peyton free. If it is, we combine this buffer with the next one in 7907cc577a4SJonathan Peyton memory, dechaining the second buffer from the free list. */ 7917cc577a4SJonathan Peyton bn = BFH(((char *)b) + b->bh.bb.bsize); 7927cc577a4SJonathan Peyton if (bn->bh.bb.bsize > 0) { 7937cc577a4SJonathan Peyton 7947cc577a4SJonathan Peyton /* The buffer is free. Remove it from the free list and add 7957cc577a4SJonathan Peyton its size to that of our buffer. */ 7963041982dSJonathan Peyton KMP_DEBUG_ASSERT(BH((char *)bn + bn->bh.bb.bsize)->bb.prevfree == 7973041982dSJonathan Peyton bn->bh.bb.bsize); 7987cc577a4SJonathan Peyton 7997cc577a4SJonathan Peyton __kmp_bget_remove_from_freelist(bn); 8007cc577a4SJonathan Peyton 8017cc577a4SJonathan Peyton b->bh.bb.bsize += bn->bh.bb.bsize; 8027cc577a4SJonathan Peyton 8033041982dSJonathan Peyton /* unlink the buffer from the old freelist, and reinsert it into the new 8043041982dSJonathan Peyton * freelist */ 8057cc577a4SJonathan Peyton __kmp_bget_remove_from_freelist(b); 8067cc577a4SJonathan Peyton __kmp_bget_insert_into_freelist(thr, b); 8077cc577a4SJonathan Peyton 8087cc577a4SJonathan Peyton /* Finally, advance to the buffer that follows the newly 8097cc577a4SJonathan Peyton consolidated free block. We must set its backpointer to the 8107cc577a4SJonathan Peyton head of the consolidated free block. We know the next block 8117cc577a4SJonathan Peyton must be an allocated block because the process of recombination 8127cc577a4SJonathan Peyton guarantees that two free blocks will never be contiguous in 8137cc577a4SJonathan Peyton memory. */ 8147cc577a4SJonathan Peyton bn = BFH(((char *)b) + b->bh.bb.bsize); 8157cc577a4SJonathan Peyton } 8167cc577a4SJonathan Peyton #ifdef FreeWipe 8177cc577a4SJonathan Peyton (void)memset(((char *)b) + sizeof(bfhead_t), 0x55, 8187cc577a4SJonathan Peyton (size_t)(b->bh.bb.bsize - sizeof(bfhead_t))); 8197cc577a4SJonathan Peyton #endif 8207cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(bn->bh.bb.bsize < 0); 8217cc577a4SJonathan Peyton 8227cc577a4SJonathan Peyton /* The next buffer is allocated. Set the backpointer in it to point 8237cc577a4SJonathan Peyton to this buffer; the previous free buffer in memory. */ 8247cc577a4SJonathan Peyton 8257cc577a4SJonathan Peyton bn->bh.bb.prevfree = b->bh.bb.bsize; 8267cc577a4SJonathan Peyton 8277cc577a4SJonathan Peyton /* If a block-release function is defined, and this free buffer 8287cc577a4SJonathan Peyton constitutes the entire block, release it. Note that pool_len 8297cc577a4SJonathan Peyton is defined in such a way that the test will fail unless all 8307cc577a4SJonathan Peyton pool blocks are the same size. */ 8317cc577a4SJonathan Peyton if (thr->relfcn != 0 && 8323041982dSJonathan Peyton b->bh.bb.bsize == (bufsize)(thr->pool_len - sizeof(bhead_t))) { 8337cc577a4SJonathan Peyton #if BufStats 8343041982dSJonathan Peyton if (thr->numpblk != 8353041982dSJonathan Peyton 1) { /* Do not release the last buffer until finalization time */ 8367cc577a4SJonathan Peyton #endif 8377cc577a4SJonathan Peyton 8387cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(b->bh.bb.prevfree == 0); 8397cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(BH((char *)b + b->bh.bb.bsize)->bb.bsize == ESent); 8403041982dSJonathan Peyton KMP_DEBUG_ASSERT(BH((char *)b + b->bh.bb.bsize)->bb.prevfree == 8413041982dSJonathan Peyton b->bh.bb.bsize); 8427cc577a4SJonathan Peyton 8437cc577a4SJonathan Peyton /* Unlink the buffer from the free list */ 8447cc577a4SJonathan Peyton __kmp_bget_remove_from_freelist(b); 8457cc577a4SJonathan Peyton 8467cc577a4SJonathan Peyton KE_TRACE(10, ("%%%%%% FREE( %p )\n", (void *)b)); 8477cc577a4SJonathan Peyton 8487cc577a4SJonathan Peyton (*thr->relfcn)(b); 8497cc577a4SJonathan Peyton #if BufStats 8507cc577a4SJonathan Peyton thr->numprel++; /* Nr of expansion block releases */ 8517cc577a4SJonathan Peyton thr->numpblk--; /* Total number of blocks */ 8527cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(thr->numpblk == thr->numpget - thr->numprel); 8537cc577a4SJonathan Peyton 8543041982dSJonathan Peyton // avoid leaving stale last_pool pointer around if it is being dealloced 8553041982dSJonathan Peyton if (thr->last_pool == b) 8563041982dSJonathan Peyton thr->last_pool = 0; 8573041982dSJonathan Peyton } else { 8587cc577a4SJonathan Peyton thr->last_pool = b; 8597cc577a4SJonathan Peyton } 8607cc577a4SJonathan Peyton #endif /* BufStats */ 8617cc577a4SJonathan Peyton } 8627cc577a4SJonathan Peyton } 8637cc577a4SJonathan Peyton 8647cc577a4SJonathan Peyton /* BECTL -- Establish automatic pool expansion control */ 8653041982dSJonathan Peyton static void bectl(kmp_info_t *th, bget_compact_t compact, 8663041982dSJonathan Peyton bget_acquire_t acquire, bget_release_t release, 8673041982dSJonathan Peyton bufsize pool_incr) { 8687cc577a4SJonathan Peyton thr_data_t *thr = get_thr_data(th); 8697cc577a4SJonathan Peyton 8707cc577a4SJonathan Peyton thr->compfcn = compact; 8717cc577a4SJonathan Peyton thr->acqfcn = acquire; 8727cc577a4SJonathan Peyton thr->relfcn = release; 8737cc577a4SJonathan Peyton thr->exp_incr = pool_incr; 8747cc577a4SJonathan Peyton } 8757cc577a4SJonathan Peyton 8767cc577a4SJonathan Peyton /* BPOOL -- Add a region of memory to the buffer pool. */ 8773041982dSJonathan Peyton static void bpool(kmp_info_t *th, void *buf, bufsize len) { 8787cc577a4SJonathan Peyton /* int bin = 0; */ 8797cc577a4SJonathan Peyton thr_data_t *thr = get_thr_data(th); 8807cc577a4SJonathan Peyton bfhead_t *b = BFH(buf); 8817cc577a4SJonathan Peyton bhead_t *bn; 8827cc577a4SJonathan Peyton 8837cc577a4SJonathan Peyton __kmp_bget_dequeue(th); /* Release any queued buffers */ 8847cc577a4SJonathan Peyton 8857cc577a4SJonathan Peyton #ifdef SizeQuant 8867cc577a4SJonathan Peyton len &= ~(SizeQuant - 1); 8877cc577a4SJonathan Peyton #endif 8887cc577a4SJonathan Peyton if (thr->pool_len == 0) { 8897cc577a4SJonathan Peyton thr->pool_len = len; 8907cc577a4SJonathan Peyton } else if (len != thr->pool_len) { 8917cc577a4SJonathan Peyton thr->pool_len = -1; 8927cc577a4SJonathan Peyton } 8937cc577a4SJonathan Peyton #if BufStats 8947cc577a4SJonathan Peyton thr->numpget++; /* Number of block acquisitions */ 8957cc577a4SJonathan Peyton thr->numpblk++; /* Number of blocks total */ 8967cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(thr->numpblk == thr->numpget - thr->numprel); 8977cc577a4SJonathan Peyton #endif /* BufStats */ 8987cc577a4SJonathan Peyton 8997cc577a4SJonathan Peyton /* Since the block is initially occupied by a single free buffer, 9007cc577a4SJonathan Peyton it had better not be (much) larger than the largest buffer 9017cc577a4SJonathan Peyton whose size we can store in bhead.bb.bsize. */ 9027cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(len - sizeof(bhead_t) <= -((bufsize)ESent + 1)); 9037cc577a4SJonathan Peyton 9047cc577a4SJonathan Peyton /* Clear the backpointer at the start of the block to indicate that 9057cc577a4SJonathan Peyton there is no free block prior to this one. That blocks 9067cc577a4SJonathan Peyton recombination when the first block in memory is released. */ 9077cc577a4SJonathan Peyton b->bh.bb.prevfree = 0; 9087cc577a4SJonathan Peyton 9097cc577a4SJonathan Peyton /* Create a dummy allocated buffer at the end of the pool. This dummy 9107cc577a4SJonathan Peyton buffer is seen when a buffer at the end of the pool is released and 9117cc577a4SJonathan Peyton blocks recombination of the last buffer with the dummy buffer at 9127cc577a4SJonathan Peyton the end. The length in the dummy buffer is set to the largest 9137cc577a4SJonathan Peyton negative number to denote the end of the pool for diagnostic 9147cc577a4SJonathan Peyton routines (this specific value is not counted on by the actual 9157cc577a4SJonathan Peyton allocation and release functions). */ 9167cc577a4SJonathan Peyton len -= sizeof(bhead_t); 9177cc577a4SJonathan Peyton b->bh.bb.bsize = (bufsize)len; 9187cc577a4SJonathan Peyton /* Set the owner of this buffer */ 9193041982dSJonathan Peyton TCW_PTR(b->bh.bb.bthr, 9203041982dSJonathan Peyton (kmp_info_t *)((kmp_uintptr_t)th | 9213041982dSJonathan Peyton 1)); // mark the buffer as allocated address 9227cc577a4SJonathan Peyton 9237cc577a4SJonathan Peyton /* Chain the new block to the free list. */ 9247cc577a4SJonathan Peyton __kmp_bget_insert_into_freelist(thr, b); 9257cc577a4SJonathan Peyton 9267cc577a4SJonathan Peyton #ifdef FreeWipe 9277cc577a4SJonathan Peyton (void)memset(((char *)b) + sizeof(bfhead_t), 0x55, 9287cc577a4SJonathan Peyton (size_t)(len - sizeof(bfhead_t))); 9297cc577a4SJonathan Peyton #endif 9307cc577a4SJonathan Peyton bn = BH(((char *)b) + len); 9317cc577a4SJonathan Peyton bn->bb.prevfree = (bufsize)len; 9327cc577a4SJonathan Peyton /* Definition of ESent assumes two's complement! */ 9337cc577a4SJonathan Peyton KMP_DEBUG_ASSERT((~0) == -1 && (bn != 0)); 9347cc577a4SJonathan Peyton 9357cc577a4SJonathan Peyton bn->bb.bsize = ESent; 9367cc577a4SJonathan Peyton } 9377cc577a4SJonathan Peyton 9387cc577a4SJonathan Peyton /* BFREED -- Dump the free lists for this thread. */ 9393041982dSJonathan Peyton static void bfreed(kmp_info_t *th) { 9407cc577a4SJonathan Peyton int bin = 0, count = 0; 9417cc577a4SJonathan Peyton int gtid = __kmp_gtid_from_thread(th); 9427cc577a4SJonathan Peyton thr_data_t *thr = get_thr_data(th); 9437cc577a4SJonathan Peyton 9447cc577a4SJonathan Peyton #if BufStats 9453041982dSJonathan Peyton __kmp_printf_no_lock("__kmp_printpool: T#%d total=%" KMP_UINT64_SPEC 9463041982dSJonathan Peyton " get=%" KMP_INT64_SPEC " rel=%" KMP_INT64_SPEC 9473041982dSJonathan Peyton " pblk=%" KMP_INT64_SPEC " pget=%" KMP_INT64_SPEC 9483041982dSJonathan Peyton " prel=%" KMP_INT64_SPEC " dget=%" KMP_INT64_SPEC 9493041982dSJonathan Peyton " drel=%" KMP_INT64_SPEC "\n", 9503041982dSJonathan Peyton gtid, (kmp_uint64)thr->totalloc, (kmp_int64)thr->numget, 9513041982dSJonathan Peyton (kmp_int64)thr->numrel, (kmp_int64)thr->numpblk, 9527cc577a4SJonathan Peyton (kmp_int64)thr->numpget, (kmp_int64)thr->numprel, 9537cc577a4SJonathan Peyton (kmp_int64)thr->numdget, (kmp_int64)thr->numdrel); 9547cc577a4SJonathan Peyton #endif 9557cc577a4SJonathan Peyton 9567cc577a4SJonathan Peyton for (bin = 0; bin < MAX_BGET_BINS; ++bin) { 9577cc577a4SJonathan Peyton bfhead_t *b; 9587cc577a4SJonathan Peyton 9593041982dSJonathan Peyton for (b = thr->freelist[bin].ql.flink; b != &thr->freelist[bin]; 9603041982dSJonathan Peyton b = b->ql.flink) { 9617cc577a4SJonathan Peyton bufsize bs = b->bh.bb.bsize; 9627cc577a4SJonathan Peyton 9637cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(b->ql.blink->ql.flink == b); 9647cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(b->ql.flink->ql.blink == b); 9657cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(bs > 0); 9667cc577a4SJonathan Peyton 9677cc577a4SJonathan Peyton count += 1; 9687cc577a4SJonathan Peyton 9693041982dSJonathan Peyton __kmp_printf_no_lock( 9703041982dSJonathan Peyton "__kmp_printpool: T#%d Free block: 0x%p size %6ld bytes.\n", gtid, b, 9713041982dSJonathan Peyton (long)bs); 9727cc577a4SJonathan Peyton #ifdef FreeWipe 9737cc577a4SJonathan Peyton { 9747cc577a4SJonathan Peyton char *lerr = ((char *)b) + sizeof(bfhead_t); 9753041982dSJonathan Peyton if ((bs > sizeof(bfhead_t)) && 9763041982dSJonathan Peyton ((*lerr != 0x55) || 9773041982dSJonathan Peyton (memcmp(lerr, lerr + 1, (size_t)(bs - (sizeof(bfhead_t) + 1))) != 9783041982dSJonathan Peyton 0))) { 9793041982dSJonathan Peyton __kmp_printf_no_lock("__kmp_printpool: T#%d (Contents of above " 9803041982dSJonathan Peyton "free block have been overstored.)\n", 9813041982dSJonathan Peyton gtid); 9827cc577a4SJonathan Peyton } 9837cc577a4SJonathan Peyton } 9847cc577a4SJonathan Peyton #endif 9857cc577a4SJonathan Peyton } 9867cc577a4SJonathan Peyton } 9877cc577a4SJonathan Peyton 9887cc577a4SJonathan Peyton if (count == 0) 9897cc577a4SJonathan Peyton __kmp_printf_no_lock("__kmp_printpool: T#%d No free blocks\n", gtid); 9907cc577a4SJonathan Peyton } 9917cc577a4SJonathan Peyton 9923041982dSJonathan Peyton void __kmp_initialize_bget(kmp_info_t *th) { 9937cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(SizeQuant >= sizeof(void *) && (th != 0)); 9947cc577a4SJonathan Peyton 9957cc577a4SJonathan Peyton set_thr_data(th); 9967cc577a4SJonathan Peyton 9977cc577a4SJonathan Peyton bectl(th, (bget_compact_t)0, (bget_acquire_t)malloc, (bget_release_t)free, 9987cc577a4SJonathan Peyton (bufsize)__kmp_malloc_pool_incr); 9997cc577a4SJonathan Peyton } 10007cc577a4SJonathan Peyton 10013041982dSJonathan Peyton void __kmp_finalize_bget(kmp_info_t *th) { 10027cc577a4SJonathan Peyton thr_data_t *thr; 10037cc577a4SJonathan Peyton bfhead_t *b; 10047cc577a4SJonathan Peyton 10057cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(th != 0); 10067cc577a4SJonathan Peyton 10077cc577a4SJonathan Peyton #if BufStats 10087cc577a4SJonathan Peyton thr = (thr_data_t *)th->th.th_local.bget_data; 10097cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(thr != NULL); 10107cc577a4SJonathan Peyton b = thr->last_pool; 10117cc577a4SJonathan Peyton 10123041982dSJonathan Peyton /* If a block-release function is defined, and this free buffer constitutes 10133041982dSJonathan Peyton the entire block, release it. Note that pool_len is defined in such a way 10143041982dSJonathan Peyton that the test will fail unless all pool blocks are the same size. */ 10157cc577a4SJonathan Peyton 10163041982dSJonathan Peyton // Deallocate the last pool if one exists because we no longer do it in brel() 10177cc577a4SJonathan Peyton if (thr->relfcn != 0 && b != 0 && thr->numpblk != 0 && 10183041982dSJonathan Peyton b->bh.bb.bsize == (bufsize)(thr->pool_len - sizeof(bhead_t))) { 10197cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(b->bh.bb.prevfree == 0); 10207cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(BH((char *)b + b->bh.bb.bsize)->bb.bsize == ESent); 10213041982dSJonathan Peyton KMP_DEBUG_ASSERT(BH((char *)b + b->bh.bb.bsize)->bb.prevfree == 10223041982dSJonathan Peyton b->bh.bb.bsize); 10237cc577a4SJonathan Peyton 10247cc577a4SJonathan Peyton /* Unlink the buffer from the free list */ 10257cc577a4SJonathan Peyton __kmp_bget_remove_from_freelist(b); 10267cc577a4SJonathan Peyton 10277cc577a4SJonathan Peyton KE_TRACE(10, ("%%%%%% FREE( %p )\n", (void *)b)); 10287cc577a4SJonathan Peyton 10297cc577a4SJonathan Peyton (*thr->relfcn)(b); 10307cc577a4SJonathan Peyton thr->numprel++; /* Nr of expansion block releases */ 10317cc577a4SJonathan Peyton thr->numpblk--; /* Total number of blocks */ 10327cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(thr->numpblk == thr->numpget - thr->numprel); 10337cc577a4SJonathan Peyton } 10347cc577a4SJonathan Peyton #endif /* BufStats */ 10357cc577a4SJonathan Peyton 10367cc577a4SJonathan Peyton /* Deallocate bget_data */ 10377cc577a4SJonathan Peyton if (th->th.th_local.bget_data != NULL) { 10387cc577a4SJonathan Peyton __kmp_free(th->th.th_local.bget_data); 10397cc577a4SJonathan Peyton th->th.th_local.bget_data = NULL; 1040bd3a7633SJonathan Peyton } 10417cc577a4SJonathan Peyton } 10427cc577a4SJonathan Peyton 10433041982dSJonathan Peyton void kmpc_set_poolsize(size_t size) { 10447cc577a4SJonathan Peyton bectl(__kmp_get_thread(), (bget_compact_t)0, (bget_acquire_t)malloc, 10457cc577a4SJonathan Peyton (bget_release_t)free, (bufsize)size); 10467cc577a4SJonathan Peyton } 10477cc577a4SJonathan Peyton 10483041982dSJonathan Peyton size_t kmpc_get_poolsize(void) { 10497cc577a4SJonathan Peyton thr_data_t *p; 10507cc577a4SJonathan Peyton 10517cc577a4SJonathan Peyton p = get_thr_data(__kmp_get_thread()); 10527cc577a4SJonathan Peyton 10537cc577a4SJonathan Peyton return p->exp_incr; 10547cc577a4SJonathan Peyton } 10557cc577a4SJonathan Peyton 10563041982dSJonathan Peyton void kmpc_set_poolmode(int mode) { 10577cc577a4SJonathan Peyton thr_data_t *p; 10587cc577a4SJonathan Peyton 10593041982dSJonathan Peyton if (mode == bget_mode_fifo || mode == bget_mode_lifo || 10603041982dSJonathan Peyton mode == bget_mode_best) { 10617cc577a4SJonathan Peyton p = get_thr_data(__kmp_get_thread()); 10627cc577a4SJonathan Peyton p->mode = (bget_mode_t)mode; 10637cc577a4SJonathan Peyton } 10647cc577a4SJonathan Peyton } 10657cc577a4SJonathan Peyton 10663041982dSJonathan Peyton int kmpc_get_poolmode(void) { 10677cc577a4SJonathan Peyton thr_data_t *p; 10687cc577a4SJonathan Peyton 10697cc577a4SJonathan Peyton p = get_thr_data(__kmp_get_thread()); 10707cc577a4SJonathan Peyton 10717cc577a4SJonathan Peyton return p->mode; 10727cc577a4SJonathan Peyton } 10737cc577a4SJonathan Peyton 10743041982dSJonathan Peyton void kmpc_get_poolstat(size_t *maxmem, size_t *allmem) { 10757cc577a4SJonathan Peyton kmp_info_t *th = __kmp_get_thread(); 10767cc577a4SJonathan Peyton bufsize a, b; 10777cc577a4SJonathan Peyton 10787cc577a4SJonathan Peyton __kmp_bget_dequeue(th); /* Release any queued buffers */ 10797cc577a4SJonathan Peyton 10807cc577a4SJonathan Peyton bcheck(th, &a, &b); 10817cc577a4SJonathan Peyton 10827cc577a4SJonathan Peyton *maxmem = a; 10837cc577a4SJonathan Peyton *allmem = b; 10847cc577a4SJonathan Peyton } 10857cc577a4SJonathan Peyton 10863041982dSJonathan Peyton void kmpc_poolprint(void) { 10877cc577a4SJonathan Peyton kmp_info_t *th = __kmp_get_thread(); 10887cc577a4SJonathan Peyton 10897cc577a4SJonathan Peyton __kmp_bget_dequeue(th); /* Release any queued buffers */ 10907cc577a4SJonathan Peyton 10917cc577a4SJonathan Peyton bfreed(th); 10927cc577a4SJonathan Peyton } 10937cc577a4SJonathan Peyton 10947cc577a4SJonathan Peyton #endif // #if KMP_USE_BGET 10957cc577a4SJonathan Peyton 10963041982dSJonathan Peyton void *kmpc_malloc(size_t size) { 10977cc577a4SJonathan Peyton void *ptr; 10987cc577a4SJonathan Peyton ptr = bget(__kmp_entry_thread(), (bufsize)(size + sizeof(ptr))); 10997cc577a4SJonathan Peyton if (ptr != NULL) { 11007cc577a4SJonathan Peyton // save allocated pointer just before one returned to user 11017cc577a4SJonathan Peyton *(void **)ptr = ptr; 11027cc577a4SJonathan Peyton ptr = (void **)ptr + 1; 11037cc577a4SJonathan Peyton } 11047cc577a4SJonathan Peyton return ptr; 11057cc577a4SJonathan Peyton } 11067cc577a4SJonathan Peyton 11077cc577a4SJonathan Peyton #define IS_POWER_OF_TWO(n) (((n) & ((n)-1)) == 0) 11087cc577a4SJonathan Peyton 11093041982dSJonathan Peyton void *kmpc_aligned_malloc(size_t size, size_t alignment) { 11107cc577a4SJonathan Peyton void *ptr; 11117cc577a4SJonathan Peyton void *ptr_allocated; 11127cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(alignment < 32 * 1024); // Alignment should not be too big 11137cc577a4SJonathan Peyton if (!IS_POWER_OF_TWO(alignment)) { 11147cc577a4SJonathan Peyton // AC: do we need to issue a warning here? 11157cc577a4SJonathan Peyton errno = EINVAL; 11167cc577a4SJonathan Peyton return NULL; 11177cc577a4SJonathan Peyton } 11187cc577a4SJonathan Peyton size = size + sizeof(void *) + alignment; 11197cc577a4SJonathan Peyton ptr_allocated = bget(__kmp_entry_thread(), (bufsize)size); 11207cc577a4SJonathan Peyton if (ptr_allocated != NULL) { 11217cc577a4SJonathan Peyton // save allocated pointer just before one returned to user 11223041982dSJonathan Peyton ptr = (void *)(((kmp_uintptr_t)ptr_allocated + sizeof(void *) + alignment) & 11233041982dSJonathan Peyton ~(alignment - 1)); 11247cc577a4SJonathan Peyton *((void **)ptr - 1) = ptr_allocated; 11257cc577a4SJonathan Peyton } else { 11267cc577a4SJonathan Peyton ptr = NULL; 11277cc577a4SJonathan Peyton } 11287cc577a4SJonathan Peyton return ptr; 11297cc577a4SJonathan Peyton } 11307cc577a4SJonathan Peyton 11313041982dSJonathan Peyton void *kmpc_calloc(size_t nelem, size_t elsize) { 11327cc577a4SJonathan Peyton void *ptr; 11337cc577a4SJonathan Peyton ptr = bgetz(__kmp_entry_thread(), (bufsize)(nelem * elsize + sizeof(ptr))); 11347cc577a4SJonathan Peyton if (ptr != NULL) { 11357cc577a4SJonathan Peyton // save allocated pointer just before one returned to user 11367cc577a4SJonathan Peyton *(void **)ptr = ptr; 11377cc577a4SJonathan Peyton ptr = (void **)ptr + 1; 11387cc577a4SJonathan Peyton } 11397cc577a4SJonathan Peyton return ptr; 11407cc577a4SJonathan Peyton } 11417cc577a4SJonathan Peyton 11423041982dSJonathan Peyton void *kmpc_realloc(void *ptr, size_t size) { 11437cc577a4SJonathan Peyton void *result = NULL; 11447cc577a4SJonathan Peyton if (ptr == NULL) { 11457cc577a4SJonathan Peyton // If pointer is NULL, realloc behaves like malloc. 11467cc577a4SJonathan Peyton result = bget(__kmp_entry_thread(), (bufsize)(size + sizeof(ptr))); 11477cc577a4SJonathan Peyton // save allocated pointer just before one returned to user 11487cc577a4SJonathan Peyton if (result != NULL) { 11497cc577a4SJonathan Peyton *(void **)result = result; 11507cc577a4SJonathan Peyton result = (void **)result + 1; 11517cc577a4SJonathan Peyton } 11527cc577a4SJonathan Peyton } else if (size == 0) { 11537cc577a4SJonathan Peyton // If size is 0, realloc behaves like free. 11543041982dSJonathan Peyton // The thread must be registered by the call to kmpc_malloc() or 11553041982dSJonathan Peyton // kmpc_calloc() before. 11563041982dSJonathan Peyton // So it should be safe to call __kmp_get_thread(), not 11573041982dSJonathan Peyton // __kmp_entry_thread(). 11587cc577a4SJonathan Peyton KMP_ASSERT(*((void **)ptr - 1)); 11597cc577a4SJonathan Peyton brel(__kmp_get_thread(), *((void **)ptr - 1)); 11607cc577a4SJonathan Peyton } else { 11613041982dSJonathan Peyton result = bgetr(__kmp_entry_thread(), *((void **)ptr - 1), 11623041982dSJonathan Peyton (bufsize)(size + sizeof(ptr))); 11637cc577a4SJonathan Peyton if (result != NULL) { 11647cc577a4SJonathan Peyton *(void **)result = result; 11657cc577a4SJonathan Peyton result = (void **)result + 1; 11667cc577a4SJonathan Peyton } 1167bd3a7633SJonathan Peyton } 11687cc577a4SJonathan Peyton return result; 11697cc577a4SJonathan Peyton } 11707cc577a4SJonathan Peyton 11713041982dSJonathan Peyton // NOTE: the library must have already been initialized by a previous allocate 11723041982dSJonathan Peyton void kmpc_free(void *ptr) { 11737cc577a4SJonathan Peyton if (!__kmp_init_serial) { 11747cc577a4SJonathan Peyton return; 1175bd3a7633SJonathan Peyton } 11767cc577a4SJonathan Peyton if (ptr != NULL) { 11777cc577a4SJonathan Peyton kmp_info_t *th = __kmp_get_thread(); 11787cc577a4SJonathan Peyton __kmp_bget_dequeue(th); /* Release any queued buffers */ 11797cc577a4SJonathan Peyton // extract allocated pointer and free it 11807cc577a4SJonathan Peyton KMP_ASSERT(*((void **)ptr - 1)); 11817cc577a4SJonathan Peyton brel(th, *((void **)ptr - 1)); 1182bd3a7633SJonathan Peyton } 11837cc577a4SJonathan Peyton } 11847cc577a4SJonathan Peyton 11853041982dSJonathan Peyton void *___kmp_thread_malloc(kmp_info_t *th, size_t size KMP_SRC_LOC_DECL) { 11867cc577a4SJonathan Peyton void *ptr; 11873041982dSJonathan Peyton KE_TRACE(30, ("-> __kmp_thread_malloc( %p, %d ) called from %s:%d\n", th, 11883041982dSJonathan Peyton (int)size KMP_SRC_LOC_PARM)); 11897cc577a4SJonathan Peyton ptr = bget(th, (bufsize)size); 11907cc577a4SJonathan Peyton KE_TRACE(30, ("<- __kmp_thread_malloc() returns %p\n", ptr)); 11917cc577a4SJonathan Peyton return ptr; 11927cc577a4SJonathan Peyton } 11937cc577a4SJonathan Peyton 11943041982dSJonathan Peyton void *___kmp_thread_calloc(kmp_info_t *th, size_t nelem, 11953041982dSJonathan Peyton size_t elsize KMP_SRC_LOC_DECL) { 11967cc577a4SJonathan Peyton void *ptr; 11973041982dSJonathan Peyton KE_TRACE(30, ("-> __kmp_thread_calloc( %p, %d, %d ) called from %s:%d\n", th, 11983041982dSJonathan Peyton (int)nelem, (int)elsize KMP_SRC_LOC_PARM)); 11997cc577a4SJonathan Peyton ptr = bgetz(th, (bufsize)(nelem * elsize)); 12007cc577a4SJonathan Peyton KE_TRACE(30, ("<- __kmp_thread_calloc() returns %p\n", ptr)); 12017cc577a4SJonathan Peyton return ptr; 12027cc577a4SJonathan Peyton } 12037cc577a4SJonathan Peyton 12043041982dSJonathan Peyton void *___kmp_thread_realloc(kmp_info_t *th, void *ptr, 12053041982dSJonathan Peyton size_t size KMP_SRC_LOC_DECL) { 12063041982dSJonathan Peyton KE_TRACE(30, ("-> __kmp_thread_realloc( %p, %p, %d ) called from %s:%d\n", th, 12073041982dSJonathan Peyton ptr, (int)size KMP_SRC_LOC_PARM)); 12087cc577a4SJonathan Peyton ptr = bgetr(th, ptr, (bufsize)size); 12097cc577a4SJonathan Peyton KE_TRACE(30, ("<- __kmp_thread_realloc() returns %p\n", ptr)); 12107cc577a4SJonathan Peyton return ptr; 12117cc577a4SJonathan Peyton } 12127cc577a4SJonathan Peyton 12133041982dSJonathan Peyton void ___kmp_thread_free(kmp_info_t *th, void *ptr KMP_SRC_LOC_DECL) { 12143041982dSJonathan Peyton KE_TRACE(30, ("-> __kmp_thread_free( %p, %p ) called from %s:%d\n", th, 12153041982dSJonathan Peyton ptr KMP_SRC_LOC_PARM)); 12167cc577a4SJonathan Peyton if (ptr != NULL) { 12177cc577a4SJonathan Peyton __kmp_bget_dequeue(th); /* Release any queued buffers */ 12187cc577a4SJonathan Peyton brel(th, ptr); 12197cc577a4SJonathan Peyton } 12207cc577a4SJonathan Peyton KE_TRACE(30, ("<- __kmp_thread_free()\n")); 12217cc577a4SJonathan Peyton } 12227cc577a4SJonathan Peyton 122392ca6188SJonathan Peyton /* OMP 5.0 Memory Management support */ 122492ca6188SJonathan Peyton static const char *kmp_mk_lib_name; 122592ca6188SJonathan Peyton static void *h_memkind; 1226ebf1830bSJonathan Peyton /* memkind experimental API: */ 1227ebf1830bSJonathan Peyton // memkind_alloc 1228ebf1830bSJonathan Peyton static void *(*kmp_mk_alloc)(void *k, size_t sz); 1229ebf1830bSJonathan Peyton // memkind_free 1230ebf1830bSJonathan Peyton static void (*kmp_mk_free)(void *kind, void *ptr); 1231ebf1830bSJonathan Peyton // memkind_check_available 1232ebf1830bSJonathan Peyton static int (*kmp_mk_check)(void *kind); 1233ebf1830bSJonathan Peyton // kinds we are going to use 1234ebf1830bSJonathan Peyton static void **mk_default; 1235ebf1830bSJonathan Peyton static void **mk_interleave; 1236ebf1830bSJonathan Peyton static void **mk_hbw; 1237ebf1830bSJonathan Peyton static void **mk_hbw_interleave; 1238ebf1830bSJonathan Peyton static void **mk_hbw_preferred; 1239ebf1830bSJonathan Peyton static void **mk_hugetlb; 1240ebf1830bSJonathan Peyton static void **mk_hbw_hugetlb; 1241ebf1830bSJonathan Peyton static void **mk_hbw_preferred_hugetlb; 1242bba3a82bSHansang Bae static void **mk_dax_kmem; 1243bba3a82bSHansang Bae static void **mk_dax_kmem_all; 1244bba3a82bSHansang Bae static void **mk_dax_kmem_preferred; 1245ebf1830bSJonathan Peyton 1246ebf1830bSJonathan Peyton #if KMP_OS_UNIX && KMP_DYNAMIC_LIB 1247ebf1830bSJonathan Peyton static inline void chk_kind(void ***pkind) { 1248ebf1830bSJonathan Peyton KMP_DEBUG_ASSERT(pkind); 1249ebf1830bSJonathan Peyton if (*pkind) // symbol found 1250ebf1830bSJonathan Peyton if (kmp_mk_check(**pkind)) // kind not available or error 1251ebf1830bSJonathan Peyton *pkind = NULL; 1252ebf1830bSJonathan Peyton } 1253ebf1830bSJonathan Peyton #endif 125492ca6188SJonathan Peyton 125592ca6188SJonathan Peyton void __kmp_init_memkind() { 1256ebf1830bSJonathan Peyton // as of 2018-07-31 memkind does not support Windows*, exclude it for now 125792ca6188SJonathan Peyton #if KMP_OS_UNIX && KMP_DYNAMIC_LIB 1258ebf1830bSJonathan Peyton // use of statically linked memkind is problematic, as it depends on libnuma 125992ca6188SJonathan Peyton kmp_mk_lib_name = "libmemkind.so"; 126092ca6188SJonathan Peyton h_memkind = dlopen(kmp_mk_lib_name, RTLD_LAZY); 126192ca6188SJonathan Peyton if (h_memkind) { 1262ebf1830bSJonathan Peyton kmp_mk_check = (int (*)(void *))dlsym(h_memkind, "memkind_check_available"); 1263ebf1830bSJonathan Peyton kmp_mk_alloc = 1264ebf1830bSJonathan Peyton (void *(*)(void *, size_t))dlsym(h_memkind, "memkind_malloc"); 1265ebf1830bSJonathan Peyton kmp_mk_free = (void (*)(void *, void *))dlsym(h_memkind, "memkind_free"); 1266ebf1830bSJonathan Peyton mk_default = (void **)dlsym(h_memkind, "MEMKIND_DEFAULT"); 1267ebf1830bSJonathan Peyton if (kmp_mk_check && kmp_mk_alloc && kmp_mk_free && mk_default && 1268ebf1830bSJonathan Peyton !kmp_mk_check(*mk_default)) { 126992ca6188SJonathan Peyton __kmp_memkind_available = 1; 1270ebf1830bSJonathan Peyton mk_interleave = (void **)dlsym(h_memkind, "MEMKIND_INTERLEAVE"); 1271ebf1830bSJonathan Peyton chk_kind(&mk_interleave); 1272ebf1830bSJonathan Peyton mk_hbw = (void **)dlsym(h_memkind, "MEMKIND_HBW"); 1273ebf1830bSJonathan Peyton chk_kind(&mk_hbw); 1274ebf1830bSJonathan Peyton mk_hbw_interleave = (void **)dlsym(h_memkind, "MEMKIND_HBW_INTERLEAVE"); 1275ebf1830bSJonathan Peyton chk_kind(&mk_hbw_interleave); 1276ebf1830bSJonathan Peyton mk_hbw_preferred = (void **)dlsym(h_memkind, "MEMKIND_HBW_PREFERRED"); 1277ebf1830bSJonathan Peyton chk_kind(&mk_hbw_preferred); 1278ebf1830bSJonathan Peyton mk_hugetlb = (void **)dlsym(h_memkind, "MEMKIND_HUGETLB"); 1279ebf1830bSJonathan Peyton chk_kind(&mk_hugetlb); 1280ebf1830bSJonathan Peyton mk_hbw_hugetlb = (void **)dlsym(h_memkind, "MEMKIND_HBW_HUGETLB"); 1281ebf1830bSJonathan Peyton chk_kind(&mk_hbw_hugetlb); 1282ebf1830bSJonathan Peyton mk_hbw_preferred_hugetlb = 1283ebf1830bSJonathan Peyton (void **)dlsym(h_memkind, "MEMKIND_HBW_PREFERRED_HUGETLB"); 1284ebf1830bSJonathan Peyton chk_kind(&mk_hbw_preferred_hugetlb); 1285bba3a82bSHansang Bae mk_dax_kmem = (void **)dlsym(h_memkind, "MEMKIND_DAX_KMEM"); 1286bba3a82bSHansang Bae chk_kind(&mk_dax_kmem); 1287bba3a82bSHansang Bae mk_dax_kmem_all = (void **)dlsym(h_memkind, "MEMKIND_DAX_KMEM_ALL"); 1288bba3a82bSHansang Bae chk_kind(&mk_dax_kmem_all); 1289bba3a82bSHansang Bae mk_dax_kmem_preferred = 1290bba3a82bSHansang Bae (void **)dlsym(h_memkind, "MEMKIND_DAX_KMEM_PREFERRED"); 1291bba3a82bSHansang Bae chk_kind(&mk_dax_kmem_preferred); 1292ebf1830bSJonathan Peyton KE_TRACE(25, ("__kmp_init_memkind: memkind library initialized\n")); 1293ebf1830bSJonathan Peyton return; // success 129492ca6188SJonathan Peyton } 129592ca6188SJonathan Peyton dlclose(h_memkind); // failure 129692ca6188SJonathan Peyton } 1297bba3a82bSHansang Bae #else // !(KMP_OS_UNIX && KMP_DYNAMIC_LIB) 129892ca6188SJonathan Peyton kmp_mk_lib_name = ""; 1299bba3a82bSHansang Bae #endif // !(KMP_OS_UNIX && KMP_DYNAMIC_LIB) 130092ca6188SJonathan Peyton h_memkind = NULL; 1301ebf1830bSJonathan Peyton kmp_mk_check = NULL; 1302ebf1830bSJonathan Peyton kmp_mk_alloc = NULL; 1303ebf1830bSJonathan Peyton kmp_mk_free = NULL; 1304ebf1830bSJonathan Peyton mk_default = NULL; 1305ebf1830bSJonathan Peyton mk_interleave = NULL; 1306ebf1830bSJonathan Peyton mk_hbw = NULL; 1307ebf1830bSJonathan Peyton mk_hbw_interleave = NULL; 1308ebf1830bSJonathan Peyton mk_hbw_preferred = NULL; 1309ebf1830bSJonathan Peyton mk_hugetlb = NULL; 1310ebf1830bSJonathan Peyton mk_hbw_hugetlb = NULL; 1311ebf1830bSJonathan Peyton mk_hbw_preferred_hugetlb = NULL; 1312bba3a82bSHansang Bae mk_dax_kmem = NULL; 1313bba3a82bSHansang Bae mk_dax_kmem_all = NULL; 1314bba3a82bSHansang Bae mk_dax_kmem_preferred = NULL; 131592ca6188SJonathan Peyton } 131692ca6188SJonathan Peyton 131792ca6188SJonathan Peyton void __kmp_fini_memkind() { 131892ca6188SJonathan Peyton #if KMP_OS_UNIX && KMP_DYNAMIC_LIB 1319ebf1830bSJonathan Peyton if (__kmp_memkind_available) 1320ebf1830bSJonathan Peyton KE_TRACE(25, ("__kmp_fini_memkind: finalize memkind library\n")); 132192ca6188SJonathan Peyton if (h_memkind) { 132292ca6188SJonathan Peyton dlclose(h_memkind); 132392ca6188SJonathan Peyton h_memkind = NULL; 132492ca6188SJonathan Peyton } 1325ebf1830bSJonathan Peyton kmp_mk_check = NULL; 1326ebf1830bSJonathan Peyton kmp_mk_alloc = NULL; 1327ebf1830bSJonathan Peyton kmp_mk_free = NULL; 1328ebf1830bSJonathan Peyton mk_default = NULL; 1329ebf1830bSJonathan Peyton mk_interleave = NULL; 1330ebf1830bSJonathan Peyton mk_hbw = NULL; 1331ebf1830bSJonathan Peyton mk_hbw_interleave = NULL; 1332ebf1830bSJonathan Peyton mk_hbw_preferred = NULL; 1333ebf1830bSJonathan Peyton mk_hugetlb = NULL; 1334ebf1830bSJonathan Peyton mk_hbw_hugetlb = NULL; 1335ebf1830bSJonathan Peyton mk_hbw_preferred_hugetlb = NULL; 1336bba3a82bSHansang Bae mk_dax_kmem = NULL; 1337bba3a82bSHansang Bae mk_dax_kmem_all = NULL; 1338bba3a82bSHansang Bae mk_dax_kmem_preferred = NULL; 133992ca6188SJonathan Peyton #endif 134092ca6188SJonathan Peyton } 134192ca6188SJonathan Peyton 1342ebf1830bSJonathan Peyton omp_allocator_handle_t __kmpc_init_allocator(int gtid, omp_memspace_handle_t ms, 1343ebf1830bSJonathan Peyton int ntraits, 1344ebf1830bSJonathan Peyton omp_alloctrait_t traits[]) { 1345ebf1830bSJonathan Peyton // OpenMP 5.0 only allows predefined memspaces 1346ebf1830bSJonathan Peyton KMP_DEBUG_ASSERT(ms == omp_default_mem_space || ms == omp_low_lat_mem_space || 1347ebf1830bSJonathan Peyton ms == omp_large_cap_mem_space || ms == omp_const_mem_space || 1348ebf1830bSJonathan Peyton ms == omp_high_bw_mem_space); 1349ebf1830bSJonathan Peyton kmp_allocator_t *al; 1350ebf1830bSJonathan Peyton int i; 1351ebf1830bSJonathan Peyton al = (kmp_allocator_t *)__kmp_allocate(sizeof(kmp_allocator_t)); // zeroed 1352ebf1830bSJonathan Peyton al->memspace = ms; // not used currently 1353ebf1830bSJonathan Peyton for (i = 0; i < ntraits; ++i) { 1354ebf1830bSJonathan Peyton switch (traits[i].key) { 13556f0f0220SHansang Bae case omp_atk_sync_hint: 1356ad24cf2aSKelvin Li case omp_atk_access: 1357ad24cf2aSKelvin Li case omp_atk_pinned: 1358ebf1830bSJonathan Peyton break; 1359ad24cf2aSKelvin Li case omp_atk_alignment: 13606b316febSTerry Wilmarth __kmp_type_convert(traits[i].value, &(al->alignment)); 1361ebf1830bSJonathan Peyton KMP_ASSERT(IS_POWER_OF_TWO(al->alignment)); 1362ebf1830bSJonathan Peyton break; 1363ad24cf2aSKelvin Li case omp_atk_pool_size: 1364ebf1830bSJonathan Peyton al->pool_size = traits[i].value; 1365ebf1830bSJonathan Peyton break; 1366ad24cf2aSKelvin Li case omp_atk_fallback: 1367ebf1830bSJonathan Peyton al->fb = (omp_alloctrait_value_t)traits[i].value; 136892ca6188SJonathan Peyton KMP_DEBUG_ASSERT( 1369ad24cf2aSKelvin Li al->fb == omp_atv_default_mem_fb || al->fb == omp_atv_null_fb || 1370ad24cf2aSKelvin Li al->fb == omp_atv_abort_fb || al->fb == omp_atv_allocator_fb); 1371ebf1830bSJonathan Peyton break; 1372ad24cf2aSKelvin Li case omp_atk_fb_data: 1373ebf1830bSJonathan Peyton al->fb_data = RCAST(kmp_allocator_t *, traits[i].value); 1374ebf1830bSJonathan Peyton break; 1375ad24cf2aSKelvin Li case omp_atk_partition: 1376ebf1830bSJonathan Peyton al->memkind = RCAST(void **, traits[i].value); 1377ebf1830bSJonathan Peyton break; 1378ebf1830bSJonathan Peyton default: 1379ebf1830bSJonathan Peyton KMP_ASSERT2(0, "Unexpected allocator trait"); 1380ebf1830bSJonathan Peyton } 1381ebf1830bSJonathan Peyton } 1382ebf1830bSJonathan Peyton if (al->fb == 0) { 1383ebf1830bSJonathan Peyton // set default allocator 1384ad24cf2aSKelvin Li al->fb = omp_atv_default_mem_fb; 1385ebf1830bSJonathan Peyton al->fb_data = (kmp_allocator_t *)omp_default_mem_alloc; 1386ad24cf2aSKelvin Li } else if (al->fb == omp_atv_allocator_fb) { 1387ebf1830bSJonathan Peyton KMP_ASSERT(al->fb_data != NULL); 1388ad24cf2aSKelvin Li } else if (al->fb == omp_atv_default_mem_fb) { 1389ebf1830bSJonathan Peyton al->fb_data = (kmp_allocator_t *)omp_default_mem_alloc; 1390ebf1830bSJonathan Peyton } 1391ebf1830bSJonathan Peyton if (__kmp_memkind_available) { 1392ebf1830bSJonathan Peyton // Let's use memkind library if available 1393ebf1830bSJonathan Peyton if (ms == omp_high_bw_mem_space) { 1394ad24cf2aSKelvin Li if (al->memkind == (void *)omp_atv_interleaved && mk_hbw_interleave) { 1395ebf1830bSJonathan Peyton al->memkind = mk_hbw_interleave; 1396ebf1830bSJonathan Peyton } else if (mk_hbw_preferred) { 1397ebf1830bSJonathan Peyton // AC: do not try to use MEMKIND_HBW for now, because memkind library 1398ebf1830bSJonathan Peyton // cannot reliably detect exhaustion of HBW memory. 1399ebf1830bSJonathan Peyton // It could be possible using hbw_verify_memory_region() but memkind 1400ebf1830bSJonathan Peyton // manual says: "Using this function in production code may result in 1401ebf1830bSJonathan Peyton // serious performance penalty". 1402ebf1830bSJonathan Peyton al->memkind = mk_hbw_preferred; 1403ebf1830bSJonathan Peyton } else { 1404ebf1830bSJonathan Peyton // HBW is requested but not available --> return NULL allocator 1405ebf1830bSJonathan Peyton __kmp_free(al); 1406ebf1830bSJonathan Peyton return omp_null_allocator; 1407ebf1830bSJonathan Peyton } 1408bba3a82bSHansang Bae } else if (ms == omp_large_cap_mem_space) { 1409bba3a82bSHansang Bae if (mk_dax_kmem_all) { 1410bba3a82bSHansang Bae // All pmem nodes are visited 1411bba3a82bSHansang Bae al->memkind = mk_dax_kmem_all; 1412bba3a82bSHansang Bae } else if (mk_dax_kmem) { 1413bba3a82bSHansang Bae // Only closest pmem node is visited 1414bba3a82bSHansang Bae al->memkind = mk_dax_kmem; 1415bba3a82bSHansang Bae } else { 1416bba3a82bSHansang Bae __kmp_free(al); 1417bba3a82bSHansang Bae return omp_null_allocator; 1418bba3a82bSHansang Bae } 1419ebf1830bSJonathan Peyton } else { 1420ad24cf2aSKelvin Li if (al->memkind == (void *)omp_atv_interleaved && mk_interleave) { 1421ebf1830bSJonathan Peyton al->memkind = mk_interleave; 1422ebf1830bSJonathan Peyton } else { 1423ebf1830bSJonathan Peyton al->memkind = mk_default; 1424ebf1830bSJonathan Peyton } 1425ebf1830bSJonathan Peyton } 1426ebf1830bSJonathan Peyton } else { 1427ebf1830bSJonathan Peyton if (ms == omp_high_bw_mem_space) { 1428ebf1830bSJonathan Peyton // cannot detect HBW memory presence without memkind library 1429ebf1830bSJonathan Peyton __kmp_free(al); 1430ebf1830bSJonathan Peyton return omp_null_allocator; 1431ebf1830bSJonathan Peyton } 1432ebf1830bSJonathan Peyton } 1433ebf1830bSJonathan Peyton return (omp_allocator_handle_t)al; 1434ebf1830bSJonathan Peyton } 1435ebf1830bSJonathan Peyton 1436ebf1830bSJonathan Peyton void __kmpc_destroy_allocator(int gtid, omp_allocator_handle_t allocator) { 1437ebf1830bSJonathan Peyton if (allocator > kmp_max_mem_alloc) 1438ebf1830bSJonathan Peyton __kmp_free(allocator); 1439ebf1830bSJonathan Peyton } 1440ebf1830bSJonathan Peyton 1441ebf1830bSJonathan Peyton void __kmpc_set_default_allocator(int gtid, omp_allocator_handle_t allocator) { 1442ebf1830bSJonathan Peyton if (allocator == omp_null_allocator) 1443ebf1830bSJonathan Peyton allocator = omp_default_mem_alloc; 144492ca6188SJonathan Peyton __kmp_threads[gtid]->th.th_def_allocator = allocator; 144592ca6188SJonathan Peyton } 1446ebf1830bSJonathan Peyton 1447ebf1830bSJonathan Peyton omp_allocator_handle_t __kmpc_get_default_allocator(int gtid) { 144892ca6188SJonathan Peyton return __kmp_threads[gtid]->th.th_def_allocator; 144992ca6188SJonathan Peyton } 145092ca6188SJonathan Peyton 145192ca6188SJonathan Peyton typedef struct kmp_mem_desc { // Memory block descriptor 145292ca6188SJonathan Peyton void *ptr_alloc; // Pointer returned by allocator 145392ca6188SJonathan Peyton size_t size_a; // Size of allocated memory block (initial+descriptor+align) 14545439db05SNawrin Sultana size_t size_orig; // Original size requested 145592ca6188SJonathan Peyton void *ptr_align; // Pointer to aligned memory, returned 1456ebf1830bSJonathan Peyton kmp_allocator_t *allocator; // allocator 145792ca6188SJonathan Peyton } kmp_mem_desc_t; 145892ca6188SJonathan Peyton static int alignment = sizeof(void *); // let's align to pointer size 145992ca6188SJonathan Peyton 1460ebf1830bSJonathan Peyton void *__kmpc_alloc(int gtid, size_t size, omp_allocator_handle_t allocator) { 1461ebf1830bSJonathan Peyton void *ptr = NULL; 1462ebf1830bSJonathan Peyton kmp_allocator_t *al; 146392ca6188SJonathan Peyton KMP_DEBUG_ASSERT(__kmp_init_serial); 1464938f1b85SNawrin Sultana 1465938f1b85SNawrin Sultana if (size == 0) 1466938f1b85SNawrin Sultana return NULL; 1467938f1b85SNawrin Sultana 1468ebf1830bSJonathan Peyton if (allocator == omp_null_allocator) 146992ca6188SJonathan Peyton allocator = __kmp_threads[gtid]->th.th_def_allocator; 147092ca6188SJonathan Peyton 1471ebf1830bSJonathan Peyton KE_TRACE(25, ("__kmpc_alloc: T#%d (%d, %p)\n", gtid, (int)size, allocator)); 1472ebf1830bSJonathan Peyton al = RCAST(kmp_allocator_t *, CCAST(omp_allocator_handle_t, allocator)); 1473ebf1830bSJonathan Peyton 147492ca6188SJonathan Peyton int sz_desc = sizeof(kmp_mem_desc_t); 147592ca6188SJonathan Peyton kmp_mem_desc_t desc; 147692ca6188SJonathan Peyton kmp_uintptr_t addr; // address returned by allocator 147792ca6188SJonathan Peyton kmp_uintptr_t addr_align; // address to return to caller 147892ca6188SJonathan Peyton kmp_uintptr_t addr_descr; // address of memory block descriptor 1479ebf1830bSJonathan Peyton int align = alignment; // default alignment 1480ebf1830bSJonathan Peyton if (allocator > kmp_max_mem_alloc && al->alignment > 0) { 1481ebf1830bSJonathan Peyton align = al->alignment; // alignment requested by user 148292ca6188SJonathan Peyton } 14835439db05SNawrin Sultana desc.size_orig = size; 1484ebf1830bSJonathan Peyton desc.size_a = size + sz_desc + align; 148592ca6188SJonathan Peyton 1486ebf1830bSJonathan Peyton if (__kmp_memkind_available) { 1487ebf1830bSJonathan Peyton if (allocator < kmp_max_mem_alloc) { 1488ebf1830bSJonathan Peyton // pre-defined allocator 1489ebf1830bSJonathan Peyton if (allocator == omp_high_bw_mem_alloc && mk_hbw_preferred) { 1490ebf1830bSJonathan Peyton ptr = kmp_mk_alloc(*mk_hbw_preferred, desc.size_a); 1491bba3a82bSHansang Bae } else if (allocator == omp_large_cap_mem_alloc && mk_dax_kmem_all) { 1492bba3a82bSHansang Bae ptr = kmp_mk_alloc(*mk_dax_kmem_all, desc.size_a); 1493ebf1830bSJonathan Peyton } else { 1494ebf1830bSJonathan Peyton ptr = kmp_mk_alloc(*mk_default, desc.size_a); 1495ebf1830bSJonathan Peyton } 1496ebf1830bSJonathan Peyton } else if (al->pool_size > 0) { 1497ebf1830bSJonathan Peyton // custom allocator with pool size requested 1498ebf1830bSJonathan Peyton kmp_uint64 used = 1499ebf1830bSJonathan Peyton KMP_TEST_THEN_ADD64((kmp_int64 *)&al->pool_used, desc.size_a); 1500ebf1830bSJonathan Peyton if (used + desc.size_a > al->pool_size) { 1501ebf1830bSJonathan Peyton // not enough space, need to go fallback path 1502ebf1830bSJonathan Peyton KMP_TEST_THEN_ADD64((kmp_int64 *)&al->pool_used, -desc.size_a); 1503ad24cf2aSKelvin Li if (al->fb == omp_atv_default_mem_fb) { 1504ebf1830bSJonathan Peyton al = (kmp_allocator_t *)omp_default_mem_alloc; 1505ebf1830bSJonathan Peyton ptr = kmp_mk_alloc(*mk_default, desc.size_a); 1506ad24cf2aSKelvin Li } else if (al->fb == omp_atv_abort_fb) { 1507ebf1830bSJonathan Peyton KMP_ASSERT(0); // abort fallback requested 1508ad24cf2aSKelvin Li } else if (al->fb == omp_atv_allocator_fb) { 1509ebf1830bSJonathan Peyton KMP_ASSERT(al != al->fb_data); 1510ebf1830bSJonathan Peyton al = al->fb_data; 1511ebf1830bSJonathan Peyton return __kmpc_alloc(gtid, size, (omp_allocator_handle_t)al); 1512ebf1830bSJonathan Peyton } // else ptr == NULL; 1513ebf1830bSJonathan Peyton } else { 1514ebf1830bSJonathan Peyton // pool has enough space 1515ebf1830bSJonathan Peyton ptr = kmp_mk_alloc(*al->memkind, desc.size_a); 1516ebf1830bSJonathan Peyton if (ptr == NULL) { 1517ad24cf2aSKelvin Li if (al->fb == omp_atv_default_mem_fb) { 1518ebf1830bSJonathan Peyton al = (kmp_allocator_t *)omp_default_mem_alloc; 1519ebf1830bSJonathan Peyton ptr = kmp_mk_alloc(*mk_default, desc.size_a); 1520ad24cf2aSKelvin Li } else if (al->fb == omp_atv_abort_fb) { 1521ebf1830bSJonathan Peyton KMP_ASSERT(0); // abort fallback requested 1522ad24cf2aSKelvin Li } else if (al->fb == omp_atv_allocator_fb) { 1523ebf1830bSJonathan Peyton KMP_ASSERT(al != al->fb_data); 1524ebf1830bSJonathan Peyton al = al->fb_data; 1525ebf1830bSJonathan Peyton return __kmpc_alloc(gtid, size, (omp_allocator_handle_t)al); 1526ebf1830bSJonathan Peyton } 1527ebf1830bSJonathan Peyton } 1528ebf1830bSJonathan Peyton } 1529ebf1830bSJonathan Peyton } else { 1530ebf1830bSJonathan Peyton // custom allocator, pool size not requested 1531ebf1830bSJonathan Peyton ptr = kmp_mk_alloc(*al->memkind, desc.size_a); 1532ebf1830bSJonathan Peyton if (ptr == NULL) { 1533ad24cf2aSKelvin Li if (al->fb == omp_atv_default_mem_fb) { 1534ebf1830bSJonathan Peyton al = (kmp_allocator_t *)omp_default_mem_alloc; 1535ebf1830bSJonathan Peyton ptr = kmp_mk_alloc(*mk_default, desc.size_a); 1536ad24cf2aSKelvin Li } else if (al->fb == omp_atv_abort_fb) { 1537ebf1830bSJonathan Peyton KMP_ASSERT(0); // abort fallback requested 1538ad24cf2aSKelvin Li } else if (al->fb == omp_atv_allocator_fb) { 1539ebf1830bSJonathan Peyton KMP_ASSERT(al != al->fb_data); 1540ebf1830bSJonathan Peyton al = al->fb_data; 1541ebf1830bSJonathan Peyton return __kmpc_alloc(gtid, size, (omp_allocator_handle_t)al); 1542ebf1830bSJonathan Peyton } 1543ebf1830bSJonathan Peyton } 1544ebf1830bSJonathan Peyton } 1545ebf1830bSJonathan Peyton } else if (allocator < kmp_max_mem_alloc) { 1546ebf1830bSJonathan Peyton // pre-defined allocator 1547ebf1830bSJonathan Peyton if (allocator == omp_high_bw_mem_alloc) { 1548ebf1830bSJonathan Peyton // ptr = NULL; 1549bba3a82bSHansang Bae } else if (allocator == omp_large_cap_mem_alloc) { 1550bba3a82bSHansang Bae // warnings? 1551ebf1830bSJonathan Peyton } else { 1552ebf1830bSJonathan Peyton ptr = __kmp_thread_malloc(__kmp_thread_from_gtid(gtid), desc.size_a); 1553ebf1830bSJonathan Peyton } 1554ebf1830bSJonathan Peyton } else if (al->pool_size > 0) { 1555ebf1830bSJonathan Peyton // custom allocator with pool size requested 1556ebf1830bSJonathan Peyton kmp_uint64 used = 1557ebf1830bSJonathan Peyton KMP_TEST_THEN_ADD64((kmp_int64 *)&al->pool_used, desc.size_a); 1558ebf1830bSJonathan Peyton if (used + desc.size_a > al->pool_size) { 1559ebf1830bSJonathan Peyton // not enough space, need to go fallback path 1560ebf1830bSJonathan Peyton KMP_TEST_THEN_ADD64((kmp_int64 *)&al->pool_used, -desc.size_a); 1561ad24cf2aSKelvin Li if (al->fb == omp_atv_default_mem_fb) { 1562ebf1830bSJonathan Peyton al = (kmp_allocator_t *)omp_default_mem_alloc; 1563ebf1830bSJonathan Peyton ptr = __kmp_thread_malloc(__kmp_thread_from_gtid(gtid), desc.size_a); 1564ad24cf2aSKelvin Li } else if (al->fb == omp_atv_abort_fb) { 1565ebf1830bSJonathan Peyton KMP_ASSERT(0); // abort fallback requested 1566ad24cf2aSKelvin Li } else if (al->fb == omp_atv_allocator_fb) { 1567ebf1830bSJonathan Peyton KMP_ASSERT(al != al->fb_data); 1568ebf1830bSJonathan Peyton al = al->fb_data; 1569ebf1830bSJonathan Peyton return __kmpc_alloc(gtid, size, (omp_allocator_handle_t)al); 1570ebf1830bSJonathan Peyton } // else ptr == NULL; 1571ebf1830bSJonathan Peyton } else { 1572ebf1830bSJonathan Peyton // pool has enough space 1573ebf1830bSJonathan Peyton ptr = __kmp_thread_malloc(__kmp_thread_from_gtid(gtid), desc.size_a); 1574ad24cf2aSKelvin Li if (ptr == NULL && al->fb == omp_atv_abort_fb) { 1575ebf1830bSJonathan Peyton KMP_ASSERT(0); // abort fallback requested 1576ebf1830bSJonathan Peyton } // no sense to look for another fallback because of same internal alloc 1577ebf1830bSJonathan Peyton } 1578ebf1830bSJonathan Peyton } else { 1579ebf1830bSJonathan Peyton // custom allocator, pool size not requested 1580ebf1830bSJonathan Peyton ptr = __kmp_thread_malloc(__kmp_thread_from_gtid(gtid), desc.size_a); 1581ad24cf2aSKelvin Li if (ptr == NULL && al->fb == omp_atv_abort_fb) { 1582ebf1830bSJonathan Peyton KMP_ASSERT(0); // abort fallback requested 1583ebf1830bSJonathan Peyton } // no sense to look for another fallback because of same internal alloc 1584ebf1830bSJonathan Peyton } 1585ebf1830bSJonathan Peyton KE_TRACE(10, ("__kmpc_alloc: T#%d %p=alloc(%d)\n", gtid, ptr, desc.size_a)); 158692ca6188SJonathan Peyton if (ptr == NULL) 158792ca6188SJonathan Peyton return NULL; 158892ca6188SJonathan Peyton 158992ca6188SJonathan Peyton addr = (kmp_uintptr_t)ptr; 1590ebf1830bSJonathan Peyton addr_align = (addr + sz_desc + align - 1) & ~(align - 1); 159192ca6188SJonathan Peyton addr_descr = addr_align - sz_desc; 159292ca6188SJonathan Peyton 159392ca6188SJonathan Peyton desc.ptr_alloc = ptr; 159492ca6188SJonathan Peyton desc.ptr_align = (void *)addr_align; 1595ebf1830bSJonathan Peyton desc.allocator = al; 159692ca6188SJonathan Peyton *((kmp_mem_desc_t *)addr_descr) = desc; // save descriptor contents 159792ca6188SJonathan Peyton KMP_MB(); 159892ca6188SJonathan Peyton 159992ca6188SJonathan Peyton KE_TRACE(25, ("__kmpc_alloc returns %p, T#%d\n", desc.ptr_align, gtid)); 160092ca6188SJonathan Peyton return desc.ptr_align; 160192ca6188SJonathan Peyton } 160292ca6188SJonathan Peyton 1603938f1b85SNawrin Sultana void *__kmpc_calloc(int gtid, size_t nmemb, size_t size, 1604938f1b85SNawrin Sultana omp_allocator_handle_t allocator) { 1605938f1b85SNawrin Sultana void *ptr = NULL; 1606938f1b85SNawrin Sultana kmp_allocator_t *al; 1607938f1b85SNawrin Sultana KMP_DEBUG_ASSERT(__kmp_init_serial); 1608938f1b85SNawrin Sultana 1609938f1b85SNawrin Sultana if (allocator == omp_null_allocator) 1610938f1b85SNawrin Sultana allocator = __kmp_threads[gtid]->th.th_def_allocator; 1611938f1b85SNawrin Sultana 1612938f1b85SNawrin Sultana KE_TRACE(25, ("__kmpc_calloc: T#%d (%d, %d, %p)\n", gtid, (int)nmemb, 1613938f1b85SNawrin Sultana (int)size, allocator)); 1614938f1b85SNawrin Sultana 1615938f1b85SNawrin Sultana al = RCAST(kmp_allocator_t *, CCAST(omp_allocator_handle_t, allocator)); 1616938f1b85SNawrin Sultana 1617938f1b85SNawrin Sultana if (nmemb == 0 || size == 0) 1618938f1b85SNawrin Sultana return ptr; 1619938f1b85SNawrin Sultana 1620938f1b85SNawrin Sultana if ((SIZE_MAX - sizeof(kmp_mem_desc_t)) / size < nmemb) { 1621938f1b85SNawrin Sultana if (al->fb == omp_atv_abort_fb) { 1622938f1b85SNawrin Sultana KMP_ASSERT(0); 1623938f1b85SNawrin Sultana } 1624938f1b85SNawrin Sultana return ptr; 1625938f1b85SNawrin Sultana } 1626938f1b85SNawrin Sultana 1627938f1b85SNawrin Sultana ptr = __kmpc_alloc(gtid, nmemb * size, allocator); 1628938f1b85SNawrin Sultana 1629938f1b85SNawrin Sultana if (ptr) { 1630938f1b85SNawrin Sultana memset(ptr, 0x00, nmemb * size); 1631938f1b85SNawrin Sultana } 1632938f1b85SNawrin Sultana KE_TRACE(25, ("__kmpc_calloc returns %p, T#%d\n", ptr, gtid)); 1633938f1b85SNawrin Sultana return ptr; 1634938f1b85SNawrin Sultana } 1635938f1b85SNawrin Sultana 16365439db05SNawrin Sultana void *__kmpc_realloc(int gtid, void *ptr, size_t size, 16375439db05SNawrin Sultana omp_allocator_handle_t allocator, 16385439db05SNawrin Sultana omp_allocator_handle_t free_allocator) { 16395439db05SNawrin Sultana void *nptr = NULL; 16405439db05SNawrin Sultana KMP_DEBUG_ASSERT(__kmp_init_serial); 16415439db05SNawrin Sultana 16425439db05SNawrin Sultana if (size == 0) { 16435439db05SNawrin Sultana if (ptr != NULL) 16445439db05SNawrin Sultana __kmpc_free(gtid, ptr, free_allocator); 16455439db05SNawrin Sultana return nptr; 16465439db05SNawrin Sultana } 16475439db05SNawrin Sultana 16485439db05SNawrin Sultana KE_TRACE(25, ("__kmpc_realloc: T#%d (%p, %d, %p, %p)\n", gtid, ptr, (int)size, 16495439db05SNawrin Sultana allocator, free_allocator)); 16505439db05SNawrin Sultana 16515439db05SNawrin Sultana nptr = __kmpc_alloc(gtid, size, allocator); 16525439db05SNawrin Sultana 16535439db05SNawrin Sultana if (nptr != NULL && ptr != NULL) { 16545439db05SNawrin Sultana kmp_mem_desc_t desc; 16555439db05SNawrin Sultana kmp_uintptr_t addr_align; // address to return to caller 16565439db05SNawrin Sultana kmp_uintptr_t addr_descr; // address of memory block descriptor 16575439db05SNawrin Sultana 16585439db05SNawrin Sultana addr_align = (kmp_uintptr_t)ptr; 16595439db05SNawrin Sultana addr_descr = addr_align - sizeof(kmp_mem_desc_t); 16605439db05SNawrin Sultana desc = *((kmp_mem_desc_t *)addr_descr); // read descriptor 16615439db05SNawrin Sultana 16625439db05SNawrin Sultana KMP_DEBUG_ASSERT(desc.ptr_align == ptr); 16635439db05SNawrin Sultana KMP_DEBUG_ASSERT(desc.size_orig > 0); 16645439db05SNawrin Sultana KMP_DEBUG_ASSERT(desc.size_orig < desc.size_a); 16655439db05SNawrin Sultana KMP_MEMCPY((char *)nptr, (char *)ptr, 16665439db05SNawrin Sultana (size_t)((size < desc.size_orig) ? size : desc.size_orig)); 16675439db05SNawrin Sultana } 16685439db05SNawrin Sultana 16695439db05SNawrin Sultana if (nptr != NULL) { 16705439db05SNawrin Sultana __kmpc_free(gtid, ptr, free_allocator); 16715439db05SNawrin Sultana } 16725439db05SNawrin Sultana 16735439db05SNawrin Sultana KE_TRACE(25, ("__kmpc_realloc returns %p, T#%d\n", nptr, gtid)); 16745439db05SNawrin Sultana return nptr; 16755439db05SNawrin Sultana } 16765439db05SNawrin Sultana 1677ebf1830bSJonathan Peyton void __kmpc_free(int gtid, void *ptr, const omp_allocator_handle_t allocator) { 167892ca6188SJonathan Peyton KE_TRACE(25, ("__kmpc_free: T#%d free(%p,%p)\n", gtid, ptr, allocator)); 167992ca6188SJonathan Peyton if (ptr == NULL) 168092ca6188SJonathan Peyton return; 168192ca6188SJonathan Peyton 1682ebf1830bSJonathan Peyton kmp_allocator_t *al; 1683ebf1830bSJonathan Peyton omp_allocator_handle_t oal; 1684ebf1830bSJonathan Peyton al = RCAST(kmp_allocator_t *, CCAST(omp_allocator_handle_t, allocator)); 168592ca6188SJonathan Peyton kmp_mem_desc_t desc; 168692ca6188SJonathan Peyton kmp_uintptr_t addr_align; // address to return to caller 168792ca6188SJonathan Peyton kmp_uintptr_t addr_descr; // address of memory block descriptor 168892ca6188SJonathan Peyton 168992ca6188SJonathan Peyton addr_align = (kmp_uintptr_t)ptr; 169092ca6188SJonathan Peyton addr_descr = addr_align - sizeof(kmp_mem_desc_t); 169192ca6188SJonathan Peyton desc = *((kmp_mem_desc_t *)addr_descr); // read descriptor 169292ca6188SJonathan Peyton 169392ca6188SJonathan Peyton KMP_DEBUG_ASSERT(desc.ptr_align == ptr); 169492ca6188SJonathan Peyton if (allocator) { 1695ebf1830bSJonathan Peyton KMP_DEBUG_ASSERT(desc.allocator == al || desc.allocator == al->fb_data); 169692ca6188SJonathan Peyton } 1697ebf1830bSJonathan Peyton al = desc.allocator; 1698ebf1830bSJonathan Peyton oal = (omp_allocator_handle_t)al; // cast to void* for comparisons 1699ebf1830bSJonathan Peyton KMP_DEBUG_ASSERT(al); 170092ca6188SJonathan Peyton 1701ebf1830bSJonathan Peyton if (__kmp_memkind_available) { 1702ebf1830bSJonathan Peyton if (oal < kmp_max_mem_alloc) { 1703ebf1830bSJonathan Peyton // pre-defined allocator 1704ebf1830bSJonathan Peyton if (oal == omp_high_bw_mem_alloc && mk_hbw_preferred) { 1705ebf1830bSJonathan Peyton kmp_mk_free(*mk_hbw_preferred, desc.ptr_alloc); 1706bba3a82bSHansang Bae } else if (oal == omp_large_cap_mem_alloc && mk_dax_kmem_all) { 1707bba3a82bSHansang Bae kmp_mk_free(*mk_dax_kmem_all, desc.ptr_alloc); 1708ebf1830bSJonathan Peyton } else { 1709ebf1830bSJonathan Peyton kmp_mk_free(*mk_default, desc.ptr_alloc); 1710ebf1830bSJonathan Peyton } 1711ebf1830bSJonathan Peyton } else { 1712ebf1830bSJonathan Peyton if (al->pool_size > 0) { // custom allocator with pool size requested 1713ebf1830bSJonathan Peyton kmp_uint64 used = 1714ebf1830bSJonathan Peyton KMP_TEST_THEN_ADD64((kmp_int64 *)&al->pool_used, -desc.size_a); 1715ebf1830bSJonathan Peyton (void)used; // to suppress compiler warning 1716ebf1830bSJonathan Peyton KMP_DEBUG_ASSERT(used >= desc.size_a); 1717ebf1830bSJonathan Peyton } 1718ebf1830bSJonathan Peyton kmp_mk_free(*al->memkind, desc.ptr_alloc); 1719ebf1830bSJonathan Peyton } 1720ebf1830bSJonathan Peyton } else { 1721ebf1830bSJonathan Peyton if (oal > kmp_max_mem_alloc && al->pool_size > 0) { 1722ebf1830bSJonathan Peyton kmp_uint64 used = 1723ebf1830bSJonathan Peyton KMP_TEST_THEN_ADD64((kmp_int64 *)&al->pool_used, -desc.size_a); 1724ebf1830bSJonathan Peyton (void)used; // to suppress compiler warning 1725ebf1830bSJonathan Peyton KMP_DEBUG_ASSERT(used >= desc.size_a); 1726ebf1830bSJonathan Peyton } 1727ebf1830bSJonathan Peyton __kmp_thread_free(__kmp_thread_from_gtid(gtid), desc.ptr_alloc); 172892ca6188SJonathan Peyton } 172992ca6188SJonathan Peyton KE_TRACE(10, ("__kmpc_free: T#%d freed %p (%p)\n", gtid, desc.ptr_alloc, 173092ca6188SJonathan Peyton allocator)); 173192ca6188SJonathan Peyton } 173292ca6188SJonathan Peyton 17333041982dSJonathan Peyton /* If LEAK_MEMORY is defined, __kmp_free() will *not* free memory. It causes 17343041982dSJonathan Peyton memory leaks, but it may be useful for debugging memory corruptions, used 17353041982dSJonathan Peyton freed pointers, etc. */ 17367cc577a4SJonathan Peyton /* #define LEAK_MEMORY */ 17377cc577a4SJonathan Peyton struct kmp_mem_descr { // Memory block descriptor. 17387cc577a4SJonathan Peyton void *ptr_allocated; // Pointer returned by malloc(), subject for free(). 17397cc577a4SJonathan Peyton size_t size_allocated; // Size of allocated memory block. 17407cc577a4SJonathan Peyton void *ptr_aligned; // Pointer to aligned memory, to be used by client code. 17417cc577a4SJonathan Peyton size_t size_aligned; // Size of aligned memory block. 17427cc577a4SJonathan Peyton }; 17437cc577a4SJonathan Peyton typedef struct kmp_mem_descr kmp_mem_descr_t; 17447cc577a4SJonathan Peyton 17453041982dSJonathan Peyton /* Allocate memory on requested boundary, fill allocated memory with 0x00. 17463041982dSJonathan Peyton NULL is NEVER returned, __kmp_abort() is called in case of memory allocation 17473041982dSJonathan Peyton error. Must use __kmp_free when freeing memory allocated by this routine! */ 17483041982dSJonathan Peyton static void *___kmp_allocate_align(size_t size, 17493041982dSJonathan Peyton size_t alignment KMP_SRC_LOC_DECL) { 17503041982dSJonathan Peyton /* __kmp_allocate() allocates (by call to malloc()) bigger memory block than 17513041982dSJonathan Peyton requested to return properly aligned pointer. Original pointer returned 17523041982dSJonathan Peyton by malloc() and size of allocated block is saved in descriptor just 17533041982dSJonathan Peyton before the aligned pointer. This information used by __kmp_free() -- it 17543041982dSJonathan Peyton has to pass to free() original pointer, not aligned one. 17557cc577a4SJonathan Peyton 17567cc577a4SJonathan Peyton +---------+------------+-----------------------------------+---------+ 17577cc577a4SJonathan Peyton | padding | descriptor | aligned block | padding | 17587cc577a4SJonathan Peyton +---------+------------+-----------------------------------+---------+ 17597cc577a4SJonathan Peyton ^ ^ 17607cc577a4SJonathan Peyton | | 17617cc577a4SJonathan Peyton | +- Aligned pointer returned to caller 17627cc577a4SJonathan Peyton +- Pointer returned by malloc() 17637cc577a4SJonathan Peyton 17643041982dSJonathan Peyton Aligned block is filled with zeros, paddings are filled with 0xEF. */ 17657cc577a4SJonathan Peyton 17667cc577a4SJonathan Peyton kmp_mem_descr_t descr; 17677cc577a4SJonathan Peyton kmp_uintptr_t addr_allocated; // Address returned by malloc(). 17687cc577a4SJonathan Peyton kmp_uintptr_t addr_aligned; // Aligned address to return to caller. 17697cc577a4SJonathan Peyton kmp_uintptr_t addr_descr; // Address of memory block descriptor. 17707cc577a4SJonathan Peyton 17713041982dSJonathan Peyton KE_TRACE(25, ("-> ___kmp_allocate_align( %d, %d ) called from %s:%d\n", 17723041982dSJonathan Peyton (int)size, (int)alignment KMP_SRC_LOC_PARM)); 17737cc577a4SJonathan Peyton 17747cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(alignment < 32 * 1024); // Alignment should not be too 17757cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(sizeof(void *) <= sizeof(kmp_uintptr_t)); 17767cc577a4SJonathan Peyton // Make sure kmp_uintptr_t is enough to store addresses. 17777cc577a4SJonathan Peyton 17787cc577a4SJonathan Peyton descr.size_aligned = size; 17793041982dSJonathan Peyton descr.size_allocated = 17803041982dSJonathan Peyton descr.size_aligned + sizeof(kmp_mem_descr_t) + alignment; 17817cc577a4SJonathan Peyton 17827cc577a4SJonathan Peyton #if KMP_DEBUG 17837cc577a4SJonathan Peyton descr.ptr_allocated = _malloc_src_loc(descr.size_allocated, _file_, _line_); 17847cc577a4SJonathan Peyton #else 17857cc577a4SJonathan Peyton descr.ptr_allocated = malloc_src_loc(descr.size_allocated KMP_SRC_LOC_PARM); 17867cc577a4SJonathan Peyton #endif 17873041982dSJonathan Peyton KE_TRACE(10, (" malloc( %d ) returned %p\n", (int)descr.size_allocated, 17883041982dSJonathan Peyton descr.ptr_allocated)); 17897cc577a4SJonathan Peyton if (descr.ptr_allocated == NULL) { 17907cc577a4SJonathan Peyton KMP_FATAL(OutOfHeapMemory); 1791bd3a7633SJonathan Peyton } 17927cc577a4SJonathan Peyton 17937cc577a4SJonathan Peyton addr_allocated = (kmp_uintptr_t)descr.ptr_allocated; 17947cc577a4SJonathan Peyton addr_aligned = 17953041982dSJonathan Peyton (addr_allocated + sizeof(kmp_mem_descr_t) + alignment) & ~(alignment - 1); 17967cc577a4SJonathan Peyton addr_descr = addr_aligned - sizeof(kmp_mem_descr_t); 17977cc577a4SJonathan Peyton 17987cc577a4SJonathan Peyton descr.ptr_aligned = (void *)addr_aligned; 17997cc577a4SJonathan Peyton 18003041982dSJonathan Peyton KE_TRACE(26, (" ___kmp_allocate_align: " 18017cc577a4SJonathan Peyton "ptr_allocated=%p, size_allocated=%d, " 18027cc577a4SJonathan Peyton "ptr_aligned=%p, size_aligned=%d\n", 18033041982dSJonathan Peyton descr.ptr_allocated, (int)descr.size_allocated, 18043041982dSJonathan Peyton descr.ptr_aligned, (int)descr.size_aligned)); 18057cc577a4SJonathan Peyton 18067cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(addr_allocated <= addr_descr); 18077cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(addr_descr + sizeof(kmp_mem_descr_t) == addr_aligned); 18083041982dSJonathan Peyton KMP_DEBUG_ASSERT(addr_aligned + descr.size_aligned <= 18093041982dSJonathan Peyton addr_allocated + descr.size_allocated); 18107cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(addr_aligned % alignment == 0); 18117cc577a4SJonathan Peyton #ifdef KMP_DEBUG 18127cc577a4SJonathan Peyton memset(descr.ptr_allocated, 0xEF, descr.size_allocated); 18137cc577a4SJonathan Peyton // Fill allocated memory block with 0xEF. 18147cc577a4SJonathan Peyton #endif 18157cc577a4SJonathan Peyton memset(descr.ptr_aligned, 0x00, descr.size_aligned); 18163041982dSJonathan Peyton // Fill the aligned memory block (which is intended for using by caller) with 18173041982dSJonathan Peyton // 0x00. Do not 18183041982dSJonathan Peyton // put this filling under KMP_DEBUG condition! Many callers expect zeroed 18193041982dSJonathan Peyton // memory. (Padding 18207cc577a4SJonathan Peyton // bytes remain filled with 0xEF in debugging library.) 18217cc577a4SJonathan Peyton *((kmp_mem_descr_t *)addr_descr) = descr; 18227cc577a4SJonathan Peyton 18237cc577a4SJonathan Peyton KMP_MB(); 18247cc577a4SJonathan Peyton 18257cc577a4SJonathan Peyton KE_TRACE(25, ("<- ___kmp_allocate_align() returns %p\n", descr.ptr_aligned)); 18267cc577a4SJonathan Peyton return descr.ptr_aligned; 18277cc577a4SJonathan Peyton } // func ___kmp_allocate_align 18287cc577a4SJonathan Peyton 18293041982dSJonathan Peyton /* Allocate memory on cache line boundary, fill allocated memory with 0x00. 18307cc577a4SJonathan Peyton Do not call this func directly! Use __kmp_allocate macro instead. 18313041982dSJonathan Peyton NULL is NEVER returned, __kmp_abort() is called in case of memory allocation 18323041982dSJonathan Peyton error. Must use __kmp_free when freeing memory allocated by this routine! */ 18333041982dSJonathan Peyton void *___kmp_allocate(size_t size KMP_SRC_LOC_DECL) { 18347cc577a4SJonathan Peyton void *ptr; 18353041982dSJonathan Peyton KE_TRACE(25, ("-> __kmp_allocate( %d ) called from %s:%d\n", 18363041982dSJonathan Peyton (int)size KMP_SRC_LOC_PARM)); 18377cc577a4SJonathan Peyton ptr = ___kmp_allocate_align(size, __kmp_align_alloc KMP_SRC_LOC_PARM); 18387cc577a4SJonathan Peyton KE_TRACE(25, ("<- __kmp_allocate() returns %p\n", ptr)); 18397cc577a4SJonathan Peyton return ptr; 18407cc577a4SJonathan Peyton } // func ___kmp_allocate 18417cc577a4SJonathan Peyton 18423041982dSJonathan Peyton /* Allocate memory on page boundary, fill allocated memory with 0x00. 18437cc577a4SJonathan Peyton Does not call this func directly! Use __kmp_page_allocate macro instead. 18443041982dSJonathan Peyton NULL is NEVER returned, __kmp_abort() is called in case of memory allocation 18453041982dSJonathan Peyton error. Must use __kmp_free when freeing memory allocated by this routine! */ 18463041982dSJonathan Peyton void *___kmp_page_allocate(size_t size KMP_SRC_LOC_DECL) { 18477cc577a4SJonathan Peyton int page_size = 8 * 1024; 18487cc577a4SJonathan Peyton void *ptr; 18497cc577a4SJonathan Peyton 18503041982dSJonathan Peyton KE_TRACE(25, ("-> __kmp_page_allocate( %d ) called from %s:%d\n", 18513041982dSJonathan Peyton (int)size KMP_SRC_LOC_PARM)); 18527cc577a4SJonathan Peyton ptr = ___kmp_allocate_align(size, page_size KMP_SRC_LOC_PARM); 18537cc577a4SJonathan Peyton KE_TRACE(25, ("<- __kmp_page_allocate( %d ) returns %p\n", (int)size, ptr)); 18547cc577a4SJonathan Peyton return ptr; 18557cc577a4SJonathan Peyton } // ___kmp_page_allocate 18567cc577a4SJonathan Peyton 18573041982dSJonathan Peyton /* Free memory allocated by __kmp_allocate() and __kmp_page_allocate(). 18583041982dSJonathan Peyton In debug mode, fill the memory block with 0xEF before call to free(). */ 18593041982dSJonathan Peyton void ___kmp_free(void *ptr KMP_SRC_LOC_DECL) { 18607cc577a4SJonathan Peyton kmp_mem_descr_t descr; 18617cc577a4SJonathan Peyton kmp_uintptr_t addr_allocated; // Address returned by malloc(). 18627cc577a4SJonathan Peyton kmp_uintptr_t addr_aligned; // Aligned address passed by caller. 18637cc577a4SJonathan Peyton 18643041982dSJonathan Peyton KE_TRACE(25, 18653041982dSJonathan Peyton ("-> __kmp_free( %p ) called from %s:%d\n", ptr KMP_SRC_LOC_PARM)); 18667cc577a4SJonathan Peyton KMP_ASSERT(ptr != NULL); 18677cc577a4SJonathan Peyton 18687cc577a4SJonathan Peyton descr = *(kmp_mem_descr_t *)((kmp_uintptr_t)ptr - sizeof(kmp_mem_descr_t)); 18697cc577a4SJonathan Peyton 18707cc577a4SJonathan Peyton KE_TRACE(26, (" __kmp_free: " 18717cc577a4SJonathan Peyton "ptr_allocated=%p, size_allocated=%d, " 18727cc577a4SJonathan Peyton "ptr_aligned=%p, size_aligned=%d\n", 18737cc577a4SJonathan Peyton descr.ptr_allocated, (int)descr.size_allocated, 18747cc577a4SJonathan Peyton descr.ptr_aligned, (int)descr.size_aligned)); 18757cc577a4SJonathan Peyton 18767cc577a4SJonathan Peyton addr_allocated = (kmp_uintptr_t)descr.ptr_allocated; 18777cc577a4SJonathan Peyton addr_aligned = (kmp_uintptr_t)descr.ptr_aligned; 18787cc577a4SJonathan Peyton 18797cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(addr_aligned % CACHE_LINE == 0); 18807cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(descr.ptr_aligned == ptr); 18817cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(addr_allocated + sizeof(kmp_mem_descr_t) <= addr_aligned); 18827cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(descr.size_aligned < descr.size_allocated); 18833041982dSJonathan Peyton KMP_DEBUG_ASSERT(addr_aligned + descr.size_aligned <= 18843041982dSJonathan Peyton addr_allocated + descr.size_allocated); 18857cc577a4SJonathan Peyton 18867cc577a4SJonathan Peyton #ifdef KMP_DEBUG 18877cc577a4SJonathan Peyton memset(descr.ptr_allocated, 0xEF, descr.size_allocated); 18887cc577a4SJonathan Peyton // Fill memory block with 0xEF, it helps catch using freed memory. 18897cc577a4SJonathan Peyton #endif 18907cc577a4SJonathan Peyton 18917cc577a4SJonathan Peyton #ifndef LEAK_MEMORY 18927cc577a4SJonathan Peyton KE_TRACE(10, (" free( %p )\n", descr.ptr_allocated)); 18937cc577a4SJonathan Peyton #ifdef KMP_DEBUG 18947cc577a4SJonathan Peyton _free_src_loc(descr.ptr_allocated, _file_, _line_); 18957cc577a4SJonathan Peyton #else 18967cc577a4SJonathan Peyton free_src_loc(descr.ptr_allocated KMP_SRC_LOC_PARM); 18977cc577a4SJonathan Peyton #endif 18987cc577a4SJonathan Peyton #endif 18997cc577a4SJonathan Peyton KMP_MB(); 19007cc577a4SJonathan Peyton KE_TRACE(25, ("<- __kmp_free() returns\n")); 19017cc577a4SJonathan Peyton } // func ___kmp_free 19027cc577a4SJonathan Peyton 19037cc577a4SJonathan Peyton #if USE_FAST_MEMORY == 3 19047cc577a4SJonathan Peyton // Allocate fast memory by first scanning the thread's free lists 19057cc577a4SJonathan Peyton // If a chunk the right size exists, grab it off the free list. 19067cc577a4SJonathan Peyton // Otherwise allocate normally using kmp_thread_malloc. 19077cc577a4SJonathan Peyton 19087cc577a4SJonathan Peyton // AC: How to choose the limit? Just get 16 for now... 19097cc577a4SJonathan Peyton #define KMP_FREE_LIST_LIMIT 16 19107cc577a4SJonathan Peyton 19117cc577a4SJonathan Peyton // Always use 128 bytes for determining buckets for caching memory blocks 19127cc577a4SJonathan Peyton #define DCACHE_LINE 128 19137cc577a4SJonathan Peyton 19143041982dSJonathan Peyton void *___kmp_fast_allocate(kmp_info_t *this_thr, size_t size KMP_SRC_LOC_DECL) { 19157cc577a4SJonathan Peyton void *ptr; 19166b316febSTerry Wilmarth size_t num_lines, idx; 19177cc577a4SJonathan Peyton int index; 19187cc577a4SJonathan Peyton void *alloc_ptr; 19197cc577a4SJonathan Peyton size_t alloc_size; 19207cc577a4SJonathan Peyton kmp_mem_descr_t *descr; 19217cc577a4SJonathan Peyton 19227cc577a4SJonathan Peyton KE_TRACE(25, ("-> __kmp_fast_allocate( T#%d, %d ) called from %s:%d\n", 19237cc577a4SJonathan Peyton __kmp_gtid_from_thread(this_thr), (int)size KMP_SRC_LOC_PARM)); 19247cc577a4SJonathan Peyton 19257cc577a4SJonathan Peyton num_lines = (size + DCACHE_LINE - 1) / DCACHE_LINE; 19267cc577a4SJonathan Peyton idx = num_lines - 1; 19277cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(idx >= 0); 19287cc577a4SJonathan Peyton if (idx < 2) { 19297cc577a4SJonathan Peyton index = 0; // idx is [ 0, 1 ], use first free list 19307cc577a4SJonathan Peyton num_lines = 2; // 1, 2 cache lines or less than cache line 19317cc577a4SJonathan Peyton } else if ((idx >>= 2) == 0) { 19327cc577a4SJonathan Peyton index = 1; // idx is [ 2, 3 ], use second free list 19337cc577a4SJonathan Peyton num_lines = 4; // 3, 4 cache lines 19347cc577a4SJonathan Peyton } else if ((idx >>= 2) == 0) { 19357cc577a4SJonathan Peyton index = 2; // idx is [ 4, 15 ], use third free list 19367cc577a4SJonathan Peyton num_lines = 16; // 5, 6, ..., 16 cache lines 19377cc577a4SJonathan Peyton } else if ((idx >>= 2) == 0) { 19387cc577a4SJonathan Peyton index = 3; // idx is [ 16, 63 ], use fourth free list 19397cc577a4SJonathan Peyton num_lines = 64; // 17, 18, ..., 64 cache lines 19407cc577a4SJonathan Peyton } else { 19417cc577a4SJonathan Peyton goto alloc_call; // 65 or more cache lines ( > 8KB ), don't use free lists 19427cc577a4SJonathan Peyton } 19437cc577a4SJonathan Peyton 19447cc577a4SJonathan Peyton ptr = this_thr->th.th_free_lists[index].th_free_list_self; 19457cc577a4SJonathan Peyton if (ptr != NULL) { 19467cc577a4SJonathan Peyton // pop the head of no-sync free list 19477cc577a4SJonathan Peyton this_thr->th.th_free_lists[index].th_free_list_self = *((void **)ptr); 1948*309b00a4SShilei Tian KMP_DEBUG_ASSERT(this_thr == ((kmp_mem_descr_t *)((kmp_uintptr_t)ptr - 1949*309b00a4SShilei Tian sizeof(kmp_mem_descr_t))) 19503041982dSJonathan Peyton ->ptr_aligned); 19517cc577a4SJonathan Peyton goto end; 1952bd3a7633SJonathan Peyton } 19537cc577a4SJonathan Peyton ptr = TCR_SYNC_PTR(this_thr->th.th_free_lists[index].th_free_list_sync); 19547cc577a4SJonathan Peyton if (ptr != NULL) { 19553041982dSJonathan Peyton // no-sync free list is empty, use sync free list (filled in by other 19563041982dSJonathan Peyton // threads only) 19577cc577a4SJonathan Peyton // pop the head of the sync free list, push NULL instead 19587cc577a4SJonathan Peyton while (!KMP_COMPARE_AND_STORE_PTR( 19595ba90c79SAndrey Churbanov &this_thr->th.th_free_lists[index].th_free_list_sync, ptr, nullptr)) { 19607cc577a4SJonathan Peyton KMP_CPU_PAUSE(); 19617cc577a4SJonathan Peyton ptr = TCR_SYNC_PTR(this_thr->th.th_free_lists[index].th_free_list_sync); 19627cc577a4SJonathan Peyton } 19633041982dSJonathan Peyton // push the rest of chain into no-sync free list (can be NULL if there was 19643041982dSJonathan Peyton // the only block) 19657cc577a4SJonathan Peyton this_thr->th.th_free_lists[index].th_free_list_self = *((void **)ptr); 1966*309b00a4SShilei Tian KMP_DEBUG_ASSERT(this_thr == ((kmp_mem_descr_t *)((kmp_uintptr_t)ptr - 1967*309b00a4SShilei Tian sizeof(kmp_mem_descr_t))) 19683041982dSJonathan Peyton ->ptr_aligned); 19697cc577a4SJonathan Peyton goto end; 19707cc577a4SJonathan Peyton } 19717cc577a4SJonathan Peyton 19727cc577a4SJonathan Peyton alloc_call: 19737cc577a4SJonathan Peyton // haven't found block in the free lists, thus allocate it 19747cc577a4SJonathan Peyton size = num_lines * DCACHE_LINE; 19757cc577a4SJonathan Peyton 19767cc577a4SJonathan Peyton alloc_size = size + sizeof(kmp_mem_descr_t) + DCACHE_LINE; 19773041982dSJonathan Peyton KE_TRACE(25, ("__kmp_fast_allocate: T#%d Calling __kmp_thread_malloc with " 19783041982dSJonathan Peyton "alloc_size %d\n", 19797cc577a4SJonathan Peyton __kmp_gtid_from_thread(this_thr), alloc_size)); 19807cc577a4SJonathan Peyton alloc_ptr = bget(this_thr, (bufsize)alloc_size); 19817cc577a4SJonathan Peyton 19827cc577a4SJonathan Peyton // align ptr to DCACHE_LINE 19833041982dSJonathan Peyton ptr = (void *)((((kmp_uintptr_t)alloc_ptr) + sizeof(kmp_mem_descr_t) + 19843041982dSJonathan Peyton DCACHE_LINE) & 19853041982dSJonathan Peyton ~(DCACHE_LINE - 1)); 19867cc577a4SJonathan Peyton descr = (kmp_mem_descr_t *)(((kmp_uintptr_t)ptr) - sizeof(kmp_mem_descr_t)); 19877cc577a4SJonathan Peyton 19887cc577a4SJonathan Peyton descr->ptr_allocated = alloc_ptr; // remember allocated pointer 19897cc577a4SJonathan Peyton // we don't need size_allocated 19907cc577a4SJonathan Peyton descr->ptr_aligned = (void *)this_thr; // remember allocating thread 19917cc577a4SJonathan Peyton // (it is already saved in bget buffer, 19927cc577a4SJonathan Peyton // but we may want to use another allocator in future) 19937cc577a4SJonathan Peyton descr->size_aligned = size; 19947cc577a4SJonathan Peyton 19957cc577a4SJonathan Peyton end: 19967cc577a4SJonathan Peyton KE_TRACE(25, ("<- __kmp_fast_allocate( T#%d ) returns %p\n", 19977cc577a4SJonathan Peyton __kmp_gtid_from_thread(this_thr), ptr)); 19987cc577a4SJonathan Peyton return ptr; 19997cc577a4SJonathan Peyton } // func __kmp_fast_allocate 20007cc577a4SJonathan Peyton 20017cc577a4SJonathan Peyton // Free fast memory and place it on the thread's free list if it is of 20027cc577a4SJonathan Peyton // the correct size. 20033041982dSJonathan Peyton void ___kmp_fast_free(kmp_info_t *this_thr, void *ptr KMP_SRC_LOC_DECL) { 20047cc577a4SJonathan Peyton kmp_mem_descr_t *descr; 20057cc577a4SJonathan Peyton kmp_info_t *alloc_thr; 20067cc577a4SJonathan Peyton size_t size; 20077cc577a4SJonathan Peyton size_t idx; 20087cc577a4SJonathan Peyton int index; 20097cc577a4SJonathan Peyton 20107cc577a4SJonathan Peyton KE_TRACE(25, ("-> __kmp_fast_free( T#%d, %p ) called from %s:%d\n", 20117cc577a4SJonathan Peyton __kmp_gtid_from_thread(this_thr), ptr KMP_SRC_LOC_PARM)); 20127cc577a4SJonathan Peyton KMP_ASSERT(ptr != NULL); 20137cc577a4SJonathan Peyton 20147cc577a4SJonathan Peyton descr = (kmp_mem_descr_t *)(((kmp_uintptr_t)ptr) - sizeof(kmp_mem_descr_t)); 20157cc577a4SJonathan Peyton 20167cc577a4SJonathan Peyton KE_TRACE(26, (" __kmp_fast_free: size_aligned=%d\n", 20177cc577a4SJonathan Peyton (int)descr->size_aligned)); 20187cc577a4SJonathan Peyton 20197cc577a4SJonathan Peyton size = descr->size_aligned; // 2, 4, 16, 64, 65, 66, ... cache lines 20207cc577a4SJonathan Peyton 20217cc577a4SJonathan Peyton idx = DCACHE_LINE * 2; // 2 cache lines is minimal size of block 20227cc577a4SJonathan Peyton if (idx == size) { 20237cc577a4SJonathan Peyton index = 0; // 2 cache lines 20247cc577a4SJonathan Peyton } else if ((idx <<= 1) == size) { 20257cc577a4SJonathan Peyton index = 1; // 4 cache lines 20267cc577a4SJonathan Peyton } else if ((idx <<= 2) == size) { 20277cc577a4SJonathan Peyton index = 2; // 16 cache lines 20287cc577a4SJonathan Peyton } else if ((idx <<= 2) == size) { 20297cc577a4SJonathan Peyton index = 3; // 64 cache lines 20307cc577a4SJonathan Peyton } else { 20317cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(size > DCACHE_LINE * 64); 20327cc577a4SJonathan Peyton goto free_call; // 65 or more cache lines ( > 8KB ) 20337cc577a4SJonathan Peyton } 20347cc577a4SJonathan Peyton 20357cc577a4SJonathan Peyton alloc_thr = (kmp_info_t *)descr->ptr_aligned; // get thread owning the block 20367cc577a4SJonathan Peyton if (alloc_thr == this_thr) { 20377cc577a4SJonathan Peyton // push block to self no-sync free list, linking previous head (LIFO) 20387cc577a4SJonathan Peyton *((void **)ptr) = this_thr->th.th_free_lists[index].th_free_list_self; 20397cc577a4SJonathan Peyton this_thr->th.th_free_lists[index].th_free_list_self = ptr; 20407cc577a4SJonathan Peyton } else { 20417cc577a4SJonathan Peyton void *head = this_thr->th.th_free_lists[index].th_free_list_other; 20427cc577a4SJonathan Peyton if (head == NULL) { 20437cc577a4SJonathan Peyton // Create new free list 20447cc577a4SJonathan Peyton this_thr->th.th_free_lists[index].th_free_list_other = ptr; 20457cc577a4SJonathan Peyton *((void **)ptr) = NULL; // mark the tail of the list 20467cc577a4SJonathan Peyton descr->size_allocated = (size_t)1; // head of the list keeps its length 20477cc577a4SJonathan Peyton } else { 20487cc577a4SJonathan Peyton // need to check existed "other" list's owner thread and size of queue 20493041982dSJonathan Peyton kmp_mem_descr_t *dsc = 20503041982dSJonathan Peyton (kmp_mem_descr_t *)((char *)head - sizeof(kmp_mem_descr_t)); 20513041982dSJonathan Peyton // allocating thread, same for all queue nodes 20523041982dSJonathan Peyton kmp_info_t *q_th = (kmp_info_t *)(dsc->ptr_aligned); 20533041982dSJonathan Peyton size_t q_sz = 20543041982dSJonathan Peyton dsc->size_allocated + 1; // new size in case we add current task 20557cc577a4SJonathan Peyton if (q_th == alloc_thr && q_sz <= KMP_FREE_LIST_LIMIT) { 20567cc577a4SJonathan Peyton // we can add current task to "other" list, no sync needed 20577cc577a4SJonathan Peyton *((void **)ptr) = head; 20587cc577a4SJonathan Peyton descr->size_allocated = q_sz; 20597cc577a4SJonathan Peyton this_thr->th.th_free_lists[index].th_free_list_other = ptr; 20607cc577a4SJonathan Peyton } else { 20617cc577a4SJonathan Peyton // either queue blocks owner is changing or size limit exceeded 206242016791SKazuaki Ishizaki // return old queue to allocating thread (q_th) synchronously, 20637cc577a4SJonathan Peyton // and start new list for alloc_thr's tasks 20647cc577a4SJonathan Peyton void *old_ptr; 20657cc577a4SJonathan Peyton void *tail = head; 20667cc577a4SJonathan Peyton void *next = *((void **)head); 20677cc577a4SJonathan Peyton while (next != NULL) { 20687cc577a4SJonathan Peyton KMP_DEBUG_ASSERT( 20697cc577a4SJonathan Peyton // queue size should decrease by 1 each step through the list 20703041982dSJonathan Peyton ((kmp_mem_descr_t *)((char *)next - sizeof(kmp_mem_descr_t))) 20713041982dSJonathan Peyton ->size_allocated + 20723041982dSJonathan Peyton 1 == 20733041982dSJonathan Peyton ((kmp_mem_descr_t *)((char *)tail - sizeof(kmp_mem_descr_t))) 20743041982dSJonathan Peyton ->size_allocated); 20757cc577a4SJonathan Peyton tail = next; // remember tail node 20767cc577a4SJonathan Peyton next = *((void **)next); 20777cc577a4SJonathan Peyton } 20787cc577a4SJonathan Peyton KMP_DEBUG_ASSERT(q_th != NULL); 20797cc577a4SJonathan Peyton // push block to owner's sync free list 20807cc577a4SJonathan Peyton old_ptr = TCR_PTR(q_th->th.th_free_lists[index].th_free_list_sync); 20817cc577a4SJonathan Peyton /* the next pointer must be set before setting free_list to ptr to avoid 20827cc577a4SJonathan Peyton exposing a broken list to other threads, even for an instant. */ 20837cc577a4SJonathan Peyton *((void **)tail) = old_ptr; 20847cc577a4SJonathan Peyton 20857cc577a4SJonathan Peyton while (!KMP_COMPARE_AND_STORE_PTR( 20863041982dSJonathan Peyton &q_th->th.th_free_lists[index].th_free_list_sync, old_ptr, head)) { 20877cc577a4SJonathan Peyton KMP_CPU_PAUSE(); 20887cc577a4SJonathan Peyton old_ptr = TCR_PTR(q_th->th.th_free_lists[index].th_free_list_sync); 20897cc577a4SJonathan Peyton *((void **)tail) = old_ptr; 20907cc577a4SJonathan Peyton } 20917cc577a4SJonathan Peyton 20927cc577a4SJonathan Peyton // start new list of not-selt tasks 20937cc577a4SJonathan Peyton this_thr->th.th_free_lists[index].th_free_list_other = ptr; 20947cc577a4SJonathan Peyton *((void **)ptr) = NULL; 20957cc577a4SJonathan Peyton descr->size_allocated = (size_t)1; // head of queue keeps its length 20967cc577a4SJonathan Peyton } 20977cc577a4SJonathan Peyton } 20987cc577a4SJonathan Peyton } 20997cc577a4SJonathan Peyton goto end; 21007cc577a4SJonathan Peyton 21017cc577a4SJonathan Peyton free_call: 21027cc577a4SJonathan Peyton KE_TRACE(25, ("__kmp_fast_free: T#%d Calling __kmp_thread_free for size %d\n", 21037cc577a4SJonathan Peyton __kmp_gtid_from_thread(this_thr), size)); 21047cc577a4SJonathan Peyton __kmp_bget_dequeue(this_thr); /* Release any queued buffers */ 21057cc577a4SJonathan Peyton brel(this_thr, descr->ptr_allocated); 21067cc577a4SJonathan Peyton 21077cc577a4SJonathan Peyton end: 21087cc577a4SJonathan Peyton KE_TRACE(25, ("<- __kmp_fast_free() returns\n")); 21097cc577a4SJonathan Peyton 21107cc577a4SJonathan Peyton } // func __kmp_fast_free 21117cc577a4SJonathan Peyton 21127cc577a4SJonathan Peyton // Initialize the thread free lists related to fast memory 21137cc577a4SJonathan Peyton // Only do this when a thread is initially created. 21143041982dSJonathan Peyton void __kmp_initialize_fast_memory(kmp_info_t *this_thr) { 21157cc577a4SJonathan Peyton KE_TRACE(10, ("__kmp_initialize_fast_memory: Called from th %p\n", this_thr)); 21167cc577a4SJonathan Peyton 21177cc577a4SJonathan Peyton memset(this_thr->th.th_free_lists, 0, NUM_LISTS * sizeof(kmp_free_list_t)); 21187cc577a4SJonathan Peyton } 21197cc577a4SJonathan Peyton 21207cc577a4SJonathan Peyton // Free the memory in the thread free lists related to fast memory 21217cc577a4SJonathan Peyton // Only do this when a thread is being reaped (destroyed). 21223041982dSJonathan Peyton void __kmp_free_fast_memory(kmp_info_t *th) { 21237cc577a4SJonathan Peyton // Suppose we use BGET underlying allocator, walk through its structures... 21247cc577a4SJonathan Peyton int bin; 21257cc577a4SJonathan Peyton thr_data_t *thr = get_thr_data(th); 21267cc577a4SJonathan Peyton void **lst = NULL; 21277cc577a4SJonathan Peyton 21283041982dSJonathan Peyton KE_TRACE( 21293041982dSJonathan Peyton 5, ("__kmp_free_fast_memory: Called T#%d\n", __kmp_gtid_from_thread(th))); 21307cc577a4SJonathan Peyton 21317cc577a4SJonathan Peyton __kmp_bget_dequeue(th); // Release any queued buffers 21327cc577a4SJonathan Peyton 21337cc577a4SJonathan Peyton // Dig through free lists and extract all allocated blocks 21347cc577a4SJonathan Peyton for (bin = 0; bin < MAX_BGET_BINS; ++bin) { 21357cc577a4SJonathan Peyton bfhead_t *b = thr->freelist[bin].ql.flink; 21367cc577a4SJonathan Peyton while (b != &thr->freelist[bin]) { 21373041982dSJonathan Peyton if ((kmp_uintptr_t)b->bh.bb.bthr & 1) { // the buffer is allocated address 21383041982dSJonathan Peyton *((void **)b) = 21393041982dSJonathan Peyton lst; // link the list (override bthr, but keep flink yet) 21407cc577a4SJonathan Peyton lst = (void **)b; // push b into lst 21417cc577a4SJonathan Peyton } 21427cc577a4SJonathan Peyton b = b->ql.flink; // get next buffer 21437cc577a4SJonathan Peyton } 21447cc577a4SJonathan Peyton } 21457cc577a4SJonathan Peyton while (lst != NULL) { 21467cc577a4SJonathan Peyton void *next = *lst; 21477cc577a4SJonathan Peyton KE_TRACE(10, ("__kmp_free_fast_memory: freeing %p, next=%p th %p (%d)\n", 21487cc577a4SJonathan Peyton lst, next, th, __kmp_gtid_from_thread(th))); 21497cc577a4SJonathan Peyton (*thr->relfcn)(lst); 21507cc577a4SJonathan Peyton #if BufStats 21517cc577a4SJonathan Peyton // count blocks to prevent problems in __kmp_finalize_bget() 21527cc577a4SJonathan Peyton thr->numprel++; /* Nr of expansion block releases */ 21537cc577a4SJonathan Peyton thr->numpblk--; /* Total number of blocks */ 21547cc577a4SJonathan Peyton #endif 21557cc577a4SJonathan Peyton lst = (void **)next; 21567cc577a4SJonathan Peyton } 21577cc577a4SJonathan Peyton 21583041982dSJonathan Peyton KE_TRACE( 21593041982dSJonathan Peyton 5, ("__kmp_free_fast_memory: Freed T#%d\n", __kmp_gtid_from_thread(th))); 21607cc577a4SJonathan Peyton } 21617cc577a4SJonathan Peyton 21627cc577a4SJonathan Peyton #endif // USE_FAST_MEMORY 2163