1. Linux内核代码的编写和优化技巧

1.1. 代码编写

  1. 使用 __same_typetypecheck编译时检查类型匹配。
  2. __printf__scanf编译时检查代码。
  3. 对宏进行undef后重新定义,生成不同的代码,如 __SYSCALL配合 unistd.h生成系统调用,TRACE_EVENT生成ftrace相关的数据结构和各个函数。
  4. 使用模板宏,减少重复代码也降低出错率,如 STANDARD_PARAM_DEF生成 module_param用到的set和get函数。
  5. 使用内联汇编提升性能。
  6. 使用位图优化内存占用。
  7. 无锁队列kfifo。

1.2. 控制编译时行为

  1. O2O3,编译时优化汇编代码。
  2. __builtin_constant_p优化常量分支。
  3. 使用 likelyunlikely,编译时对代码进程重排序。
  4. __noreturn优化不需要返回的函数。
  5. 宏、inline__always_inline,内联函数,减少入栈出栈操作。
  6. 使用 __randomize_layout,结构体布局随机化,打乱成员排序,提升入侵难度。
  7. 使用 __cacheline_aligned对结构体进行cache line对齐,提升访问性能,减少cache颠簸
  8. 细化程序分段,如 initinitdata等,释放无用内存。
  9. 区分冷热段,热段如 schedread_mostly,冷段如 tracepoint段,热段更容易常驻cache。
  10. 重要部分使用联合减少结构大小,如 struct page,减少内存占用。

1.3. 控制运行时行为

  1. 使用percpu变量减少核见竞争。
  2. 访问一个变量时,需同时获取两把锁,将锁放到不同的cache line。如struct zone
  3. 使用动态代码修改,如 jump_labelalternative_if,减少分支判断。
  4. 栈随机化和地址空间布局随机化(KASLR),提升攻击难度。
  5. 零拷贝技术、写时复制

2. Linux内核中的面向对象编程

  1. 使用函数回调,抽象通用接口
  2. 抽象通用数据结构,使用container获取自定义数据结构

2.1. 使用 __noreturn会有哪些编译优化?

使用 __noreturn属性可以允许编译器进行一些特定的优化,因为编译器知道带这个属性的函数不会返回。这些优化可能包括:

  1. 省略返回值:如果一个函数被标记为 __noreturn,并且它的返回类型不是 void,编译器可能会省略对返回值的处理,因为它知道这个函数不会返回给调用者。
  2. 省略后续代码的生成:在函数调用的后面如果有代码,编译器可能会省略这些代码的生成,因为它们永远不会被执行。
  3. 优化调用栈:编译器可能会优化函数调用的栈处理,因为不需要为非 void返回类型的函数保留返回地址。
  4. 分支预测:编译器可能会对调用 __noreturn函数的代码进行分支预测优化,因为它知道执行流程将不会回到正常的控制流。
  5. 省略函数结束时的清理代码:通常,函数在返回前需要执行一些清理工作,比如释放局部变量的存储空间。对于标记为 __noreturn的函数,这些清理工作可能被省略。
  6. 优化错误处理代码:如果一个函数在错误处理分支中调用 __noreturn函数,编译器可能会优化这些错误处理路径,因为它们不会导致函数的正常返回。
  7. 消除不必要的检查:例如,如果一个 __noreturn函数的返回值被用来做条件判断,编译器可能会省略这些检查,因为函数不会返回。 需要注意的是,虽然 __noreturn可以带来一些优化,但它也可能导致一些问题,如果使用不当。例如,如果一个函数被错误地标记为 __noreturn但实际上它可以返回,那么编译器可能会省略一些重要的代码路径,导致未定义的行为。因此,使用 __noreturn时必须非常小心,确保函数确实不会返回。