Earlier quoted context omitted.
Modern compilers have quite a deep understanding of memcpy, and they will recognize the pattern and put in optimal assembly (on x86, probably "rep movsb" or whatever), even if you don't literally call memcpy. This is why the GCC implmentation of memcpy is, like, trivial: [1]. The compiler will recognize that this is a memcpy and sub the better implementation. I wonder though: it seems to me that memory bandwidth shou…
> on x86, probably "rep movsb" or whatever) Sadly I don't have a link, but as far as I remember rep movsb was always hilariously slow. So memcpy implementations tried to optimize copies using half a page of vector instructions with size and alignment tests, which of course killed the CPUs instruction cache.
A 100LOC C impl of memset, that is faster than glibc's
101–110 of 110 posts
Re: A 100LOC C impl of memset, that is faster than glibc's
#102memset is something JEDEC SDRAM standard should of implemented on a hardware level back in 1993. Why even bother writing to ram byte by byte when we could of had dedicated command to fill up to whole row (8-16kbit per chip, 8-32KB per DIMM) at a time with _single command_. Safe zero fill memory allocation would be free and standard. For background: https://faculty-web.msoe.edu/johnsontimoj/EE4980/files4980/m... Since…
Modern microcontrollers can have DMA units that you can program to, among other things, do a memset or even a memcpy when the memory bus happens to be idle, and they’ll interrupt you when they’re done. The design point is different (a microcontroller application can be limited by processor cycles but rarely by memory bus bandwidth), but I still wonder why PCs don’t have anything like that.
Re: A 100LOC C impl of memset, that is faster than glibc's
#103Earlier quoted context omitted.
Is the choice of 16 as the "limit" value based on benchmarking? As opposed to just doing something like "!buffer[0] && !memcmp(buffer, buffer + 1, size - 1)" which uses the same principle.
Not the OP, but 16 has the benefit of keeping both pointers in the comparison 16-byte aligned if the buffer was initially aligned. This would eliminate split loads and provide a decent speedup.
https://lemire.me/blog/2012/05/31/data-alignment-for-speed-m...
Memory alignment is innocuous (others than often compromise code legibility).
Loop unrolling, on the other hand, can slow down the code. Specially in small loops.
See Agner uarch PDF.
Re: A 100LOC C impl of memset, that is faster than glibc's
#104Earlier quoted context omitted.
Not the OP, but 16 has the benefit of keeping both pointers in the comparison 16-byte aligned if the buffer was initially aligned. This would eliminate split loads and provide a decent speedup.
This, and loop unrolling, are two commons misconception about uarch optimization. https://lemire.me/blog/2012/05/31/data-alignment-for-speed-m... Memory alignment is innocuous (others than often compromise code legibility). Loop unrolling, on the other hand, can slow down the code. Specially in small loops. See Agner uarch PDF.
Re: A 100LOC C impl of memset, that is faster than glibc's
#105Earlier quoted context omitted.
Modern compilers have quite a deep understanding of memcpy, and they will recognize the pattern and put in optimal assembly (on x86, probably "rep movsb" or whatever), even if you don't literally call memcpy. This is why the GCC implmentation of memcpy is, like, trivial: [1]. The compiler will recognize that this is a memcpy and sub the better implementation. I wonder though: it seems to me that memory bandwidth shou…
> on x86, probably "rep movsb" or whatever) Sadly I don't have a link, but as far as I remember rep movsb was always hilariously slow. So memcpy implementations tried to optimize copies using half a page of vector instructions with size and alignment tests, which of course killed the CPUs instruction cache.
Re: A 100LOC C impl of memset, that is faster than glibc's
#106Earlier quoted context omitted.
strchr(str, 0) == NULL memchr(str, 0, len) == NULL
Those find the first zero -- not the number of contiguous zeros.
Huh. OP is right, there is no good function for this in the standard library.
Re: A 100LOC C impl of memset, that is faster than glibc's
#107On x86 the situation is in some ways worse. Quite a few x86 CPUs have had atrociously bad implementation of the string instructions. As a result, some high performance systems rolled their own memset/memcpy implementations. That results in feedback to the CPU designers failing to prioritize further optimize those string instructions. Thankfully, string instructions have kept getting better, so the general recommendation today is to just use the string instructions.
Re: A 100LOC C impl of memset, that is faster than glibc's
#108Earlier quoted context omitted.
Here's the code in godbolt: gcc: https://godbolt.org/z/6xG5dKjj9 clang: https://godbolt.org/z/Mh9zozjvK I'm no asm expert, but it doesn't look like a lot of vector instructions in the gcc compilation of this, while the clang compilation seems to have more calls with the 128-bit xmm registers (at least on x86_64.) You can also just see visibly how many more instructions the gcc version outputs.
Thank you! Indeed GCC does not use SIMD here unless you set -O3 (... I seem to remember this enables some vectorization?) or allow it to use AVX with -mavx or -march=x86-64-v3. For some reason I’m unable to get it to use plain SSE (always available on x86-64) with any -mtune setting or even with -march=x86-64-v2.
Re: A 100LOC C impl of memset, that is faster than glibc's
#109I have a memset that's not only 10x faster than glibc, but also secure. The trick is to bypass the generic asm, and let the compiler optimize it, esp. with constant sizes and known alignments. Esp. with clang.
Don't do this. Security. explicit_bzero() won't be optimized away.
explicit_bzero and it's numerous variants are not only insecure, but also slow. (byte wise!)
Only safelibc has a secure memset_s. https://github.com/rurban/safeclib/blob/master/tests/perf_me...
Re: A 100LOC C impl of memset, that is faster than glibc's
#110memset is something JEDEC SDRAM standard should of implemented on a hardware level back in 1993. Why even bother writing to ram byte by byte when we could of had dedicated command to fill up to whole row (8-16kbit per chip, 8-32KB per DIMM) at a time with _single command_. Safe zero fill memory allocation would be free and standard. For background: https://faculty-web.msoe.edu/johnsontimoj/EE4980/files4980/m... Since…