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

标签 performance x86 kernel system-calls

我经常听到驱动程序开发人员说尽可能避免内核模式切换是件好事。我无法理解确切的原因。首先我的理解是——

  • 系统调用是软件中断。在 x86 上,它们是通过使用指令系统输入器触发的。这实际上看起来像一个分支指令,它从机器特定的寄存器中获取目标。
  • 系统调用实际上不必更改地址空间或进程上下文。
  • 尽管如此,它们确实将寄存器保存在进程堆栈上,并将堆栈指针更改为内核堆栈。

  • 在这些操作中,syscall 的工作方式与普通函数调用非常相似。尽管 sysenter 可能表现得像一个错误预测的分支,这可能导致处理器管道中的 ROB 刷新。即使那也不是很糟糕,就像任何其他错误预测的分支一样。

    我听到一些人在 Stack Overflow 上回答:
  • 你永远不知道系统调用需要多长时间 - [我] 是的,但任何函数都是如此。所需时间取决于函数
  • 它经常是调度点。 - [me] 进程可以重新安排,即使它一直在用户模式下运行。例如,while(1);不保证无上下文切换。

  • 实际的系统调用成本从何而来?

    最佳答案

    您没有说明您要询问的操作系统。无论如何,让我尝试一个答案。
    CPU 指令 syscallsysenter不应与 system call 的概念混淆及其在相应操作系统中的表示。
    通读 给出了每个指令所产生的开销差异的最佳解释。操作英特尔® 64 位和 IA-32 架构开发人员手册的部分 volume 2A (对于 int,请参见第 3-392 页)和 volume 2B (对于 sysenter,请参见第 4-463 页)。也不要忘记看一眼 iretdsysexit而在它。
    对操作伪代码的随意计数产生:

  • 408 行为 int
  • sysenter 55 行

  • 注:尽管现有的答案是正确的 sysentersyscall不是中断或与中断有任何关系,Linux 和 Windows 世界中的旧内核 使用中断来实现他们的系统调用机制 .在 Linux 上,这曾经是 int 0x80和在 Windows int 0x2E .因此,在这些内核版本上,IDT 必须准备好为相应的中断提供中断处理程序。在较新的系统上,确实如此,sysentersyscall指令已经完全取代了旧的方式。与 sysenter它是 MSR(机器特定寄存器)0x176sysenter 的处理程序地址准备好(请参阅下面链接的阅读 Material )。

    在 Windows 上...
    Windows 上的系统调用,就像在 Linux 上一样,会导致切换到内核模式。 NT 的调度程序不提供有关授予线程的时间的任何保证。此外,它会从线程中抽出时间,甚至可能最终导致线程饥饿。一般来说,可以说用户模式代码可以被内核模式代码抢占(除了极少数非常具体的异常(exception),您肯定会在“高级驱动程序编写类(class)”中遇到这种情况)。如果我们只看一个例子,这是完全有道理的。用户模式代码可以换出——或者,就此而言,它试图访问的数据。现在 CPU 对如何访问交换/分页文件中的页面一无所知,因此需要一个中间步骤。这也是内核模式代码必须能够抢占用户模式代码的原因。这也是 Windows 上最多产的错误检查代码之一的原因,并且主要由第三方驱动程序引起:IRQL_NOT_LESS_OR_EQUAL .这意味着当无法抢占触及该内存的代码时,驱动程序访问了分页内存。

    进一步阅读
  • SYSENTER and SYSEXIT in Windows作者 Geoff Chappell(在我的经历中总是值得一读!)
  • Sysenter Based System Call Mechanism in Linux 2.6
  • Windows NT平台具体讨论:How Do Windows NT System Calls REALLY Work?
  • Windows NT平台具体讨论:System Call Optimization with the SYSENTER Instruction
  • Windows Internals,第 5 版,作者:Russinovich 等。阿尔。 - 第 125 至 132 页。
  • ReactOS implementation of KiFastSystemCall
  • 关于系统调用与函数调用之间的性能差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11169809/

    相关文章:

    带有线性插值的 x86 程序集衰落 bmp

    c - 工作队列和中断失败

    linux - 修改menuconfig中的内核版本信息

    linux - 冗余的 Linux 内核系统调用

    x86 - 为什么在 Intel x86 64 位 CPU 中除了兼容模式还需要保护模式?

    multithreading - TLS 可变查找速度

    vim - 切换选项卡或导航行时,Ubuntu 中的 gVim 很慢

    mysql - 多个相等性测试的效率与 MySQL 中的连接

    regex - 从 perl 5.8(32 位)升级到 5.16(64 位)- 正则表达式性能受到影响

    python - 采样 Pandas Dataframe 的最快方法?