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

Performance 系统调用与函数调用之间的性能差异,performance,x86,kernel,system-calls,Performance,X86,Kernel,System Calls,我经常听到驱动程序开发人员说,尽可能避免内核模式切换很好。我不明白确切的原因。首先,我的理解是- 系统调用是软件中断。在x86上,它们是通过使用指令sysenter触发的。它实际上看起来像一条分支指令,它从机器特定的寄存器中获取目标 系统调用实际上不必更改地址空间或进程上下文 不过,它们确实在进程堆栈上保存寄存器,并将堆栈指针更改为内核堆栈 在这些操作中,syscall的工作方式与普通函数调用非常相似。尽管sysenter的行为可能类似于错误预测的分支,这可能会导致处理器管道中的ROB flus

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

  • 系统调用是软件中断。在x86上,它们是通过使用指令sysenter触发的。它实际上看起来像一条分支指令,它从机器特定的寄存器中获取目标
  • 系统调用实际上不必更改地址空间或进程上下文
  • 不过,它们确实在进程堆栈上保存寄存器,并将堆栈指针更改为内核堆栈
  • 在这些操作中,syscall的工作方式与普通函数调用非常相似。尽管sysenter的行为可能类似于错误预测的分支,这可能会导致处理器管道中的ROB flush。即使这也不是很糟糕,它就像其他错误预测的分支一样

    我听到一些人在回答堆栈溢出问题:

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

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

    syscenter
    /
    syscall
    不是软件中断;这些指令的全部要点是避免因发出IRQ和调用中断处理程序而导致的开销

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

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


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

    您没有指出您要询问的操作系统。不管怎样,让我试着回答

    CPU指令
    syscall
    sysenter
    不应与a的概念及其在相应OSs中的表示混淆

    通过阅读《英特尔64和IA-32体系结构开发人员手册》(有关
    int
    ,请参阅第3-392页)和(有关
    syscenter
    ,请参阅第4-463页)中的操作部分,可以最好地解释每个指令所产生的开销差异。在查看时,也不要忘记浏览
    iretd
    sysexit

    对操作的伪代码进行偶然计数会产生:

    • 408行用于
      int
    • 55行用于
      sysenter
    注意:尽管现有的答案是正确的,即
    sysenter
    syscall
    不是中断或与中断有关,但Linux和Windows世界中较旧的内核使用中断来实现其系统调用机制。在Linux上,这曾经是
    int0x80
    ,在Windows上是
    int0x2e
    。因此,在这些内核版本上,必须对IDT进行预处理,以便为相应的中断提供中断处理程序。的确,在较新的系统上,
    syscenter
    syscall
    指令已经完全取代了旧的方式。使用
    syscenter
    时,MSR(机器特定寄存器)
    0x176
    将使用
    syscenter
    的处理程序地址进行初始化(请参阅下面链接的阅读资料)


    在Windows上。。。 在Windows上进行系统调用,就像在Linux上一样,会导致切换到内核模式。NT的调度程序不保证线程被授予的时间。此外,它还会从线程中抽走时间,甚至会导致线程饥饿。一般来说,可以说用户模式代码可以被内核模式代码抢占(在“高级驱动程序编写类”中肯定会遇到极少数非常特殊的异常)。如果我们只看一个例子,这是非常有意义的。用户模式代码可以被调出——或者,就这一点而言,可以调出它试图访问的数据。现在CPU根本不知道如何访问交换/分页文件中的页面,因此需要一个中间步骤。这也是内核模式代码必须能够抢占用户模式代码的原因。这也是Windows上出现最多的bug检查代码之一的原因,主要是由第三方驱动程序引起的:
    IRQL\u不小于或等于
    。这意味着驱动程序在无法抢占与该内存接触的代码时访问了分页内存


    进一步阅读
  • 作者:杰夫·查佩尔(以我的经验来看,总是值得一读!)
  • Windows NT平台特定讨论:
  • Windows NT平台特定讨论:
  • 窗户内部构件,第5版,由Russinovich等人出版,第125页至132页

  • 现代处理器的性能取决于程序使用缓存的能力。没有什么比环转换更糟糕的了,每个缓存都是垃圾。从RAM中重新加载数据、指令和TLB缓存需要很多时间,尤其是当数据被交换出去时。我不太确定,你在这里的意思是什么。我的理解是,缓存永远不必在环转换时刷新,因为地址空间仍然是相同的。缓存和TLB只需要在进程竞争开关上刷新。如果处理器可以用一些地址空间(或进程)标识符标记TLB条目,甚至不需要这样做。我现在理解得更好了。因此,在x86中,系统调用背后的主要成本是节省寄存器!!区别在于近调用和远调用?@BhaskarMuppana,保存寄存器的过程并没有软件的成本那么大