Windows上的系统调用本身是否比Linux慢?

时间:2014-02-27 12:50:29

标签: linux windows operating-system system-calls

我对系统调用的理解是,在Linux中,系统调用机制(int 0x80或其他)被记录在案,并保证在不同的内核版本中保持稳定。使用此信息,系统调用直接在CRT库中实现,因此当我调用例如printf("a");这涉及对CRT的单个函数调用,其中系统调用已设置并激活。从理论上讲,这可以通过静态编译CRT(在Linux上不常见,但有可能)进一步改进,这样即使单个函数调用也可以内联。

另一方面,Windows不记录甚至不保证系统调用机制的一致性。在Windows上进行系统调用的唯一方式是调用ntdll.dll(或者可能是其他*.dll),这是从CRT完成的,因此有涉及两个函数调用。如果静态使用CRT并且函数内联(在Windows上比Linux稍微常见),我们仍然可以调用ntdll.dll的单个函数,而这是我们无法摆脱的。

因此,在我看来理论上,Windows上的系统调用本身就会变慢,因为它们总是必须执行一个函数调用,而不是Linux等价函数。这种理解(以及我上面的解释)是真的吗?

注意:我纯粹在理论上问这个问题。我理解在进行系统调用时(我认为总是涉及2个上下文切换 - 每个方向一个),额外函数调用的成本可能完全可以忽略不计。

1 个答案:

答案 0 :(得分:9)

在IA-32上,有两种方法可以进行系统调用:

  • 使用int / iret说明
  • 使用sysenter / sysexit说明

基于纯int / iret的系统调用需要211个CPU周期(在现代处理器上甚至更多)。 Sysenter / sysexit需要46个CPU滴答。正如您所看到的,只有一对用于系统调用的指令的执行会带来很大的开销。但是任何系统调用实现都涉及内核方面的一些工作(内核上下文的设置,调用的调度及其参数等)。对于基于int / iret和sysenter / sysexit的系统调用,或多或少现实的高度优化的系统调用将花费约250和~100个CPU周期。在Linux和Windows中,它需要大约500个滴答。

同时,函数调用(基于call / ret)每个参数的成本为2-4 tics + 1。

如您所见,函数调用引入的开销与系统调用成本的比较可以忽略不计。

另一方面,如果在应用程序中嵌入原始系统调用,则会使其高度依赖硬件。例如,如果没有这些指令支持的基于sysenter / sysexit的原始系统调用的应用程序将在旧PC上执行,该怎么办?此外,您的应用程序将对操作系统使用的系统调用约定敏感。

通常使用像ntdll.dll和glibc这样的库,因为它们为系统服务提供了众所周知的和独立于硬件的接口,并隐藏了与场景后面的内核通信的细节。

如果使用相同的方式跨越用户/内核空间边界,Linux和Windows的系统调用成本大致相同(差异可以忽略不计)。两者都尝试在每台特定机器上使用最快的方式。至少从Windows XP开始的所有现代Windows版本都是为sysenter / sysexit准备的。一些旧的和/或特定版本的Linux仍然可以使用基于int / iret的调用。 x64版本的操作系统依赖于syscall / sysret指令,这些指令的作用类似于sysenter / sysexit,并作为AMD64指令集的一部分提供。