[英]Performance difference between system call vs function call
I quite often listen to driver developers saying its good to avoid kernel mode switches as much as possible. 我经常听到驱动程序开发人员说,这样做有助于避免内核模式切换。 I couldn't understand the precise reason. 我不明白确切的原因。 To start with my understanding is - 首先我的理解是-
Among these operations syscall pretty much works like a normal function call. 在这些操作中,syscall几乎像正常的函数调用一样工作。 Though the sysenter could behave like a mis-predicted branch which could lead to ROB flush in processor pipeline. 虽然sysenter的行为可能像一个错误预测的分支,但可能导致处理器管道中的ROB刷新。 Even that is not really bad, its just like any other mis-predicted branch. 即使那还算不错,就像其他任何错误预测的分支一样。
I heard a few people answering on Stack Overflow: 我听说有人在Stack Overflow上回答:
while(1);
例如, while(1);
doesnt guarantee a no-context switch. 不保证无上下文切换。 Where is the actual syscall cost coming from? 实际的系统调用成本来自哪里?
You don't indicate what OS you are asking about. 您没有指明要询问的操作系统。 Let me attempt an answer anyway. 无论如何,让我尝试一个答案。
The CPU instructions syscall
and sysenter
should not be confused with the concept of a system call and its representation in the respective OSs. CPU指令syscall
和sysenter
不应与系统调用的概念及其在各个OS中的表示相混淆。
The best explanation for the difference in the overhead incurred by each respective instruction is given by reading through the Operation sections of the Intel® 64 and IA-32 Architectures Developer's Manual volume 2A (for int
, see page 3-392) and volume 2B (for sysenter
see page 4-463). 用于在由每个相应的指令所引起的开销的差最好的解释是通过在64和IA-32架构开发者手册的操作部分读取给定的体积2A (对于int
,见3-392页)和体积2B (对于sysenter
见4-463页)。 Also don't forget to glance at iretd
and sysexit
while at it. 同时也不要忘记浏览iretd
和sysexit
。
A casual counting of the pseudo-code for the operations yields: 对该操作的伪代码进行随意计数会得出:
int
int
408行 sysenter
sysenter
55行 Note: Although the existing answer is right in that sysenter
and syscall
are not interrupts or in any way related to interrupts, older kernels in the Linux and the Windows world used interrupts to implement their system call mechanism . 注意:尽管现有的答案很正确,因为sysenter
和syscall
不是中断,或与中断没有任何关系,但是Linux和Windows世界中的较早内核使用中断来实现其系统调用机制 。 On Linux this used to be int 0x80
and on Windows int 0x2E
. 在Linux上,它以前是int 0x80
,在Windows上是int 0x2E
。 And consequently on those kernel versions the IDT had to be primed to provide an interrupt handler for the respective interrupt. 因此,在那些内核版本上,必须对IDT进行灌注以为相应的中断提供中断处理程序。 On newer systems, that's true, the sysenter
and syscall
instructions have completely replaced the old ways. 在较新的系统上,的确如此, sysenter
和syscall
指令已完全取代了旧方法。 With sysenter
it's the MSR (machine specific register) 0x176
which gets primed with the address of the handler for sysenter
(see the reading material linked below). 对于sysenter
它是MSR(机器专用寄存器) 0x176
,它使用0x176
处理程序的地址进行sysenter
(请参阅下面的阅读材料链接)。
A system call on Windows, just like on Linux, results in the switch to kernel mode. 与Linux一样,Windows上的系统调用也会导致切换到内核模式。 The scheduler of NT doesn't provide any guarantees about the time a thread is granted. NT的调度程序不保证线程被授予的时间。 Also it yanks away time from threads and can even end up starving threads. 同样,它浪费了线程的时间,甚至可能导致线程饥饿。 In general one can say that user mode code can be preempted by kernel mode code (with very few very specific exceptions to which you'll certainly get in the "advanced driver writing class"). 通常,可以说用户模式代码可以被内核模式代码抢占(只有很少的非常具体的异常,您肯定会在“高级驱动程序编写类”中得到这些异常)。 This makes perfect sense if we only look at one example. 如果只看一个例子,这是很合理的。 User mode code can be swapped out - or, for that matter, the data it's trying to access. 用户模式代码可以换出-或换而言之,它正在尝试访问的数据。 Now the CPU doesn't have the slightest clue how to access pages in the swap/paging file, so an intermediate step is required. 现在,CPU没有丝毫线索了解如何访问交换/分页文件中的页面,因此需要一个中间步骤。 And that's also why kernel mode code must be able to preempt user mode code. 这也是为什么内核模式代码必须能够抢占用户模式代码的原因。 It is also the reason for one of the most prolific bug-check codes seen on Windows and mostly caused by third-party drivers: IRQL_NOT_LESS_OR_EQUAL
. 这也是Windows上出现的最多产的bug检查代码之一,并且主要由第三方驱动程序引起的原因: IRQL_NOT_LESS_OR_EQUAL
。 It means that a driver accessed paged memory when it wasn't possible to preempt the code touching that memory. 这意味着驱动程序在无法抢占接触该内存的代码时访问了页面内存。
KiFastSystemCall
KiFastSystemCall
ReactOS实现 SYSENTER
/ SYSCALL
is not a software interrupt; SYSENTER
/ SYSCALL
不是软件中断; whole point of those instructions is to avoid overhead caused by issuing IRQ and calling interrupt handler. 这些指令的全部目的是为了避免由于发出IRQ和调用中断处理程序而引起的开销。
Saving registers on stack costs time, this is one place where the syscall cost comes from. 将寄存器保存在堆栈上会花费时间,这是系统调用成本的来源之一。
Another place comes from the kernel mode switch itself. 另一个地方来自内核模式开关本身。 It involves changing segment registers - CS, DS, ES, FS, GS, they all have to be changed (it's less costly on x86-64, as segmentation is mostly unused, but you still need to essentially make far jump to kernel code) and also changes CPU ring of execution. 它涉及到更改段寄存器-CS,DS,ES,FS,GS,所有这些都必须更改(在x86-64上成本较低,因为段未使用,但是您仍然需要从根本上跳到内核代码)并更改CPU执行环。
To conclude: function call is (on modern systems, where segmentation is not used) near call, while syscall involves far call and ring switch. 得出的结论是:函数调用是(在现代系统中,不使用分段的)近调用,而syscall涉及远调用和振铃切换。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.