[英]Performance difference between system call vs function call
我經常聽到驅動程序開發人員說,這樣做有助於避免內核模式切換。 我不明白確切的原因。 首先我的理解是-
在這些操作中,syscall幾乎像正常的函數調用一樣工作。 雖然sysenter的行為可能像一個錯誤預測的分支,但可能導致處理器管道中的ROB刷新。 即使那還算不錯,就像其他任何錯誤預測的分支一樣。
我聽說有人在Stack Overflow上回答:
while(1);
不保證無上下文切換。 實際的系統調用成本來自哪里?
您沒有指明要詢問的操作系統。 無論如何,讓我嘗試一個答案。
CPU指令syscall
和sysenter
不應與系統調用的概念及其在各個OS中的表示相混淆。
用於在由每個相應的指令所引起的開銷的差最好的解釋是通過在64和IA-32架構開發者手冊的操作部分讀取給定的體積2A (對於int
,見3-392頁)和體積2B (對於sysenter
見4-463頁)。 同時也不要忘記瀏覽iretd
和sysexit
。
對該操作的偽代碼進行隨意計數會得出:
int
408行 sysenter
55行 注意:盡管現有的答案很正確,因為sysenter
和syscall
不是中斷,或與中斷沒有任何關系,但是Linux和Windows世界中的較早內核使用中斷來實現其系統調用機制 。 在Linux上,它以前是int 0x80
,在Windows上是int 0x2E
。 因此,在那些內核版本上,必須對IDT進行灌注以為相應的中斷提供中斷處理程序。 在較新的系統上,的確如此, sysenter
和syscall
指令已完全取代了舊方法。 對於sysenter
它是MSR(機器專用寄存器) 0x176
,它使用0x176
處理程序的地址進行sysenter
(請參閱下面的閱讀材料鏈接)。
與Linux一樣,Windows上的系統調用也會導致切換到內核模式。 NT的調度程序不保證線程被授予的時間。 同樣,它浪費了線程的時間,甚至可能導致線程飢餓。 通常,可以說用戶模式代碼可以被內核模式代碼搶占(只有很少的非常具體的異常,您肯定會在“高級驅動程序編寫類”中得到這些異常)。 如果只看一個例子,這是很合理的。 用戶模式代碼可以換出-或換而言之,它正在嘗試訪問的數據。 現在,CPU沒有絲毫線索了解如何訪問交換/分頁文件中的頁面,因此需要一個中間步驟。 這也是為什么內核模式代碼必須能夠搶占用戶模式代碼的原因。 這也是Windows上出現的最多產的bug檢查代碼之一,並且主要由第三方驅動程序引起的原因: IRQL_NOT_LESS_OR_EQUAL
。 這意味着驅動程序在無法搶占接觸該內存的代碼時訪問了頁面內存。
KiFastSystemCall
ReactOS實現 SYSENTER
/ SYSCALL
不是軟件中斷; 這些指令的全部目的是為了避免由於發出IRQ和調用中斷處理程序而引起的開銷。
將寄存器保存在堆棧上會花費時間,這是系統調用成本的來源之一。
另一個地方來自內核模式開關本身。 它涉及到更改段寄存器-CS,DS,ES,FS,GS,所有這些都必須更改(在x86-64上成本較低,因為段未使用,但是您仍然需要從根本上跳到內核代碼)並更改CPU執行環。
得出的結論是:函數調用是(在現代系統中,不使用分段的)近調用,而syscall涉及遠調用和振鈴切換。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.