当我尝试自己实现C字符串库时,我发现glibc和Linux内核对某些功能的实现方式有所不同。例如,glibc内存记录器和glibc 字符串使用一些技巧来加速该功能但是内核memchr和内核strchr不。为什么Linux内核函数没有像glibc那样进行优化?
答案1
内核确实在特定于架构的目录中提供了其中一些函数的优化版本;参见例如x86 实现memchr
(看所有的memchr
定义, 和所有的strchr
定义)。您找到的版本是后备通用版本;您可以通过查找保护性检查#ifndef __HAVE_ARCH_MEMCHR
formemchr
和#ifndef __HAVE_ARCH_STRCHR
for来发现这些strchr
。
C 库的优化版本确实倾向于使用更复杂的代码,因此上面的内容并不能解释为什么内核不竭尽全力去加快速度。如果您能找到内核可以从这些功能之一的更优化版本中受益的场景,我想补丁会受到欢迎(有适当的支持证据,并且只要优化的功能仍然是可以理解的 - 请参阅这个旧的讨论关于memcpy
)。但我怀疑内核对这些函数的使用通常不会使它值得;例如memcpy
,相关函数往往在内核中的小缓冲区上使用。并且永远不要低估适合缓存或可以内联的短函数所带来的速度增益......
此外,正如我将不存在 我不存在,MMX和SSE不能轻易在内核中使用,许多优化版本的内存搜索或复制功能都依赖于它们。
在许多情况下,使用的版本最终是编译器的内置版本无论如何,这些都经过了高度优化,甚至比 C 库的优化还要好(例如,memcpy
通常会转换为寄存器加载和存储,甚至常量存储)。
答案2
我记得我必须在 2006 年修复 Solaris 中的一个内核核心转储错误,该错误是由由mkisofs
.
该 ISO 格式化软件并未将 Rock Ridge 文件名包含在 ISO-9660 目录条目的中间(如 所做的那样mkisofs
),而是将其包含在 ISO-9660 目录条目的末尾。现在您需要知道 Rock Ridge 文件名不是以空字节终止的...
发生的情况是,Solaris 内核中的(当时过于优化的)字符串例程在某些情况下可能会超出 1,并且如果 Rock Ridge 文件名正好在 2k 扇区的末尾结束,而该扇区恰好在末尾结束对于 4k 内核内存页面,这种超调访问会因非法内存访问而导致内核恐慌。
我们需要将访问代码重写得非常保守,以防止将来出现这种内核恐慌。
正如您所看到的,有时为内核编写安全代码要困难得多,并且这样的代码有时会慢一些,只是为了避免内核恐慌。
顺便说一句:如果有可能到达 MMU 页的末尾,则可以通过让链接器在段后添加几个字节来处理用户空间程序中来自 CPU 的潜在不可预测的预取问题。这在依赖于映射区域的内核中不起作用。