系统调用与函数调用之间的性能差异

APK*_*Kar 8 performance x86 kernel system-calls

我经常听司机开发人员说尽可能避免内核模式切换.我无法理解确切的原因.从我的理解开始是 -

  1. 系统调用是软件中断.在x86上,它们由使用指令sysenter触发.这实际上看起来像是从机器特定寄存器获取目标的分支指令.
  2. 系统调用实际上不必更改地址空间或进程上下文.
  3. 但是,它们确实在进程堆栈上保存寄存器,并将堆栈指针更改为内核堆栈.

在这些操作中,系统调用几乎像普通函数调用一样工作.虽然sysenter可能表现得像一个错误预测的分支,这可能导致处理器流水线中的ROB刷新.即使这并不是很糟糕,它就像任何其他错误预测的分支一样.

我听到一些人在Stack Overflow上回答:

  1. 你永远不知道系统调用需要多长时间 - [我]是的,但是任何功能都是如此.所需的时间取决于功能
  2. 它通常是安排现场. - [me]进程可以重新安排,即使它一直在用户模式下运行.例如,while(1);不保证无上下文切换.

实际的系统调用成本来自哪里?

Gri*_*wes 2

SYSENTER/SYSCALL 不是软件中断;这些指令的全部目的是避免因发出 IRQ 和调用中断处理程序而造成的开销。

在堆栈上保存寄存器会花费时间,这是系统调用成本的来源之一。

另一个地方来自于内核模式切换本身。它涉及更改段寄存器 - CS、DS、ES、FS、GS,它们都必须更改(在 x86-64 上成本较低,因为分段大部分未使用,但本质上您仍然需要远跳转到内核代码)并且还改变了CPU的执行环。

总结一下:函数调用(在不使用分段的现代系统上)是近调用,而系统调用涉及远调用和环切换。