【问题标题】:Performance difference between system call vs function call系统调用与函数调用之间的性能差异
【发布时间】:2012-06-25 13:20:34
【问题描述】:

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

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

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

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

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

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

【问题讨论】:

  • 现代处理器的性能主要取决于程序使用缓存的程度。没有什么比环形过渡更糟糕的了,每个缓存都是垃圾。从 RAM 中重新加载数据、指令和 TLB 缓存需要很长时间,尤其是在数据被换出时。
  • 我不太确定,你的意思是什么。我的理解是缓存永远不必在环转换时刷新,因为地址空间仍然相同。缓存和 TLB 只需要在进程竞争切换时刷新。如果处理器可以用一些地址空间(或进程)标识符标记 TLB 条目,即使这也不需要发生。

标签: performance x86 kernel system-calls


【解决方案1】:

您没有说明您要询问的操作系统。无论如何,让我尝试一个答案。

CPU 指令 syscall 和 sysenter 不应与 system call 的概念及其在各自操作系统中的表示相混淆。

通读英特尔® 64 和 IA-32 架构开发人员手册的操作部分可以对每条指令产生的开销差异进行最佳解释 volume 2A(int,见第 3-392 页)和volume 2B(sysenter,见第 4-463 页)。另外别忘了看看iretd 和sysexit。

随意计算操作产生的伪代码:

  • int 的 408 行
  • 55 行用于sysenter

注意:虽然现有答案是正确的,sysenter 和 syscall 不是中断或与中断有任何关系,Linux 和 Windows 世界中的旧内核使用中断来实现其系统调用机制。在 Linux 上,这曾经是 int 0x80,在 Windows 上是 int 0x2E。因此,在那些内核版本上,IDT 必须准备好为相应的中断提供中断处理程序。在较新的系统上,确实如此,sysenter 和 syscall 指令已经完全取代了旧方法。 sysenter 是 MSR(机器特定寄存器)0x176,它使用 sysenter 的处理程序地址进行初始化(请参阅下面链接的阅读材料)。


在 Windows ...

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


进一步阅读

  1. SYSENTER and SYSEXIT in Windows Geoff Chappell (根据我的经验总是值得一读!)
  2. Sysenter Based System Call Mechanism in Linux 2.6
  3. Windows NT 平台具体讨论:How Do Windows NT System Calls REALLY Work?
  4. Windows NT 平台具体讨论:System Call Optimization with the SYSENTER Instruction
  5. Windows Internals,第 5 版,Russinovich 等人。人。 - 第 125 至 132 页。
  6. ReactOS implementation of KiFastSystemCall

【讨论】:

    【解决方案2】:

    SYSENTER/SYSCALL 不是软件中断;这些指令的重点是避免发出 IRQ 和调用中断处理程序引起的开销。

    在堆栈上保存寄存器需要时间,这是系统调用成本的来源。

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

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

    【讨论】:

    • 我现在明白一点了。因此,在 x86 中,系统调用背后的主要成本是节省寄存器!区别是近调用和远调用?
    • @BhaskarMuppana,保存寄存器的过程没有切换处理器环和段寄存器的成本那么大。
    猜你喜欢
    • 2018-05-22
    • 1970-01-01
    • 1970-01-01
    • 2011-02-09
    • 2011-10-12
    • 1970-01-01
    • 2012-12-01
    • 2011-08-13
    • 2019-10-20
    相关资源
    最近更新 更多