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 <[email protected]> 
> --- 
>  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 = &pr; 
> @@ -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 [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/osv-dev/d75ef4c5-cfef-4b95-908b-c695163ae163%40googlegroups.com.

Reply via email to