github.com/moontrade/nogc@v0.1.7/alloc/rpmalloc/rpmalloc.h (about) 1 /* rpmalloc.h - Memory allocator - Public Domain - 2016 Mattias Jansson 2 * 3 * This library provides a cross-platform lock free thread caching malloc implementation in C11. 4 * The latest source code is always available at 5 * 6 * https://github.com/mjansson/rpmalloc 7 * 8 * This library is put in the public domain; you can redistribute it and/or modify it without any restrictions. 9 * 10 */ 11 12 #pragma once 13 14 #include <stddef.h> 15 16 #ifdef __cplusplus 17 extern "C" { 18 #endif 19 20 #if defined(__clang__) || defined(__GNUC__) 21 # define RPMALLOC_EXPORT __attribute__((visibility("default"))) 22 # define RPMALLOC_ALLOCATOR 23 # if (defined(__clang_major__) && (__clang_major__ < 4)) || (defined(__GNUC__) && defined(ENABLE_PRELOAD) && ENABLE_PRELOAD) 24 # define RPMALLOC_ATTRIB_MALLOC 25 # define RPMALLOC_ATTRIB_ALLOC_SIZE(size) 26 # define RPMALLOC_ATTRIB_ALLOC_SIZE2(count, size) 27 # else 28 # define RPMALLOC_ATTRIB_MALLOC __attribute__((__malloc__)) 29 # define RPMALLOC_ATTRIB_ALLOC_SIZE(size) __attribute__((alloc_size(size))) 30 # define RPMALLOC_ATTRIB_ALLOC_SIZE2(count, size) __attribute__((alloc_size(count, size))) 31 # endif 32 # define RPMALLOC_CDECL 33 #elif defined(_MSC_VER) 34 # define RPMALLOC_EXPORT 35 # define RPMALLOC_ALLOCATOR __declspec(allocator) __declspec(restrict) 36 # define RPMALLOC_ATTRIB_MALLOC 37 # define RPMALLOC_ATTRIB_ALLOC_SIZE(size) 38 # define RPMALLOC_ATTRIB_ALLOC_SIZE2(count,size) 39 # define RPMALLOC_CDECL __cdecl 40 #else 41 # define RPMALLOC_EXPORT 42 # define RPMALLOC_ALLOCATOR 43 # define RPMALLOC_ATTRIB_MALLOC 44 # define RPMALLOC_ATTRIB_ALLOC_SIZE(size) 45 # define RPMALLOC_ATTRIB_ALLOC_SIZE2(count,size) 46 # define RPMALLOC_CDECL 47 #endif 48 49 //! Define RPMALLOC_CONFIGURABLE to enable configuring sizes. Will introduce 50 // a very small overhead due to some size calculations not being compile time constants 51 #ifndef RPMALLOC_CONFIGURABLE 52 #define RPMALLOC_CONFIGURABLE 0 53 #endif 54 55 //! Define RPMALLOC_FIRST_CLASS_HEAPS to enable heap based API (rpmalloc_heap_* functions). 56 // Will introduce a very small overhead to track fully allocated spans in heaps 57 #ifndef RPMALLOC_FIRST_CLASS_HEAPS 58 #define RPMALLOC_FIRST_CLASS_HEAPS 1 59 #endif 60 61 //! Flag to rpaligned_realloc to not preserve content in reallocation 62 #define RPMALLOC_NO_PRESERVE 1 63 //! Flag to rpaligned_realloc to fail and return null pointer if grow cannot be done in-place, 64 // in which case the original pointer is still valid (just like a call to realloc which failes to allocate 65 // a new block). 66 #define RPMALLOC_GROW_OR_FAIL 2 67 68 typedef struct rpmalloc_global_statistics_t { 69 //! Current amount of virtual memory mapped, all of which might not have been committed (only if ENABLE_STATISTICS=1) 70 size_t mapped; 71 //! Peak amount of virtual memory mapped, all of which might not have been committed (only if ENABLE_STATISTICS=1) 72 size_t mapped_peak; 73 //! Current amount of memory in global caches for small and medium sizes (<32KiB) 74 size_t cached; 75 //! Current amount of memory allocated in huge allocations, i.e larger than LARGE_SIZE_LIMIT which is 2MiB by default (only if ENABLE_STATISTICS=1) 76 size_t huge_alloc; 77 //! Peak amount of memory allocated in huge allocations, i.e larger than LARGE_SIZE_LIMIT which is 2MiB by default (only if ENABLE_STATISTICS=1) 78 size_t huge_alloc_peak; 79 //! Total amount of memory mapped since initialization (only if ENABLE_STATISTICS=1) 80 size_t mapped_total; 81 //! Total amount of memory unmapped since initialization (only if ENABLE_STATISTICS=1) 82 size_t unmapped_total; 83 } rpmalloc_global_statistics_t; 84 85 typedef struct rpmalloc_thread_statistics_t { 86 //! Current number of bytes available in thread size class caches for small and medium sizes (<32KiB) 87 size_t sizecache; 88 //! Current number of bytes available in thread span caches for small and medium sizes (<32KiB) 89 size_t spancache; 90 //! Total number of bytes transitioned from thread cache to global cache (only if ENABLE_STATISTICS=1) 91 size_t thread_to_global; 92 //! Total number of bytes transitioned from global cache to thread cache (only if ENABLE_STATISTICS=1) 93 size_t global_to_thread; 94 //! Per span count statistics (only if ENABLE_STATISTICS=1) 95 struct { 96 //! Currently used number of spans 97 size_t current; 98 //! High water mark of spans used 99 size_t peak; 100 //! Number of spans transitioned to global cache 101 size_t to_global; 102 //! Number of spans transitioned from global cache 103 size_t from_global; 104 //! Number of spans transitioned to thread cache 105 size_t to_cache; 106 //! Number of spans transitioned from thread cache 107 size_t from_cache; 108 //! Number of spans transitioned to reserved state 109 size_t to_reserved; 110 //! Number of spans transitioned from reserved state 111 size_t from_reserved; 112 //! Number of raw memory map calls (not hitting the reserve spans but resulting in actual OS mmap calls) 113 size_t map_calls; 114 } span_use[64]; 115 //! Per size class statistics (only if ENABLE_STATISTICS=1) 116 struct { 117 //! Current number of allocations 118 size_t alloc_current; 119 //! Peak number of allocations 120 size_t alloc_peak; 121 //! Total number of allocations 122 size_t alloc_total; 123 //! Total number of frees 124 size_t free_total; 125 //! Number of spans transitioned to cache 126 size_t spans_to_cache; 127 //! Number of spans transitioned from cache 128 size_t spans_from_cache; 129 //! Number of spans transitioned from reserved state 130 size_t spans_from_reserved; 131 //! Number of raw memory map calls (not hitting the reserve spans but resulting in actual OS mmap calls) 132 size_t map_calls; 133 } size_use[128]; 134 } rpmalloc_thread_statistics_t; 135 136 typedef struct rpmalloc_config_t { 137 //! Map memory pages for the given number of bytes. The returned address MUST be 138 // aligned to the rpmalloc span size, which will always be a power of two. 139 // Optionally the function can store an alignment offset in the offset variable 140 // in case it performs alignment and the returned pointer is offset from the 141 // actual start of the memory region due to this alignment. The alignment offset 142 // will be passed to the memory unmap function. The alignment offset MUST NOT be 143 // larger than 65535 (storable in an uint16_t), if it is you must use natural 144 // alignment to shift it into 16 bits. If you set a memory_map function, you 145 // must also set a memory_unmap function or else the default implementation will 146 // be used for both. 147 void* (*memory_map)(size_t size, size_t* offset); 148 //! Unmap the memory pages starting at address and spanning the given number of bytes. 149 // If release is set to non-zero, the unmap is for an entire span range as returned by 150 // a previous call to memory_map and that the entire range should be released. The 151 // release argument holds the size of the entire span range. If release is set to 0, 152 // the unmap is a partial decommit of a subset of the mapped memory range. 153 // If you set a memory_unmap function, you must also set a memory_map function or 154 // else the default implementation will be used for both. 155 void (*memory_unmap)(void* address, size_t size, size_t offset, size_t release); 156 //! Called when an assert fails, if asserts are enabled. Will use the standard assert() 157 // if this is not set. 158 void (*error_callback)(const char* message); 159 //! Called when a call to map memory pages fails (out of memory). If this callback is 160 // not set or returns zero the library will return a null pointer in the allocation 161 // call. If this callback returns non-zero the map call will be retried. The argument 162 // passed is the number of bytes that was requested in the map call. Only used if 163 // the default system memory map function is used (memory_map callback is not set). 164 int (*map_fail_callback)(size_t size); 165 //! Size of memory pages. The page size MUST be a power of two. All memory mapping 166 // requests to memory_map will be made with size set to a multiple of the page size. 167 // Used if RPMALLOC_CONFIGURABLE is defined to 1, otherwise system page size is used. 168 size_t page_size; 169 //! Size of a span of memory blocks. MUST be a power of two, and in [4096,262144] 170 // range (unless 0 - set to 0 to use the default span size). Used if RPMALLOC_CONFIGURABLE 171 // is defined to 1. 172 size_t span_size; 173 //! Number of spans to map at each request to map new virtual memory blocks. This can 174 // be used to minimize the system call overhead at the cost of virtual memory address 175 // space. The extra mapped pages will not be written until actually used, so physical 176 // committed memory should not be affected in the default implementation. Will be 177 // aligned to a multiple of spans that match memory page size in case of huge pages. 178 size_t span_map_count; 179 //! Enable use of large/huge pages. If this flag is set to non-zero and page size is 180 // zero, the allocator will try to enable huge pages and auto detect the configuration. 181 // If this is set to non-zero and page_size is also non-zero, the allocator will 182 // assume huge pages have been configured and enabled prior to initializing the 183 // allocator. 184 // For Windows, see https://docs.microsoft.com/en-us/windows/desktop/memory/large-page-support 185 // For Linux, see https://www.kernel.org/doc/Documentation/vm/hugetlbpage.txt 186 int enable_huge_pages; 187 int unused; 188 } rpmalloc_config_t; 189 190 //! Initialize allocator with default configuration 191 RPMALLOC_EXPORT int 192 rpmalloc_initialize(void); 193 194 //! Initialize allocator with given configuration 195 RPMALLOC_EXPORT int 196 rpmalloc_initialize_config(const rpmalloc_config_t* config); 197 198 //! Get allocator configuration 199 RPMALLOC_EXPORT const rpmalloc_config_t* 200 rpmalloc_config(void); 201 202 //! Finalize allocator 203 RPMALLOC_EXPORT void 204 rpmalloc_finalize(void); 205 206 //! Initialize allocator for calling thread 207 RPMALLOC_EXPORT void 208 rpmalloc_thread_initialize(void); 209 210 //! Finalize allocator for calling thread 211 RPMALLOC_EXPORT void 212 rpmalloc_thread_finalize(int release_caches); 213 214 //! Perform deferred deallocations pending for the calling thread heap 215 RPMALLOC_EXPORT void 216 rpmalloc_thread_collect(void); 217 218 //! Query if allocator is initialized for calling thread 219 RPMALLOC_EXPORT int 220 rpmalloc_is_thread_initialized(void); 221 222 //! Get per-thread statistics 223 RPMALLOC_EXPORT void 224 rpmalloc_thread_statistics(rpmalloc_thread_statistics_t* stats); 225 226 //! Get global statistics 227 RPMALLOC_EXPORT void 228 rpmalloc_global_statistics(rpmalloc_global_statistics_t* stats); 229 230 //! Dump all statistics in human readable format to file (should be a FILE*) 231 RPMALLOC_EXPORT void 232 rpmalloc_dump_statistics(void* file); 233 234 //! Allocate a memory block of at least the given size 235 RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void* 236 rpmalloc(size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(1); 237 238 //! Free the given memory block 239 RPMALLOC_EXPORT void 240 rpfree(void* ptr); 241 242 //! Allocate a memory block of at least the given size and zero initialize it 243 RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void* 244 rpcalloc(size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(1, 2); 245 246 //! Reallocate the given block to at least the given size 247 RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void* 248 rprealloc(void* ptr, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2); 249 250 //! Reallocate the given block to at least the given size and alignment, 251 // with optional control flags (see RPMALLOC_NO_PRESERVE). 252 // Alignment must be a power of two and a multiple of sizeof(void*), 253 // and should ideally be less than memory page size. A caveat of rpmalloc 254 // internals is that this must also be strictly less than the span size (default 64KiB) 255 RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void* 256 rpaligned_realloc(void* ptr, size_t alignment, size_t size, size_t oldsize, unsigned int flags) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(3); 257 258 //! Allocate a memory block of at least the given size and alignment. 259 // Alignment must be a power of two and a multiple of sizeof(void*), 260 // and should ideally be less than memory page size. A caveat of rpmalloc 261 // internals is that this must also be strictly less than the span size (default 64KiB) 262 RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void* 263 rpaligned_alloc(size_t alignment, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2); 264 265 //! Allocate a memory block of at least the given size and alignment, and zero initialize it. 266 // Alignment must be a power of two and a multiple of sizeof(void*), 267 // and should ideally be less than memory page size. A caveat of rpmalloc 268 // internals is that this must also be strictly less than the span size (default 64KiB) 269 RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void* 270 rpaligned_calloc(size_t alignment, size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(2, 3); 271 272 //! Allocate a memory block of at least the given size and alignment. 273 // Alignment must be a power of two and a multiple of sizeof(void*), 274 // and should ideally be less than memory page size. A caveat of rpmalloc 275 // internals is that this must also be strictly less than the span size (default 64KiB) 276 RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void* 277 rpmemalign(size_t alignment, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2); 278 279 //! Allocate a memory block of at least the given size and alignment. 280 // Alignment must be a power of two and a multiple of sizeof(void*), 281 // and should ideally be less than memory page size. A caveat of rpmalloc 282 // internals is that this must also be strictly less than the span size (default 64KiB) 283 RPMALLOC_EXPORT int 284 rpposix_memalign(void** memptr, size_t alignment, size_t size); 285 286 //! Query the usable size of the given memory block (from given pointer to the end of block) 287 RPMALLOC_EXPORT size_t 288 rpmalloc_usable_size(void* ptr); 289 290 #if RPMALLOC_FIRST_CLASS_HEAPS 291 292 //! Heap type 293 typedef struct heap_t rpmalloc_heap_t; 294 295 //! Acquire a new heap. Will reuse existing released heaps or allocate memory for a new heap 296 // if none available. Heap API is implemented with the strict assumption that only one single 297 // thread will call heap functions for a given heap at any given time, no functions are thread safe. 298 RPMALLOC_EXPORT rpmalloc_heap_t* 299 rpmalloc_heap_acquire(void); 300 301 //! Release a heap (does NOT free the memory allocated by the heap, use rpmalloc_heap_free_all before destroying the heap). 302 // Releasing a heap will enable it to be reused by other threads. Safe to pass a null pointer. 303 RPMALLOC_EXPORT void 304 rpmalloc_heap_release(rpmalloc_heap_t* heap); 305 306 //! Allocate a memory block of at least the given size using the given heap. 307 RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void* 308 rpmalloc_heap_alloc(rpmalloc_heap_t* heap, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2); 309 310 //! Allocate a memory block of at least the given size using the given heap. The returned 311 // block will have the requested alignment. Alignment must be a power of two and a multiple of sizeof(void*), 312 // and should ideally be less than memory page size. A caveat of rpmalloc 313 // internals is that this must also be strictly less than the span size (default 64KiB). 314 RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void* 315 rpmalloc_heap_aligned_alloc(rpmalloc_heap_t* heap, size_t alignment, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(3); 316 317 //! Allocate a memory block of at least the given size using the given heap and zero initialize it. 318 RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void* 319 rpmalloc_heap_calloc(rpmalloc_heap_t* heap, size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(2, 3); 320 321 //! Allocate a memory block of at least the given size using the given heap and zero initialize it. The returned 322 // block will have the requested alignment. Alignment must either be zero, or a power of two and a multiple of sizeof(void*), 323 // and should ideally be less than memory page size. A caveat of rpmalloc 324 // internals is that this must also be strictly less than the span size (default 64KiB). 325 RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void* 326 rpmalloc_heap_aligned_calloc(rpmalloc_heap_t* heap, size_t alignment, size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(2, 3); 327 328 //! Reallocate the given block to at least the given size. The memory block MUST be allocated 329 // by the same heap given to this function. 330 RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void* 331 rpmalloc_heap_realloc(rpmalloc_heap_t* heap, void* ptr, size_t size, unsigned int flags) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(3); 332 333 //! Reallocate the given block to at least the given size. The memory block MUST be allocated 334 // by the same heap given to this function. The returned block will have the requested alignment. 335 // Alignment must be either zero, or a power of two and a multiple of sizeof(void*), and should ideally be 336 // less than memory page size. A caveat of rpmalloc internals is that this must also be strictly less than 337 // the span size (default 64KiB). 338 RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void* 339 rpmalloc_heap_aligned_realloc(rpmalloc_heap_t* heap, void* ptr, size_t alignment, size_t size, unsigned int flags) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(4); 340 341 //! Free the given memory block from the given heap. The memory block MUST be allocated 342 // by the same heap given to this function. 343 RPMALLOC_EXPORT void 344 rpmalloc_heap_free(rpmalloc_heap_t* heap, void* ptr); 345 346 //! Free all memory allocated by the heap 347 RPMALLOC_EXPORT void 348 rpmalloc_heap_free_all(rpmalloc_heap_t* heap); 349 350 //! Set the given heap as the current heap for the calling thread. A heap MUST only be current heap 351 // for a single thread, a heap can never be shared between multiple threads. The previous 352 // current heap for the calling thread is released to be reused by other threads. 353 RPMALLOC_EXPORT void 354 rpmalloc_heap_thread_set_current(rpmalloc_heap_t* heap); 355 356 #endif 357 358 #ifdef __cplusplus 359 } 360 #endif