When I try to implement the C string library myself, I found that glibc and the Linux kernel have a different way to implement some functions. For instance, glibc memchr and glibc strchr use some trick to speed up the function but the kernel memchr and the kernel strchr don't. Why aren't the Linux kernel functions optimized like glibc?
The kernel does have optimised versions of some of these functions, in the arch-specific directories; see for example the x86 implementation of
memchr (see all the
memchr definitions, and all the
strchr definitions). The versions you found are the fallback generic versions; you can spot these by looking for the protective check,
#ifndef __HAVE_ARCH_MEMCHR for
#ifndef __HAVE_ARCH_STRCHR for
The C library’s optimised versions do tend to used more sophisticated code, so the above doesn’t explain why the kernel doesn’t go to such great lengths to go fast. If you can find scenarios where the kernel would benefit from a more optimised version of one of these functions, I imagine a patch would be welcome (with appropriate supporting evidence, and as long as the optimised function is still understandable — see this old discussion regarding
memcpy). But I suspect the kernel’s uses of these functions often won’t make it worth it; for example
memcpy and related functions tend to be used on small buffers in the kernel. And never discount the speed gains from a short function which fits in cache or can be inlined...
In many cases, the version used ends up being the compiler’s built-in version anyway, and these are heavily optimised, much more so than even the C library’s can be (for example,
memcpy will often be converted to a register load and store, or even a constant store).
I remember that I had to fix a kernel core dump bug in Solaris in 2006 that was triggered with a ISO-9660 + Rock Ridge file system created by something other than
That ISO formatting software did not include the Rock Ridge file name in the middle of the ISO-9660 directory entry (as done by
mkisofs) but at the end of the ISO-9660 directory entry. Now you need to know that the Rock Ridge filenames are not terminated by a null byte...
What happened was that the (at that time too much optimized) string routines in the Solaris kernel could overshoot by one in some cases and if the Rock Ridge file name ended exactly at the end of a 2k sector and that sector ended just at the end of a 4k kernel memory page, this overshoot access caused a kernel panic due to an illegal memory access.
We needed to rewrite the access code to be very conservative in order to prevent this kernel panic in the future.
As you see, it is sometimes much harder to write safe code for the kernel and such code is sometimes a bit slower just in order to avoid a kernel panic.
BTW: the problem with a potentially unpredictable prefetch from the CPU in user space programs can be handled by letting the linker add a few bytes after the segments if there is the potential to hit the end of a MMU page. This does not work in a kernel that depends om mmaping areas.