Windows上的系统调用本质上比Linux更慢吗?

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

另一方面,Windows不logging甚至保证系统调用机制的一致性。 在Windows上进行系统调用的唯一方法是调用由CRT完成的ntdll.dll (或者其他一些*.dll ),因此涉及到两个函数调用。 如果CRT被静态使用,并且函数被内联(在Windows上比在Linux上稍微普遍),我们仍然把单个函数调用到ntdll.dll ,这是我们无法摆脱的。

所以在我看来,理论上Windows上的系统调用本质上会比较慢,因为他们总是需要做一个函数调用,而不是他们的Linux等价物。 这种理解(以及我上面的解释)是正确的吗?

注:我纯粹从理论上提出这个问题。 我知道在进行系统调用时(我认为总是涉及2个上下文切换 – 每个方向都有一个切换),额外函数调用的代价可能完全可以忽略不计。

在IA-32上有两种方式进行系统调用:

  • 使用int / iret指令
  • 使用sysenter / sysexit指令

基于纯int / iret的系统调用需要211个CPU周期(现代处理器甚至更多)。 Sysenter / sysexit需要46个CPU ticks。 正如你所看到的,只有一对用于系统调用的指令执行会带来很大的开销。 但任何系统调用实现都涉及到内核方面的一些工作(内核上下文的设置,调用调用及其参数等)。 对于基于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版本至少从Windows XP开始准备sysenter / sysexit。 某些旧的和/或特定版本的Linux仍然可以使用基于int / iret的调用。 x64版本的操作系统依赖于syscall / sysret指令,其工作方式与sysenter / sysexit类似,可作为AMD64指令集的一部分使用。