| ▲ | marssaxman 3 days ago |
| People have such different perspectives. 26% slower does not sound "terrible" to me; it sounds like quite a reasonable price one might choose to pay for the convenience musl offers. If musl's allocator were 2.6x slower, I might call that "not so great"... but in order to qualify as "terrible" I think the difference would have to be an order of magnitude! |
|
| ▲ | loeg 3 days ago | parent | next [-] |
| The 26% number at the top of the article is from using mimalloc (which is a high performance allocator, at least as fast as the glibc allocator) + musl for some task, and the slowdown is coming from (probably) slow musl implementations of memcpy/memset. The musl allocator is even worse. |
| |
| ▲ | hibikir 2 days ago | parent | next [-] | | Yeah, doing compute-heavy work a couple of jobs ago, we tried small images with musl, and the default allocator was a catastrophe: 75%+ slowdowns for our real life tasks. Even with a better allocator, we were way better off with the larger image. | |
| ▲ | Joker_vD 3 days ago | parent | prev | next [-] | | > the slowdown is coming from (probably) slow musl implementations of memcpy/memset. It's wild that such a fundamental piece of code (you can't really implement operation on structs without those) is library-supplied. I wish compilers would just have something like __builtin_memcpy and __builtin_memset, and provided some highly optimized, specialist-crafted assembly in those, instead of having to inline the library code and hopefully be able to optimize it. | | |
| ▲ | compiler-guy 3 days ago | parent | next [-] | | Clang and GCC do provide these, and automatically use them in many situations (particularly small copies). But c-libraries can actually do it better in many cases, especially for large copies. Glibc, for example, has perhaps ten different implementations of memcpy just for x86. The compiler certainly could provide all that, but the next step is harder: glibc automatically dispatches to the proper one at runtime based on the actual microarchitecture that the binary is running on. You pay the extra dispatch cost once, but all of non-inline function call cost every time. This is what allows distros to compile to a nice baseline architecture, but still get near-optimal memcpy performance on many more architectures than a single inline instance could possibly give. These differences matter. And it does it for not just memcpy, but half-a-dozen other extremely performance sensitive library functions, like strcpy and so on. Inlining works very much against this strategy. If you can guarantee that the target microarch never changes, then it isn't a good one. But that is somewhat unusual for everyone but those who build their own binaries to run on a single class of machines forever. Worse, inlining the really high performance versions of these ends up being terrible from a code size perspective, because they are often hundreds of instructions, which can have bad caching effects. And once you amortize the function-call cost over many iterations of the loop, it isn't so expensive to call out to the library. Anyway, just some additional considerations to think about. | |
| ▲ | fweimer 2 days ago | parent | prev | next [-] | | These builtins of course exist, it's how compilers keep track of the behavior of these functions. For GCC, there is -minline-all-stringops: https://gcc.gnu.org/onlinedocs/gcc-16.2.0/gcc/x86-Options.ht... It does what it says, but the results may not be what you expect. | |
| ▲ | SkiFire13 2 days ago | parent | prev | next [-] | | > I wish compilers would just have something like __builtin_memcpy and __builtin_memset The ones provided by the compilers are simply the libc ones. LLVM will even go as far as detect attempts to rewrite memcpy and replace them with a call to the libc one! | | |
| ▲ | wren6991 2 days ago | parent [-] | | Even if the attempt is inside of a function called memcpy() which contains no code other than your copy loop, and links with priority over the libc implementation! (as all embedded firmware engineers learn at some point in their journey) |
| |
| ▲ | kvuj 3 days ago | parent | prev [-] | | Maybe you're being sarcastic, but I'm pretty sure clang + gcc do offer these. The problems at first glance : - Not having control over the implementation detail of the interface that your library provides is probably not wise. Sounds like a lot of bad bug reports and edge cases that you have no control over. - Not all compilers may provide these. | | |
| ▲ | wahern 2 days ago | parent [-] | | As others have alluded, __builtin_memcpy doesn't resolve to a runtime implementation. GCC and clang treat functions like memcpy specially. Because they're defined by the standard and are reserved names, compilers can assume the exact semantics specified by the standard and elide library calls altogether with optimized inline code. But if the compiler can't do the optimization (can't prove alignment, indeterminate length, etc), it just emits a library call, even if your source has some other local function definition named "memcpy". Explicit use of __builtin_memcpy is treated identically to calls to memcpy, unless the compiler is invoked with -ffreestanding, in which case it only optimizes __builtin_memcpy and skips special treatment of calls to memcpy, but __builtin_memcpy could still expand into a call to memcpy. If you're writing a C library you want to use -ffreestanding. (I think. There may be more nuance. More info at https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56888) |
|
| |
| ▲ | 3 days ago | parent | prev [-] | | [deleted] |
|
|
| ▲ | SkiFire13 2 days ago | parent | prev | next [-] |
| The 26% slower appears to be for their whole application, not just the allocator. For some parts of the application to make the whole this much slower it must mean that those parts are quite a lot slower, likely much more than 2x. Moreover the 26% is with mimalloc, with musl's allocator it's 144%, so there are likely other parts that are slower (likely the memcpy implementation) |
|
| ▲ | stackskipton 3 days ago | parent | prev | next [-] |
| Ops here, I think if you NEED that convenience, sure, rock with MUSL BUT I also see a ton of devs crowing about using MUSL on my 128GB x86 Kubernetes hosts. I have plenty of Disk Space, you can ship glibc based container. |
| |
|
| ▲ | wakawaka28 2 days ago | parent | prev | next [-] |
| 26% slower could turn into a huge hardware bill, and could render the library unusable for some purposes. There are many applications for which 26% is negligible, but it ain't nothing... |
|
| ▲ | otterley 2 days ago | parent | prev | next [-] |
| I'm curious. What convenience, specifically, are people benefiting from by using musl? |
| |
| ▲ | plorkyeran 2 days ago | parent | next [-] | | If you want to ship a prebuilt binary that'll run on any linux distro you need to statically link libc and musl is by far the easiest way to do that. | | |
| ▲ | jcelerier 2 days ago | parent [-] | | except it only can work for CLI apps or anything that doesn't use the GPU as for instance nvidia drivers require glibc |
| |
| ▲ | sombragris 2 days ago | parent | prev [-] | | The convenience (?) of not having to comply with GPL terms. Some people really hate copyleft. | | |
|
|
| ▲ | jcelerier 2 days ago | parent | prev | next [-] |
| > for the convenience musl offers ... you're fine with trading an app running 26% slower, to save a dozen megabytes ? that sounds positively insane to me. That's accepting to go from e.g. 60fps to ~45 fps (e.g. completely unacceptable) |
| |
| ▲ | atiedebee 2 days ago | parent [-] | | That would depend on the application. The convenience isn't just a smaller binary, but also being independent of the distros glibc version (being on an LTS distro and not updating often, I have experienced incompatible glibc versions often enough). The megabytes shaved off are significant if the final binary size is < 1MB, which is a completely different size class. And not all applications are performance sensitive. Something like UNIX's bc command would benefit more from having easier compatibility and a faster startup than more optimized allocators and string functions. In the end, it ~doesnt even matter~ is all trade-offs. The nice thing is that it is up to the developer to make the decision of which libc to use, so everyone gets what they want. |
|
|
| ▲ | fhn 2 days ago | parent | prev [-] |
| Tell your employer a 26% pay decrease for you is acceptable. |