5 ms·
Looks like the default allocator uses mmap(2) for every single allocation, which is horribly inefficient - you map a whole PAGE_SIZE worth of memory for every t
by Retr0id 5mo ago
Looks like the default allocator uses mmap(2) for every single allocation, which is horribly inefficient - you map a whole PAGE_SIZE worth of memory for every tiny string. Aside from just wasting memory this will make the TLB very unhappy.
It looks like sp_log's string formatting is entirely unbuffered which results in lots of tiny write syscalls.
- AlotOfReading 5mo agoThat seems to be a pretty consistent quality level for the entire library. Look at the implementations in sp_math, yikes.
- jcranmer 5mo ago"How bad can it be, I mean I know that numerics are not many people's strong suit, but..." ... ... ... oh wow, the math functions are really bad implementations. The range reduction on the sin/cos functions are yikes-level. Like the wrong input gives you an infinite loop level of yikes.
- lacewing 5mo agoCommendable accuracy, too: https://godbolt.org/z/s9haz611Y https://godbolt.org/z/s9haz611Y
- chrismorgan 5mo agoHere’s a diagram that very visibly shows the error: <https://www.wolframalpha.com/input?i=plot+y+%3D+sin%28x%29%2C+y+%3D+x+*+%281+%E2%88%92+x%C2%B2%2F6+*+%281+%E2%88%92+x%C2%B2%2F20+*+%281+-+x%C2%B2%2F42%29%29%29+from+x%3D%E2%88%92%CF%80+to+%CF%80 https://www.wolframalpha.com/input?i=plot+y+%3D+sin%28x%29%2...>. And that’s even without accumulated float error if you start outside the range [−π, π] (huge numbers will just be wildly wrong).
- locknitpicker 5mo ago> That seems to be a pretty consistent quality level for the entire library. Look at the implementations in sp_math, yikes. That does spin the meaning of "Sp.h is the standard library that C deserves"
- 12_throw_away 5mo agoOh man. Oof. I'm sure there must be some repository out there that has an AGENTS.md but isn't pure slopcode, but I haven't seen it yet. The number of people who can be trusted to vibe code "responsibly" is probably about the same as the number of people who can be trusted to write memory safe C.
- lifthrasiir 5mo agoAs noted in my other comment though, some interesting decisions and interfaces do point to some degree of human intervention. I have recently written a similarly sized WebAssembly runner in C using agents (feel free to review: [1]) so I'm pretty certain that agents simply don't do that kind of things themselves... [1] https://github.com/lifthrasiir/wah/ https://github.com/lifthrasiir/wah/
- 12_throw_away 5mo ago> feel free to review: [1] feel free to pay me before asking me to review slop
- lifthrasiir 5mo agoFeel free to ignore if you don't feel so.
- dboon 5mo agosp_math.h is, as noted at the top of the file, a repackaging of https://github.com/HandmadeMath/HandmadeMath https://github.com/HandmadeMath/HandmadeMath It is not part of the core library. It is certainly not meant as a reference-level implementation of math functions. It's there so you can write an easing function for a game without pulling in libc. It seems like its existence has offended you. If that's the case...I'm sorry? At every possible point, I note as loudly as possible exactly what that library is. I found your tone extremely dismissive and disrespectful and I don't care to engage with that any more than I already have.
- lifthrasiir 5mo agoI don't like that slopcode angle either, but unfortunately I have to say that you do have picked a wrong library to bundle. For example, it's almost likely that there is a correct (not just accurate enough, but correct) implementation of sqrt in your CPU because IEEE 754 mandates that. Unless you're doing softfloat you simply want to wire it via asm.
- AlotOfReading 5mo ago> It is not part of the core library. It is certainly not meant as a reference-level implementation of math functions. It's there so you can write an easing function for a game without pulling in libc. I saw the note and ignored it because it's not actually a repackaging of HHM. It simply happens to define a few vaguely similar functions. It doesn't reuse the naming conventions (MulVec3f vs vec3_scale), it doesn't reuse the interface (see SP_MATH_IMPLEMENTATION), and it's missing genuinely useful bits like the matrix functions. Moreover, the quality of what's been added is significantly worse. Look at sp_sys_expf: f32 sp_sys_expf(f32 x) { f32 result = 1.0f; f32 term = 1.0f; for (int i = 0; i < 20; i++) { term *= x / (f32)(i + 1); result += term; } return result; } I can't imagine a good reason why anyone (even an LLM) would ever write a 20th order taylor series for expf. A single FMA can improve on this and have capped relative error to boot, and that's not even a good way to do it. See what happens with your function at +-10 for comparison. At the f32 limit of 88, you achieve an honestly impressive 100% relative error. Also, because sp_math doesn't use FMAs, your library isn't reproducible. Different compilers will produce different values. Reproducibility is a pretty nice property in games.
- gabriela_c 5mo agoJesus! Claude could've told this guy all these things. People underestimate how much the average malloc implementation does and how many considerations it makes. Or how much IO sucks.
- lelanthran 5mo ago> Jesus! Claude could've told this guy all these things. Claude probably wrote it.
- dboon 5mo agoThe point of the library is that you do not call the low level allocation primitive to allocate a single string. Of course, in simple programs which exit immediately, there is no difference between using a page allocator and a heap allocator. In real programs, I use an appropriate allocator for the allocation rather than making arbitrary calls to malloc(). In the sp.h examples, I use the page allocator to keep freestanding Linux simple. I could swap out a single line to be backed by an arena, but it misses the forest for the trees. sp_log() writes directly to an IO writer. An IO writer can be buffered or unbuffered, but is unbuffered by default. This is a feature, not a bug. Have a look through the IO code! Cheers and thanks for reading.
- feelamee 5mo agoq> sp_log() writes directly to an IO writer. An IO writer can be buffered or unbuffered, but is unbuffered by default. This is a feature, not a bug. Have a look through the IO code! Why is the unbuffered default? Is there any thoughts on this?
- NetMageSCW 5mo agoSo every program using sp has to re-invent malloc or multiple copies of their own bespoke allocator and this is supposed to be a good idea?
- dboon 5mo agoThe library provides a few basic allocators.
- monocasa 5mo agoNot just the TLB, but the L1 D$ will be very unhappy as well. All heap objects being page aligned on most microarchs ends up making every object start at cache set 0 because the set determination ends up being indexed off of the offest within a page so that the TLB lookup can happen in parallel with the set load.