diff --git a/include/mimalloc.h b/include/mimalloc.h index f4881319..ac4a63f9 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -58,8 +58,12 @@ terms of the MIT license. A copy of the license can be found in the file #define mi_attr_alloc_size2(s1,s2) #define mi_attr_alloc_align(p) #elif defined(__GNUC__) // includes clang and icc + #if defined(MI_SHARED_LIB) && defined(MI_SHARED_LIB_EXPORT) + #define mi_decl_export __attribute__((visibility("default"))) + #else + #define mi_decl_export + #endif #define mi_cdecl // leads to warnings... __attribute__((cdecl)) - #define mi_decl_export __attribute__((visibility("default"))) #define mi_decl_restrict #define mi_attr_malloc __attribute__((malloc)) #if (defined(__clang_major__) && (__clang_major__ < 4)) || (__GNUC__ < 5) diff --git a/src/alloc-override.c b/src/alloc-override.c index f97b6e78..af9035dd 100644 --- a/src/alloc-override.c +++ b/src/alloc-override.c @@ -173,7 +173,7 @@ extern "C" { void cfree(void* p) MI_FORWARD0(mi_free, p) void* reallocf(void* p, size_t newsize) MI_FORWARD2(mi_reallocf,p,newsize) size_t malloc_size(const void* p) MI_FORWARD1(mi_usable_size,p) -#if !defined(__ANDROID__) +#if !defined(__ANDROID__) && !defined(__FreeBSD__) size_t malloc_usable_size(void *p) MI_FORWARD1(mi_usable_size,p) #else size_t malloc_usable_size(const void *p) MI_FORWARD1(mi_usable_size,p) diff --git a/src/os.c b/src/os.c index 32aa57cf..2fed1143 100644 --- a/src/os.c +++ b/src/os.c @@ -39,6 +39,7 @@ terms of the MIT license. A copy of the license can be found in the file #include // sysconf #if defined(__linux__) #include +#include #if defined(__GLIBC__) #include // linux mmap flags #else @@ -51,6 +52,14 @@ terms of the MIT license. A copy of the license can be found in the file #include #endif #endif +#if defined(__FreeBSD__) || defined(__DragonFly__) +#include +#if __FreeBSD_version >= 1200000 +#include +#include +#endif +#include +#endif #endif /* ----------------------------------------------------------- @@ -77,6 +86,10 @@ static size_t os_alloc_granularity = 4096; // if non-zero, use large page allocation static size_t large_os_page_size = 0; +// is memory overcommit allowed? +// set dynamically in _mi_os_init (and if true we use MAP_NORESERVE) +static bool os_overcommit = true; + // OS (small) page size size_t _mi_os_page_size() { return os_page_size; @@ -165,7 +178,9 @@ static bool mi_win_enable_large_os_pages() return (ok!=0); } -void _mi_os_init(void) { +void _mi_os_init(void) +{ + os_overcommit = false; // get the page size SYSTEM_INFO si; GetSystemInfo(&si); @@ -200,10 +215,36 @@ void _mi_os_init(void) { } #elif defined(__wasi__) void _mi_os_init() { + os_overcommit = false; os_page_size = 0x10000; // WebAssembly has a fixed page size: 64KiB os_alloc_granularity = 16; } + +#else // generic unix + +static void os_detect_overcommit(void) { +#if defined(__linux__) + int fd = open("/proc/sys/vm/overcommit_memory", O_RDONLY); + if (fd < 0) return; + char buf[128]; + ssize_t nread = read(fd, &buf, sizeof(buf)); + close(fd); + // + // 0: heuristic overcommit, 1: always overcommit, 2: never overcommit (ignore NORESERVE) + if (nread >= 1) { + os_overcommit = (buf[0] == '0' || buf[0] == '1'); + } +#elif defined(__FreeBSD__) + int val = 0; + size_t olen = sizeof(val); + if (sysctlbyname("vm.overcommit", &val, &olen, NULL, 0) == 0) { + os_overcommit = (val != 0); + } #else + // default: overcommit is true +#endif +} + void _mi_os_init() { // get the page size long result = sysconf(_SC_PAGESIZE); @@ -212,6 +253,7 @@ void _mi_os_init() { os_alloc_granularity = os_page_size; } large_os_page_size = 2*MiB; // TODO: can we query the OS for this? + os_detect_overcommit(); } #endif @@ -401,8 +443,11 @@ static void* mi_unix_mmap(void* addr, size_t size, size_t try_alignment, int pro #if !defined(MAP_NORESERVE) #define MAP_NORESERVE 0 #endif - int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE; const int fd = mi_unix_mmap_fd(); + int flags = MAP_PRIVATE | MAP_ANONYMOUS; + if (os_overcommit) { + flags |= MAP_NORESERVE; + } #if defined(MAP_ALIGNED) // BSD if (try_alignment > 0) { size_t n = mi_bsr(try_alignment); @@ -1246,6 +1291,35 @@ static size_t mi_os_numa_node_countx(void) { } return (node+1); } +#elif defined(__FreeBSD__) && __FreeBSD_version >= 1200000 +static size_t mi_os_numa_nodex(void) { + domainset_t dom; + size_t node; + int policy; + if (cpuset_getdomain(CPU_LEVEL_CPUSET, CPU_WHICH_PID, -1, sizeof(dom), &dom, &policy) == -1) return 0ul; + for (node = 0; node < MAXMEMDOM; node++) { + if (DOMAINSET_ISSET(node, &dom)) return node; + } + return 0ul; +} +static size_t mi_os_numa_node_countx(void) { + size_t ndomains = 0; + size_t len = sizeof(ndomains); + if (sysctlbyname("vm.ndomains", &ndomains, &len, NULL, 0) == -1) return 0ul; + return ndomains; +} +#elif defined(__DragonFly__) +static size_t mi_os_numa_nodex(void) { + // TODO: DragonFly does not seem to provide any userland means to get this information. + return 0ul; +} +static size_t mi_os_numa_node_countx(void) { + size_t ncpus = 0, nvirtcoresperphys = 0; + size_t len = sizeof(size_t); + if (sysctlbyname("hw.ncpu", &ncpus, &len, NULL, 0) == -1) return 0ul; + if (sysctlbyname("hw.cpu_topology_ht_ids", &nvirtcoresperphys, &len, NULL, 0) == -1) return 0ul; + return nvirtcoresperphys * ncpus; +} #else static size_t mi_os_numa_nodex(void) { return 0;