6 ms·
No, musl's allocator is just bad even in completely normal programs, and it is especially awful if you are using even two threads much less a lot of them. It ha
by aseipp 19d ago
No, musl's allocator is just bad even in completely normal programs, and it is especially awful if you are using even two threads much less a lot of them. It has no TLABs or arenas. It has a single global mutex over alloc/free paths. It does syscalls underneath that lock (mmap) meaning the few fast paths it has are rarely taken under contention and have to fall back to futex wakes, so even 2 threads with minor contention and allocation rate will have visible wait points in profiles, stuck waiting for the allocator. It returns mapped memory to the OS very eagerly when a size class is empty, so even single allocs followed by a single free can cause thrashing as it mmaps/unmmaps things repeatedly for a size class over and over. Etc. You quite literally have to limit your thread count when using musl, because it will tank the performance of actually highly threaded programs that can scale with core count, even at very modest allocation rates and small working set sizes.
Its string routines and memory copy routines are also similarly bad, as the article alludes to. They are just naive loops with nearly no optimization. These are not small insignificant functions where using them is "doing it wrong", they are the backbone of vast amounts of code and can be made multiple times faster. You can similarly see string routines pop up in profiles all the time in musl builds in my experience. And unlike the memory allocator these cannot be "fixed" systematically across the application at link time, so you are stuck with it.
Real programs have to often do things like allocate memory and use multiple threads and process strings. People have been optimizing these things for decades, there is vast amounts of prior art, the musl developers simply did not do so because they prioritize simplicity over nearly everything else (from what I can tell) including performance.
- CyberDildonics 19d agoIt has a single global mutex over alloc/free paths. It does syscalls underneath that lock (mmap) Every default malloc implementation worked this way about 12 years ago. Making lots of small allocations, even from multiple threads then blaming the allocator is a losing strategy. An allocator is only going to be able to mitigate the damage to speed and interactivity. The solution is and always has been to make larger allocations and use those efficiently. They are just naive loops with nearly no optimization. The compiler should be able to take something with good access patterns and make something fast, especially out of the basic C functions. they are the backbone of vast amounts of code Performance wise it's unlikely C string functions are actually the bottleneck in a program. Maybe for specific programs a naive memory copy function could benefit from AVX instructions. Real programs have to often do things like allocate memory "Have to" and "often" are debatable. Any allocations in a hot loop are the very first things that should be optimized away after profiling.
- wakawaka28 19d ago>Performance wise it's unlikely C string functions are actually the bottleneck in a program. Maybe for specific programs a naive memory copy function could benefit from AVX instructions. Many programs use lots of strings. It tends to become a bottleneck. It also tends to be very difficult to improve because the strings are everywhere in that kind of program, and refactoring to eliminate them is either impossible or very risky.
- CyberDildonics 19d agoMany programs use lots of strings. It tends to become a bottleneck. I would dispute this in anything that isn't mostly about string processing and in that case you can always easily grab different string functions, which you should probably do anyway if strings are that important. It also tends to be very difficult to improve because the strings are everywhere in that kind of program, I don't know what 'that kind of program' is supposed to mean. and refactoring to eliminate them is either impossible or very risky. This doesn't sound like a general purpose statement that applies to anything broadly. All I'm saying is the the title is wrong and musl doesn't do much to prevent speed in a program. If someone was really trying to optimize, blaming the standard library is not going to get them very far and it's easy to work around, but needing to do that is very rare.
- wakawaka28 19d ago>I would dispute this in anything that isn't mostly about string processing and in that case you can always easily grab different string functions, which you should probably do anyway if strings are that important. I'm telling you that I've seen it, in stuff as diverse as video games and robotics. Lots of things use strings as values. It's easy to say "just change everything in millions of lines of code" when you aren't the one who has to make that change. By the way most software does copious amounts of string processing... I think that should be common knowledge, but I guess it isn't. >This doesn't sound like a general purpose statement that applies to anything broadly. You sound like you have zero experience. If your config is in strings, and hundreds of thousands of lines of code already rely on the string-ness of the data, then you just can't make the change easily. >All I'm saying is the the title is wrong and musl doesn't do much to prevent speed in a program. If someone was really trying to optimize, blaming the standard library is not going to get them very far and it's easy to work around, but needing to do that is very rare. I believe the title is accurate. People in performance-sensitive areas gripe about libraries, even standard libraries, quite often. I don't mean to insult you but you're making bold assertions despite clearly lacking the experience to know how things are done in industry generally.