On Tuesday, March 24, 2020 at 12:59:08 AM UTC-4, Waldek Kozaczuk wrote: > > This patch addresses the issue #854. In essence it changes malloc_large() > to use mmu::map_anon() if requested memory is greater than size of "huge > page" > and it does not have be contiguous in physical memory. Also it makes it > fallback > to map_anon() based allocation for requests > 4K and < 2MB that cannot be > satisfied > when mamory is fragmented. > > It is supposed to help OSv memory allocation behave better when memory > in free_page_ranges is heavily fragmented and large allocations (>=2MB) > cannot be satisfied with single contiguous page range. > > Fixes #854 > > Signed-off-by: Waldemar Kozaczuk <jwkozac...@gmail.com> > --- > core/mempool.cc | 54 +++++++++++++++++++++++++++++++++++++++---------- > 1 file changed, 43 insertions(+), 11 deletions(-) > > diff --git a/core/mempool.cc b/core/mempool.cc > index 11fd1456..f14a6a68 100644 > --- a/core/mempool.cc > +++ b/core/mempool.cc > @@ -546,7 +546,7 @@ public: > page_range_allocator() : _deferred_free(nullptr) { } > > template<bool UseBitmap = true> > - page_range* alloc(size_t size); > + page_range* alloc(size_t size, bool contiguous = true); > page_range* alloc_aligned(size_t size, size_t offset, size_t > alignment, > bool fill = false); > void free(page_range* pr); > @@ -678,7 +678,7 @@ void > page_range_allocator::bitmap_allocator<T>::deallocate(T* p, size_t n) > } > > template<bool UseBitmap> > -page_range* page_range_allocator::alloc(size_t size) > +page_range* page_range_allocator::alloc(size_t size, bool contiguous) > { > auto exact_order = ilog2_roundup(size / page_size); > if (exact_order > max_order) { > @@ -692,13 +692,12 @@ page_range* page_range_allocator::alloc(size_t size) > > page_range* range = nullptr; > if (!bitset) { > - if (!exact_order || _free[exact_order - 1].empty()) { > + if (!contiguous || !exact_order || _free[exact_order - > 1].empty()) { > return nullptr; > } > - // TODO: This linear search makes worst case complexity of the > allocator > - // O(n). It would be better to fall back to non-contiguous > allocation > - // and make worst case complexity depend on the size of requested > memory > - // block and the logarithm of the number of free huge page > ranges. > + // This linear search makes worst case complexity of the > allocator > + // O(n). Unfortunately we do not have choice for contiguous > allocation > + // so let us hope there is large enough range. > for (auto&& pr : _free[exact_order - 1]) { > if (pr.size >= size) { > range = ≺ > @@ -823,7 +822,16 @@ void page_range_allocator::for_each(unsigned > min_order, Func f) > } > } > > -static void* malloc_large(size_t size, size_t alignment, bool block = > true) > +static void* mapped_malloc_large(size_t size, size_t offset) > +{ > + //TODO: For now pre-populate the memory, in future consider doing > lazy population > + void* obj = mmu::map_anon(nullptr, size, mmu::mmap_populate, > mmu::perm_read | mmu::perm_write); > + size_t* ret_header = reinterpret_cast<size_t*>(obj); > I think I should be using static_cast here (and in other place). But I am not sure it is causing any particular harm.
> + *ret_header = size; > + return obj + offset; > +} > + > +static void* malloc_large(size_t size, size_t alignment, bool block = > true, bool contiguous = true) > { > auto requested_size = size; > size_t offset; > @@ -835,6 +843,14 @@ static void* malloc_large(size_t size, size_t > alignment, bool block = true) > size += offset; > size = align_up(size, page_size); > > + // Use mmap if requested memory greater than "huge page" size > + // and does not need to be contiguous > + if (size >= mmu::huge_page_size && !contiguous) { > + void* obj = mapped_malloc_large(size, offset); > + trace_memory_malloc_large(obj, requested_size, size, alignment); > + return obj; > + } > + > Not sure if above and below when we call mapped_malloc_large() we need to do something extra if (alignment > page_size). > while (true) { > WITH_LOCK(free_page_ranges_lock) { > reclaimer_thread.wait_for_minimum_memory(); > @@ -842,7 +858,7 @@ static void* malloc_large(size_t size, size_t > alignment, bool block = true) > if (alignment > page_size) { > ret_header = free_page_ranges.alloc_aligned(size, > page_size, alignment); > } else { > - ret_header = free_page_ranges.alloc(size); > + ret_header = free_page_ranges.alloc(size, contiguous); > } > if (ret_header) { > on_alloc(size); > @@ -850,6 +866,10 @@ static void* malloc_large(size_t size, size_t > alignment, bool block = true) > obj += offset; > trace_memory_malloc_large(obj, requested_size, size, > alignment); > return obj; > + } else if (!contiguous) { > + // If we failed to get contiguous memory allocation and > + // the caller does not require one let us use map-based > allocation > + break; > } > if (block) > reclaimer_thread.wait_for_memory(size); > @@ -857,6 +877,10 @@ static void* malloc_large(size_t size, size_t > alignment, bool block = true) > return nullptr; > } > } > + > + void* obj = mapped_malloc_large(size, offset); > + trace_memory_malloc_large(obj, requested_size, size, alignment); > + return obj; > } > > void shrinker::deactivate_shrinker() > @@ -1692,7 +1716,7 @@ static inline void* std_malloc(size_t size, size_t > alignment) > memory::alloc_page()); > trace_memory_malloc_page(ret, size, mmu::page_size, alignment); > } else { > - ret = memory::malloc_large(size, alignment); > + ret = memory::malloc_large(size, alignment, true, false); > } > memory::tracker_remember(ret, size); > return ret; > @@ -1763,6 +1787,14 @@ void free(void* object) > return; > } > memory::tracker_forget(object); > + > + if (!mmu::is_linear_mapped(object, 0)) { > + object = align_down(object - 1, mmu::page_size); > + size_t* ret_header = reinterpret_cast<size_t*>(object); > + mmu::munmap(object, *ret_header); > + return; > + } > + > switch (mmu::get_mem_area(object)) { > case mmu::mem_area::page: > object = mmu::translate_mem_area(mmu::mem_area::page, > @@ -1972,7 +2004,7 @@ void* alloc_phys_contiguous_aligned(size_t size, > size_t align, bool block) > assert(is_power_of_two(align)); > // make use of the standard large allocator returning properly > aligned > // physically contiguous memory: > - auto ret = malloc_large(size, align, block); > + auto ret = malloc_large(size, align, block, true); > assert (!(reinterpret_cast<uintptr_t>(ret) & (align - 1))); > return ret; > } > -- > 2.20.1 > > -- You received this message because you are subscribed to the Google Groups "OSv Development" group. To unsubscribe from this group and stop receiving emails from it, send an email to osv-dev+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/osv-dev/d75ef4c5-cfef-4b95-908b-c695163ae163%40googlegroups.com.