mirror of
https://github.com/microsoft/mimalloc.git
synced 2024-12-27 13:33:18 +08:00
better fast path for aligned allocation; check max alloc size correctly in the aligned fallback
This commit is contained in:
parent
605c354bd4
commit
c70c1df16a
@ -15,17 +15,23 @@ terms of the MIT license. A copy of the license can be found in the file
|
|||||||
// Aligned Allocation
|
// Aligned Allocation
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
|
|
||||||
|
static inline bool mi_is_naturally_aligned( size_t size, size_t alignment ) {
|
||||||
|
// objects up to `MI_MEDIUM_OBJ_SIZE_MAX` are allocated aligned to their size (see `segment.c:_mi_segment_page_start`).
|
||||||
|
// note: the size may not be not an actual bin-size but it turns out the test below is still correct for our
|
||||||
|
// powers of two bin spacing (see test-api.c:test-aligned13).
|
||||||
|
mi_assert_internal(_mi_is_power_of_two(alignment) && (alignment > 0));
|
||||||
|
return (size <= MI_MEDIUM_OBJ_SIZE_MAX && alignment <= size && ((size + MI_PADDING_SIZE) & (alignment-1)) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Fallback primitive aligned allocation -- split out for better codegen
|
// Fallback primitive aligned allocation -- split out for better codegen
|
||||||
static mi_decl_noinline void* mi_heap_malloc_zero_aligned_at_fallback(mi_heap_t* const heap, const size_t size, const size_t alignment, const size_t offset, const bool zero) mi_attr_noexcept
|
static mi_decl_noinline void* mi_heap_malloc_zero_aligned_at_fallback(mi_heap_t* const heap, const size_t size, const size_t alignment, const size_t offset, const bool zero) mi_attr_noexcept
|
||||||
{
|
{
|
||||||
mi_assert_internal(size <= PTRDIFF_MAX);
|
mi_assert_internal(size <= (MI_MAX_ALLOC_SIZE - MI_PADDING_SIZE));
|
||||||
mi_assert_internal(alignment != 0 && _mi_is_power_of_two(alignment));
|
mi_assert_internal(alignment != 0 && _mi_is_power_of_two(alignment));
|
||||||
|
|
||||||
const uintptr_t align_mask = alignment - 1; // for any x, `(x & align_mask) == (x % alignment)`
|
// use regular allocation if it is guaranteed to fit the alignment constraints.
|
||||||
const size_t padsize = size + MI_PADDING_SIZE;
|
if (offset == 0 && mi_is_naturally_aligned(size,alignment)) {
|
||||||
|
|
||||||
// use regular allocation if it is guaranteed to fit the alignment constraints
|
|
||||||
if (offset == 0 && alignment <= padsize && padsize <= MI_MEDIUM_OBJ_SIZE_MAX && (padsize & align_mask) == 0) {
|
|
||||||
void* p = _mi_heap_malloc_zero(heap, size, zero);
|
void* p = _mi_heap_malloc_zero(heap, size, zero);
|
||||||
mi_assert_internal(p == NULL || ((uintptr_t)p % alignment) == 0);
|
mi_assert_internal(p == NULL || ((uintptr_t)p % alignment) == 0);
|
||||||
return p;
|
return p;
|
||||||
@ -57,6 +63,7 @@ static mi_decl_noinline void* mi_heap_malloc_zero_aligned_at_fallback(mi_heap_t*
|
|||||||
}
|
}
|
||||||
|
|
||||||
// .. and align within the allocation
|
// .. and align within the allocation
|
||||||
|
const uintptr_t align_mask = alignment - 1; // for any x, `(x & align_mask) == (x % alignment)`
|
||||||
const uintptr_t poffset = ((uintptr_t)p + offset) & align_mask;
|
const uintptr_t poffset = ((uintptr_t)p + offset) & align_mask;
|
||||||
const uintptr_t adjust = (poffset == 0 ? 0 : alignment - poffset);
|
const uintptr_t adjust = (poffset == 0 ? 0 : alignment - poffset);
|
||||||
mi_assert_internal(adjust < alignment);
|
mi_assert_internal(adjust < alignment);
|
||||||
@ -100,14 +107,14 @@ static void* mi_heap_malloc_zero_aligned_at(mi_heap_t* const heap, const size_t
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if mi_unlikely(size > PTRDIFF_MAX) { // we don't allocate more than PTRDIFF_MAX (see <https://sourceware.org/ml/libc-announce/2019/msg00001.html>)
|
if mi_unlikely(size > (MI_MAX_ALLOC_SIZE - MI_PADDING_SIZE)) { // we don't allocate more than MI_MAX_ALLOC_SIZE (see <https://sourceware.org/ml/libc-announce/2019/msg00001.html>)
|
||||||
#if MI_DEBUG > 0
|
#if MI_DEBUG > 0
|
||||||
_mi_error_message(EOVERFLOW, "aligned allocation request is too large (size %zu, alignment %zu)\n", size, alignment);
|
_mi_error_message(EOVERFLOW, "aligned allocation request is too large (size %zu, alignment %zu)\n", size, alignment);
|
||||||
#endif
|
#endif
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
const uintptr_t align_mask = alignment-1; // for any x, `(x & align_mask) == (x % alignment)`
|
const uintptr_t align_mask = alignment-1; // for any x, `(x & align_mask) == (x % alignment)`
|
||||||
const size_t padsize = size + MI_PADDING_SIZE; // note: cannot overflow due to earlier size > PTRDIFF_MAX check
|
const size_t padsize = size + MI_PADDING_SIZE; // note: cannot overflow due to earlier size check
|
||||||
|
|
||||||
// try first if there happens to be a small block available with just the right alignment
|
// try first if there happens to be a small block available with just the right alignment
|
||||||
if mi_likely(padsize <= MI_SMALL_SIZE_MAX && alignment <= padsize) {
|
if mi_likely(padsize <= MI_SMALL_SIZE_MAX && alignment <= padsize) {
|
||||||
@ -140,15 +147,7 @@ mi_decl_nodiscard mi_decl_restrict void* mi_heap_malloc_aligned_at(mi_heap_t* he
|
|||||||
|
|
||||||
mi_decl_nodiscard mi_decl_restrict void* mi_heap_malloc_aligned(mi_heap_t* heap, size_t size, size_t alignment) mi_attr_noexcept {
|
mi_decl_nodiscard mi_decl_restrict void* mi_heap_malloc_aligned(mi_heap_t* heap, size_t size, size_t alignment) mi_attr_noexcept {
|
||||||
if (alignment == 0 || !_mi_is_power_of_two(alignment)) return NULL;
|
if (alignment == 0 || !_mi_is_power_of_two(alignment)) return NULL;
|
||||||
#if !MI_PADDING
|
if (size <= MI_SMALL_SIZE_MAX && mi_is_naturally_aligned(size,alignment)) {
|
||||||
// without padding, any small sized allocation is naturally aligned (see also `_mi_segment_page_start`)
|
|
||||||
if mi_likely(_mi_is_power_of_two(size) && size >= alignment && size <= MI_SMALL_SIZE_MAX)
|
|
||||||
#else
|
|
||||||
// with padding, we can only guarantee this for fixed alignments
|
|
||||||
if mi_likely((alignment == sizeof(void*) || (alignment == MI_MAX_ALIGN_SIZE && size > (MI_MAX_ALIGN_SIZE/2)))
|
|
||||||
&& size <= MI_SMALL_SIZE_MAX)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
// fast path for common alignment and size
|
// fast path for common alignment and size
|
||||||
return mi_heap_malloc_small(heap, size);
|
return mi_heap_malloc_small(heap, size);
|
||||||
}
|
}
|
||||||
|
@ -230,6 +230,23 @@ int main(void) {
|
|||||||
result = (((uintptr_t)p % 0x100) == 0); // #602
|
result = (((uintptr_t)p % 0x100) == 0); // #602
|
||||||
mi_free(p);
|
mi_free(p);
|
||||||
}
|
}
|
||||||
|
CHECK_BODY("mimalloc-aligned13") {
|
||||||
|
bool ok = true;
|
||||||
|
for( size_t size = 1; size <= MI_SMALL_SIZE_MAX && ok; size++ ) {
|
||||||
|
for(size_t align = 1; align <= size && ok; align *= 2 ) {
|
||||||
|
void* p = mi_malloc_aligned(size,align);
|
||||||
|
ok = (p != NULL && ((uintptr_t)p % align) == 0);
|
||||||
|
mi_free(p);
|
||||||
|
/*
|
||||||
|
if (ok && align <= size && ((size + MI_PADDING_SIZE) & (align-1)) == 0) {
|
||||||
|
size_t bsize = mi_good_size(size);
|
||||||
|
ok = (align <= bsize && ((bsize + MI_PADDING_SIZE) & (align-1)) == 0);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result = ok;
|
||||||
|
}
|
||||||
CHECK_BODY("malloc-aligned-at1") {
|
CHECK_BODY("malloc-aligned-at1") {
|
||||||
void* p = mi_malloc_aligned_at(48,32,0); result = (p != NULL && ((uintptr_t)(p) + 0) % 32 == 0); mi_free(p);
|
void* p = mi_malloc_aligned_at(48,32,0); result = (p != NULL && ((uintptr_t)(p) + 0) % 32 == 0); mi_free(p);
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user