Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reserve and limit memory usage? #655

Open
richarddd opened this issue Jan 30, 2024 · 3 comments
Open

Reserve and limit memory usage? #655

richarddd opened this issue Jan 30, 2024 · 3 comments

Comments

@richarddd
Copy link

I'm seeing fantastic performance with snmalloc in a resource constrained environment.

MiMalloc has MIMALLOC_RESERVE_OS_MEMORY and MIMALLOC_LIMIT_OS_ALLOC. Is there any equivalent for snmalloc?
I wan't to improve the startup of my program that i know upfront will allocate a lot of memory. But I also want to limit request anymore memory from the OS simlar to MIMALLOC_LIMIT_OS_ALLOC

Thank you!

@mjp41
Copy link
Member

mjp41 commented Jan 30, 2024

This is not a facility we currently support, but the structure of the backend should make this easy to do.

So is the idea to have one parameter which sets the initial reservation that the OS requires, and then to add a bound on the requested memory?

I think we can easily add a range that prevents allocating more than a threshold. snmalloc has ranges that have a super simple interface, e.g.

https://github.com/microsoft/snmalloc/blob/main/src/snmalloc/backend_helpers/commitrange.h

We could make a LimitRange that would prevent allocating too much (typed quickly into github, so probably needs some work):

  template <size_t Limit>
  struct LimitRange
  {
    template<typename ParentRange>
    class Type : public ContainsParent<ParentRange>
    {
      using ContainsParent<ParentRange>::parent;

      size_t allocated{0}; 

    public:
      static constexpr bool Aligned = ParentRange::Aligned;

      static constexpr bool ConcurrencySafe = false;

      using ChunkBounds = typename ParentRange::ChunkBounds;

      CapPtr<void, ChunkBounds> alloc_range(size_t size)
      {
         if (allocated + size >= Limit)
           return nullptr;
         auto result = parent.alloc_range(size);
         if (result != nullptr)
           allocated += size;
         return result;
       }

       void dealloc_range(CapPtr<void, ChunkBounds> base, size_t size)
       {
         allocated -= size;
         parent.dealloc_range(base, size);
       }
     }
   }

This version is taking a template parameter for the size, but that could be more dynamic, if required.

I have a few other things I am working on, so will be a little while before I can add this. So if you want to try, I am happy to review a PR.

@mjp41
Copy link
Member

mjp41 commented Jan 30, 2024

P.S. Super interested to know you use case, and any benchmarking that we can use to improve snmalloc.

@richarddd
Copy link
Author

richarddd commented Jan 30, 2024

P.S. Super interested to know you use case, and any benchmarking that we can use to improve snmalloc.

I'm running snmalloc as an allocator for a JavaScript runtime written in Rust + C running in AWS Lambda that only has 128MB memory available. It uses A LOT of allocations due to the dynamic nature of JS. I see some regression in "startup" time compared with mimalloc when needing to process larger events as i can not upfront reserve. Lambda typically only needs a few MB for background processes and can dedicate the rest to the main runtime.

Whats really convenient in mimalloc is that this can be controlled via environment variables and thus set dynamically which is a requirement. It would be fantastic if we had a similar option for snmalloc :)

Unfortunately i posses zero c++ skill so a PR would be tricky to put together...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants