作業系統介面

系統呼叫的成本(the cost of a system call)

想像在家工作,相對於走去政府機關蓋一個表格的章。任何你能在自己桌前做的事都幾乎是瞬間完成。但每一趟去機關——即使只是蓋個微不足道的章——都要花你去程的路、安檢、等候、回程的路。這趟路就是開銷,它遠遠蓋過實際蓋章那一下。系統呼叫正是這個形狀:跨越邊界的成本,往往遠大於那個小操作本身。

具體而言,系統呼叫遠比普通函式呼叫昂貴,原因就在跨越邊界所需的代價。CPU 必須從使用者模式切到核心模式再切回來、保存並還原暫存器與狀態、並在真正開始工作之前先跑過核心的進入與驗證程式碼。還有更隱微的成本:這次切換可能擾亂 CPU 的快取與管線,而現代的安全緩解措施更讓這次跨越比以往昂貴。一次單純的函式呼叫可能只花少數幾個 CPU 週期;一次系統呼叫光是純開銷通常就要數百到數千個週期,這還沒算上它所請求的實際工作。確切數字因 CPU 與作業系統而異——重點是數量級,而非精確的數字。

為何重要:這個成本正是為什麼高效能的系統程式碼會設法進行較少、較大的系統呼叫,而不是許多細碎的呼叫。用一百萬次 read() 一次一位元組地讀檔案,比起一次讀一大塊要慢得驚人,即使總位元組數一模一樣——因為每一次呼叫都要付過路費。這個單一事實解釋了為什麼有緩衝(C 函式庫把你細小的寫入批次成一次大的系統呼叫)、為什麼有批量與向量化的 I/O 呼叫、以及為什麼一個顯示程式淹沒在系統呼叫裡的剖析器,正指向一個真實且可修正的效能問題。

用一次一位元組地呼叫 read() 與 write() 來複製一百萬位元組(約一 MiB),會進行約兩百萬次系統呼叫;而以 64 KiB 為一塊來複製,只進行約三十次。搬動的位元組相同,但一次一位元組的版本可能單純因跨越邊界的開銷而慢上數十倍。

較少、較大的呼叫勝過許多細小的呼叫——過路費是按跨越次數收、不是按位元組收。

昂貴並不等於絕對意義上的慢——對人而言,一次系統呼叫仍然很快。只有當你在緊密的迴圈裡做很多次時,這個成本才會咬人。解法通常是批次處理(每次呼叫讀或寫更多)或緩衝,而不是完全避開系統呼叫。

又稱
syscall overheaduser/kernel boundary cost系統呼叫開銷邊界跨越成本