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

Bar*_*uch 6 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个上下文切换 - 每个方向一个),额外函数调用的成本可能完全可以忽略不计.

Zar*_*trA 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上执行,该怎么办?此外,您的应用程序将对OS使用的系统调用约定敏感.

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

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