merge from dev

This commit is contained in:
Daan 2021-10-19 12:55:10 -07:00
commit aeb73b0cd4
11 changed files with 45 additions and 37 deletions

View file

@ -43,7 +43,7 @@ set(mi_sources
src/init.c) src/init.c)
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# Converience: set default build type depending on the build directory # Convenience: set default build type depending on the build directory
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
if (NOT CMAKE_BUILD_TYPE) if (NOT CMAKE_BUILD_TYPE)
@ -224,7 +224,7 @@ else()
endif() endif()
string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_LC) string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_LC)
if(NOT(CMAKE_BUILD_TYPE_LC MATCHES "^(release|relwithdebinfo|minsizerel)$")) if(NOT(CMAKE_BUILD_TYPE_LC MATCHES "^(release|relwithdebinfo|minsizerel|none)$"))
set(mi_basename "${mi_basename}-${CMAKE_BUILD_TYPE_LC}") #append build type (e.g. -debug) if not a release version set(mi_basename "${mi_basename}-${CMAKE_BUILD_TYPE_LC}") #append build type (e.g. -debug) if not a release version
endif() endif()
if(MI_BUILD_SHARED) if(MI_BUILD_SHARED)

View file

@ -463,7 +463,7 @@ static inline mi_page_t* _mi_ptr_page(void* p) {
return _mi_segment_page_of(_mi_ptr_segment(p), p); return _mi_segment_page_of(_mi_ptr_segment(p), p);
} }
// Get the block size of a page (special cased for huge objects) // Get the block size of a page (special case for huge objects)
static inline size_t mi_page_block_size(const mi_page_t* page) { static inline size_t mi_page_block_size(const mi_page_t* page) {
const size_t bsize = page->xblock_size; const size_t bsize = page->xblock_size;
mi_assert_internal(bsize > 0); mi_assert_internal(bsize > 0);

View file

@ -105,11 +105,11 @@ terms of the MIT license. A copy of the license can be found in the file
// Main tuning parameters for segment and page sizes // Main tuning parameters for segment and page sizes
// Sizes for 64-bit, divide by two for 32-bit // Sizes for 64-bit, divide by two for 32-bit
#define MI_SEGMENT_SLICE_SHIFT (13 + MI_INTPTR_SHIFT) // 64kb #define MI_SEGMENT_SLICE_SHIFT (13 + MI_INTPTR_SHIFT) // 64KiB
#define MI_SEGMENT_SHIFT ( 7 + MI_SEGMENT_SLICE_SHIFT) // 8mb #define MI_SEGMENT_SHIFT ( 7 + MI_SEGMENT_SLICE_SHIFT) // 8MiB
#define MI_SMALL_PAGE_SHIFT (MI_SEGMENT_SLICE_SHIFT) // 64kb #define MI_SMALL_PAGE_SHIFT (MI_SEGMENT_SLICE_SHIFT) // 64KiB
#define MI_MEDIUM_PAGE_SHIFT ( 3 + MI_SMALL_PAGE_SHIFT) // 512kb #define MI_MEDIUM_PAGE_SHIFT ( 3 + MI_SMALL_PAGE_SHIFT) // 512KiB
// Derived constants // Derived constants
@ -122,12 +122,12 @@ terms of the MIT license. A copy of the license can be found in the file
#define MI_SMALL_PAGE_SIZE (1ULL<<MI_SMALL_PAGE_SHIFT) #define MI_SMALL_PAGE_SIZE (1ULL<<MI_SMALL_PAGE_SHIFT)
#define MI_MEDIUM_PAGE_SIZE (1ULL<<MI_MEDIUM_PAGE_SHIFT) #define MI_MEDIUM_PAGE_SIZE (1ULL<<MI_MEDIUM_PAGE_SHIFT)
#define MI_SMALL_OBJ_SIZE_MAX (MI_SMALL_PAGE_SIZE/4) // 8kb on 64-bit #define MI_SMALL_OBJ_SIZE_MAX (MI_SMALL_PAGE_SIZE/4) // 8KiB on 64-bit
#define MI_MEDIUM_OBJ_SIZE_MAX (MI_MEDIUM_PAGE_SIZE/4) // 128kb on 64-bit #define MI_MEDIUM_OBJ_SIZE_MAX (MI_MEDIUM_PAGE_SIZE/4) // 128KiB on 64-bit
#define MI_MEDIUM_OBJ_WSIZE_MAX (MI_MEDIUM_OBJ_SIZE_MAX/MI_INTPTR_SIZE) // 64kb on 64-bit #define MI_MEDIUM_OBJ_WSIZE_MAX (MI_MEDIUM_OBJ_SIZE_MAX/MI_INTPTR_SIZE)
#define MI_LARGE_OBJ_SIZE_MAX (MI_SEGMENT_SIZE/2) // 4mb on 64-bit #define MI_LARGE_OBJ_SIZE_MAX (MI_SEGMENT_SIZE/2) // 4MiB on 64-bit
#define MI_LARGE_OBJ_WSIZE_MAX (MI_LARGE_OBJ_SIZE_MAX/MI_INTPTR_SIZE) #define MI_LARGE_OBJ_WSIZE_MAX (MI_LARGE_OBJ_SIZE_MAX/MI_INTPTR_SIZE)
#define MI_HUGE_OBJ_SIZE_MAX (2*MI_INTPTR_SIZE*MI_SEGMENT_SIZE) // (must match MI_REGION_MAX_ALLOC_SIZE in memory.c) #define MI_HUGE_OBJ_SIZE_MAX (2*MI_INTPTR_SIZE*MI_SEGMENT_SIZE) // (must match MI_REGION_MAX_ALLOC_SIZE in memory.c)
@ -264,10 +264,10 @@ typedef struct mi_page_s {
typedef enum mi_page_kind_e { typedef enum mi_page_kind_e {
MI_PAGE_SMALL, // small blocks go into 64kb pages inside a segment MI_PAGE_SMALL, // small blocks go into 64KiB pages inside a segment
MI_PAGE_MEDIUM, // medium blocks go into 512kb pages inside a segment MI_PAGE_MEDIUM, // medium blocks go into medium pages inside a segment
MI_PAGE_LARGE, // larger blocks go into a page of just one block MI_PAGE_LARGE, // larger blocks go into a page of just one block
MI_PAGE_HUGE, // huge blocks (>16mb) are put into a single page in a single segment. MI_PAGE_HUGE, // huge blocks (> 16 MiB) are put into a single page in a single segment.
} mi_page_kind_t; } mi_page_kind_t;
typedef enum mi_segment_kind_e { typedef enum mi_segment_kind_e {
@ -355,7 +355,7 @@ typedef struct mi_random_cxt_s {
} mi_random_ctx_t; } mi_random_ctx_t;
// In debug mode there is a padding stucture at the end of the blocks to check for buffer overflows // In debug mode there is a padding structure at the end of the blocks to check for buffer overflows
#if (MI_PADDING) #if (MI_PADDING)
typedef struct mi_padding_s { typedef struct mi_padding_s {
uint32_t canary; // encoded block value to check validity of the padding (in case of overflow) uint32_t canary; // encoded block value to check validity of the padding (in case of overflow)

View file

@ -345,7 +345,7 @@ int mi_reserve_os_memory(size_t size, bool commit, bool allow_large) mi_attr_noe
_mi_verbose_message("failed to reserve %zu k memory\n", _mi_divide_up(size,1024)); _mi_verbose_message("failed to reserve %zu k memory\n", _mi_divide_up(size,1024));
return ENOMEM; return ENOMEM;
} }
_mi_verbose_message("reserved %zu kb memory%s\n", _mi_divide_up(size,1024), large ? " (in large os pages)" : ""); _mi_verbose_message("reserved %zu KiB memory%s\n", _mi_divide_up(size,1024), large ? " (in large os pages)" : "");
return 0; return 0;
} }
@ -389,10 +389,10 @@ int mi_reserve_huge_os_pages_at(size_t pages, int numa_node, size_t timeout_msec
size_t pages_reserved = 0; size_t pages_reserved = 0;
void* p = _mi_os_alloc_huge_os_pages(pages, numa_node, timeout_msecs, &pages_reserved, &hsize); void* p = _mi_os_alloc_huge_os_pages(pages, numa_node, timeout_msecs, &pages_reserved, &hsize);
if (p==NULL || pages_reserved==0) { if (p==NULL || pages_reserved==0) {
_mi_warning_message("failed to reserve %zu gb huge pages\n", pages); _mi_warning_message("failed to reserve %zu GiB huge pages\n", pages);
return ENOMEM; return ENOMEM;
} }
_mi_verbose_message("numa node %i: reserved %zu gb huge pages (of the %zu gb requested)\n", numa_node, pages_reserved, pages); _mi_verbose_message("numa node %i: reserved %zu GiB huge pages (of the %zu GiB requested)\n", numa_node, pages_reserved, pages);
if (!mi_manage_os_memory(p, hsize, true, true, true, numa_node)) { if (!mi_manage_os_memory(p, hsize, true, true, true, numa_node)) {
_mi_os_free_huge_pages(p, hsize, &_mi_stats_main); _mi_os_free_huge_pages(p, hsize, &_mi_stats_main);

View file

@ -333,7 +333,7 @@ void mi_heap_destroy(mi_heap_t* heap) {
Safe Heap delete Safe Heap delete
----------------------------------------------------------- */ ----------------------------------------------------------- */
// Tranfer the pages from one heap to the other // Transfer the pages from one heap to the other
static void mi_heap_absorb(mi_heap_t* heap, mi_heap_t* from) { static void mi_heap_absorb(mi_heap_t* heap, mi_heap_t* from) {
mi_assert_internal(heap!=NULL); mi_assert_internal(heap!=NULL);
if (from==NULL || from->page_count == 0) return; if (from==NULL || from->page_count == 0) return;

View file

@ -204,7 +204,7 @@ void _mi_os_init(void) {
} }
#elif defined(__wasi__) #elif defined(__wasi__)
void _mi_os_init() { void _mi_os_init() {
os_page_size = 0x10000; // WebAssembly has a fixed page size: 64KB os_page_size = 0x10000; // WebAssembly has a fixed page size: 64KiB
os_alloc_granularity = 16; os_alloc_granularity = 16;
} }
#else #else
@ -638,6 +638,10 @@ static void* mi_os_mem_alloc_aligned(size_t size, size_t alignment, bool commit,
mi_os_mem_free(p, over_size, commit, stats); mi_os_mem_free(p, over_size, commit, stats);
void* aligned_p = mi_align_up_ptr(p, alignment); void* aligned_p = mi_align_up_ptr(p, alignment);
p = mi_win_virtual_alloc(aligned_p, size, alignment, flags, false, allow_large, is_large); p = mi_win_virtual_alloc(aligned_p, size, alignment, flags, false, allow_large, is_large);
if (p != NULL) {
_mi_stat_increase(&stats->reserved, size);
if (commit) { _mi_stat_increase(&stats->committed, size); }
}
if (p == aligned_p) break; // success! if (p == aligned_p) break; // success!
if (p != NULL) { // should not happen? if (p != NULL) { // should not happen?
mi_os_mem_free(p, size, commit, stats); mi_os_mem_free(p, size, commit, stats);
@ -1024,7 +1028,7 @@ static void* mi_os_alloc_huge_os_pagesx(void* addr, size_t size, int numa_node)
else { else {
// fall back to regular large pages // fall back to regular large pages
mi_huge_pages_available = false; // don't try further huge pages mi_huge_pages_available = false; // don't try further huge pages
_mi_warning_message("unable to allocate using huge (1gb) pages, trying large (2mb) pages instead (status 0x%lx)\n", err); _mi_warning_message("unable to allocate using huge (1GiB) pages, trying large (2MiB) pages instead (status 0x%lx)\n", err);
} }
} }
// on modern Windows try use VirtualAlloc2 for numa aware large OS page allocation // on modern Windows try use VirtualAlloc2 for numa aware large OS page allocation
@ -1067,7 +1071,7 @@ static void* mi_os_alloc_huge_os_pagesx(void* addr, size_t size, int numa_node)
// see: <https://lkml.org/lkml/2017/2/9/875> // see: <https://lkml.org/lkml/2017/2/9/875>
long err = mi_os_mbind(p, size, MPOL_PREFERRED, &numa_mask, 8*MI_INTPTR_SIZE, 0); long err = mi_os_mbind(p, size, MPOL_PREFERRED, &numa_mask, 8*MI_INTPTR_SIZE, 0);
if (err != 0) { if (err != 0) {
_mi_warning_message("failed to bind huge (1gb) pages to numa node %d: %s\n", numa_node, strerror(errno)); _mi_warning_message("failed to bind huge (1GiB) pages to numa node %d: %s\n", numa_node, strerror(errno));
} }
} }
return p; return p;

View file

@ -7,7 +7,7 @@ terms of the MIT license. A copy of the license can be found in the file
/* ----------------------------------------------------------- /* -----------------------------------------------------------
The core of the allocator. Every segment contains The core of the allocator. Every segment contains
pages of a {certain block size. The main function pages of a certain block size. The main function
exported is `mi_malloc_generic`. exported is `mi_malloc_generic`.
----------------------------------------------------------- */ ----------------------------------------------------------- */

View file

@ -198,8 +198,10 @@ static bool os_random_buf(void* buf, size_t buf_len) {
arc4random_buf(buf, buf_len); arc4random_buf(buf, buf_len);
return true; return true;
} }
#elif defined(__linux__) #elif defined(__linux__) || defined(__HAIKU__)
#if defined(__linux__)
#include <sys/syscall.h> #include <sys/syscall.h>
#endif
#include <unistd.h> #include <unistd.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>

View file

@ -18,9 +18,6 @@ static void mi_segment_delayed_decommit(mi_segment_t* segment, bool force, mi_st
/* -------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------
Segment allocation Segment allocation
In any case the memory for a segment is virtual and usually committed on demand.
(i.e. we are careful to not touch the memory until we actually allocate a block there)
If a thread ends, it "abandons" pages with used blocks If a thread ends, it "abandons" pages with used blocks
and there is an abandoned segment list whose segments can and there is an abandoned segment list whose segments can
be reclaimed by still running threads, much like work-stealing. be reclaimed by still running threads, much like work-stealing.

View file

@ -133,25 +133,29 @@ static void mi_stats_add(mi_stats_t* stats, const mi_stats_t* src) {
// unit == 0: count as decimal // unit == 0: count as decimal
// unit < 0 : count in binary // unit < 0 : count in binary
static void mi_printf_amount(int64_t n, int64_t unit, mi_output_fun* out, void* arg, const char* fmt) { static void mi_printf_amount(int64_t n, int64_t unit, mi_output_fun* out, void* arg, const char* fmt) {
char buf[32]; char buf[32]; buf[0] = 0;
int len = 32; int len = 32;
const char* suffix = (unit <= 0 ? " " : "b"); const char* suffix = (unit <= 0 ? " " : "B");
const int64_t base = (unit == 0 ? 1000 : 1024); const int64_t base = (unit == 0 ? 1000 : 1024);
if (unit>0) n *= unit; if (unit>0) n *= unit;
const int64_t pos = (n < 0 ? -n : n); const int64_t pos = (n < 0 ? -n : n);
if (pos < base) { if (pos < base) {
snprintf(buf, len, "%d %s ", (int)n, suffix); if (n!=1 || suffix[0] != 'B') { // skip printing 1 B for the unit column
snprintf(buf, len, "%d %-3s", (int)n, (n==0 ? "" : suffix));
}
} }
else { else {
int64_t divider = base; int64_t divider = base;
const char* magnitude = "k"; const char* magnitude = "K";
if (pos >= divider*base) { divider *= base; magnitude = "m"; } if (pos >= divider*base) { divider *= base; magnitude = "M"; }
if (pos >= divider*base) { divider *= base; magnitude = "g"; } if (pos >= divider*base) { divider *= base; magnitude = "G"; }
const int64_t tens = (n / (divider/10)); const int64_t tens = (n / (divider/10));
const long whole = (long)(tens/10); const long whole = (long)(tens/10);
const long frac1 = (long)(tens%10); const long frac1 = (long)(tens%10);
snprintf(buf, len, "%ld.%ld %s%s", whole, (frac1 < 0 ? -frac1 : frac1), magnitude, suffix); char unitdesc[16];
snprintf(unitdesc, 16, "%s%s%s", magnitude, (base==1024 ? "i" : ""), suffix);
snprintf(buf, len, "%ld.%ld %-3s", whole, (frac1 < 0 ? -frac1 : frac1), unitdesc);
} }
_mi_fprintf(out, arg, (fmt==NULL ? "%11s" : fmt), buf); _mi_fprintf(out, arg, (fmt==NULL ? "%11s" : fmt), buf);
} }
@ -221,7 +225,7 @@ static void mi_stat_counter_print_avg(const mi_stat_counter_t* stat, const char*
static void mi_print_header(mi_output_fun* out, void* arg ) { static void mi_print_header(mi_output_fun* out, void* arg ) {
_mi_fprintf(out, arg, "%10s: %10s %10s %10s %10s %10s %10s\n", "heap stats", "peak ", "total ", "freed ", "current ", "unit ", "count "); _mi_fprintf(out, arg, "%10s: %10s %10s %10s %10s %10s %10s\n", "heap stats", "peak ", "total ", "freed ", "current ", "unit ", "count ");
} }
#if MI_STAT>1 #if MI_STAT>1
@ -524,6 +528,7 @@ static void mi_stat_process_info(mi_msecs_t* elapsed, mi_msecs_t* utime, mi_msec
while (get_next_area_info(tid.team, &c, &mem) == B_OK) { while (get_next_area_info(tid.team, &c, &mem) == B_OK) {
*peak_rss += mem.ram_size; *peak_rss += mem.ram_size;
} }
*page_faults = 0;
#elif defined(__APPLE__) #elif defined(__APPLE__)
*peak_rss = rusage.ru_maxrss; // BSD reports in bytes *peak_rss = rusage.ru_maxrss; // BSD reports in bytes
struct mach_task_basic_info info; struct mach_task_basic_info info;

View file

@ -83,7 +83,7 @@ int main(void) {
void* p = mi_malloc(0); mi_free(p); void* p = mi_malloc(0); mi_free(p);
}); });
CHECK_BODY("malloc-nomem1",{ CHECK_BODY("malloc-nomem1",{
result = (mi_malloc(SIZE_MAX/2) == NULL); result = (mi_malloc((size_t)PTRDIFF_MAX + (size_t)1) == NULL);
}); });
CHECK_BODY("malloc-null",{ CHECK_BODY("malloc-null",{
mi_free(NULL); mi_free(NULL);