Re: Xenomai 4 Allocator Fragmentation Questions
Bryan Smith <[email protected]> Mon, 27 Jul 2026 17:55:13 -0400
| Newsgroups | dev.linux.lists.xenomai |
|---|---|
| Message-ID | <CABE=YNs=T-x2iyDjOMcuDzkEOx6EQCUeX7ivGy15O01cZ8682w@mail.gmail.com> |
Philippe Gerum <[email protected]> writes: > Kevin Strell <[email protected]> writes: > > > > > 1. Other than the compaction procedure, is there anything we can do > > with the default Xenomai allocator to improve the performance in > > regards to fragmentation? > > Use multiple heaps if possible, to confine the problematic allocation > patterns. > > > 2. When is the correct time to run the compaction procedure in regards > > to when we should call evl_init()? > > Those are unrelated issues. > > > 3. If the fragmentation is a known issue of the default allocator, is > > there any other allocator that is recommended? > > > > An allocator which meets real-time requirements while still limiting > external fragmentation to the minimum may be difficult to find because > both goals are somewhat conflicting (notably because garbage collection > may not fit well when it comes to time complexity). You may want to have > a look at respins of the TLSF allocator, some of them were designed to > address the fragmentation issue the original one had - which was the > reason for developing heapmem years ago. > > I'm interested by any result in this area, feedback welcome. -- > Kevin Strell <[email protected]> writes: > > > We have been able to avoid the fragmentation problems by switching to > > using the rpmalloc library (https://github.com/mjansson/rpmalloc) > > A note regarding this allocator, which documentation reads as follows > under the "Worst case scenarios" section: > > "Since each heap maps a span of memory pages per page type, a thread > that allocates just a few blocks of each size class (16, 32, ...) for > many size classes will commit a memory page for each used size class, > while only using a small fraction of the committed memory. However, > memory pages are committed on demand and blocks are initialized only as > needed, ..." > > Assuming that "committing pages" may mean mapping them to the current > address space and/or performing some kind of memcontrol work (msync?), > you may want to make sure that rpmalloc can pre-commit pages, so that > this does not happen in time-critical work loops. Because rpmalloc > operates on a per-thread basis, you would need to ensure this for each > thread attached to the evl core specifically. Failing to do so would > certainly cause those real-time threads to be demoted to the in-band > stage. You may want to check this using the related health monitoring > service [1] (EVL_HMDIAG_SYSDEMOTE). > > To sum up, rpmalloc addresses the fragmentation issue by dedicating each > memory page to dealing with a particular block size, for allocation > _and_ release, so it does not have to resort to dynamic garbage > collection. However, in order to meet real-time requirements, you may > want to make sure that alloc and release operations won't ever issue a > regular system call under the hood. > > [1] https://v4.xenomai.org/core/user-api/thread/index.html#health-monitoring Thank you for your feedback. We originally had a process that used a single large heap that was shared among multiple threads: * Main thread: allocates upon initialization only. * Lower-priority thread A: allocates/frees during normal operation. * Lower-priority thread B: allocates/frees during normal operation. Memory was allocated using the non-serializing/unlocked libevl heap API, which was obviously problematic when threads A and B run concurrently. We have historically avoided the use of mutexes and similar mechanisms, so we attempted to continue using the unlocked API with a large heap for the main thread and a smaller heap for one of the lower-priority threads. The smaller heap was much more likely to be fully consumed, which is where our concerns about fragmentation came from. When reverting to use a single large heap and the serializing libevl heap API, we haven't seen any issues with memory allocation nor any concerns about using mutexes. We had to use a small workaround because there are multiple processes that each use their own `struct evl_heap`, and the name of the mutex created internally by evl_init_heap() is only unique within the same process (and not between multiple processes). struct evl_heap heap; ret = evl_new_mutex(&heap.lock, "heap:%.3d", getpid()) /* ... */ ret = evl_init_heap_unlocked(&heap, mem, size); rpmalloc did end up meeting real-time performance requirements with the evaluation that we had done, but I believe that we are going to abandon this evaluation since the libevl serialized heap API works well for our use case. Regards, Bryan