(1) int 80h
保護模式下執行int 80h
指令的過程比較複雜
[1] cpu 根據中斷號 80h 和 idtr(idt記憶體位址) 讀取描述符 idt[80h] (並作有效、特權級等檢查);
[2] cpu 根據 idt[80h] 描述符中的 gdt 選擇符(s)和 gdtr(gdt記憶體位址)讀取段描述符 gdt[s](並作有效、特權級等檢查);
idt
+==+ logic memory addr
idtr[1]|..| ^
+ -->+--+ sys_fn [3]|
80h | |-+-----------------------+
+--+ | |
|..| | |
+==+ | gdt |
| +==+ |
v [2]|..| |
gdtr + selcotr-->+--+ base_addr |
| |-----------+
+--+
|..|
+==+
[3] 現場(暫存器)備份
+-----+
| ss |棧切換
|-----|備份
| esp |
+-----+
|eflag|tf=if=0
+-----+
| cs |跳轉
|-----|備份
| eip |
+-----+
以及規定由子函式備份的暫存器
[4] 結合 gdt[s] 中的段基址和 idt[80h] 中的系統呼叫入口函式偏移位址生成系統呼叫入口函式的邏輯記憶體位址,該邏輯記憶體位址經頁轉換便得到系統呼叫入口函式的物理記憶體位址;
[5] 棧切換並跳轉執行(會導致清空cpu流水線,快取重載入)系統呼叫入口函式處;
(2) 執行系統呼叫(可能會因共享資源如緩衝區缺乏進入睡眠而主動切換其他程序執行,程序切換的tss備份開銷和其它程序在時間片期間的執行應該比整個系統呼叫切換開銷大);
(3) 系統呼叫返回,彈出核心棧中備份的暫存器,切換使用者程式棧,返回使用者程式系統呼叫處(會導致清空cpu流水線,快取重載入)。
拋開(2)(假設所需的核心資源充足),系統呼叫開銷主要體現在
[1] 系統呼叫的執行;
[2] 重新整理cpu流水線,快取過載;
[3] 記憶體中描述符解析;
[4] 現場備份和恢復。
假設使用者自己寫**完成系統呼叫的功能,且二者時間效能相近,那麼系統呼叫的主要開銷為
[1] 重新整理cpu流水線,快取過載——使用者態和核心態之間的切換破壞了暫存器(如ss:esp,cs:eip)所指記憶體的區域性性;
[2] 記憶體中描述符解析;
[3] 現場備份和恢復。
在這些開銷中,[1]和[2]是主要開銷。
當所需核心資源不足時,系統呼叫開銷可能主要體現在對核心資源的等待上
[1] 等待核心資源(程序切換/排程開銷);
[2] 重新整理cpu流水線;記憶體中描述符解析;現場備份和恢復。
程序切換中的大部分工作(如tss備份與恢復,描述符的解析)由cpu自動完成,依賴cpu的速度;排程則主要依賴於核心軟體的排程演算法(當然也依賴於執行程式的速度)。
所以,在現實應用中,需要避開哪一種效能開銷會影響我們的選擇(如等待核心資源開銷在任何時間都是絕對不被忍受的,那就不能用系統呼叫)。
在以下環境下粗略測試一下系統開銷。
$ lscpu
architecture: x86_64
cpu op-mode(s): 32-bit, 64-bit
cpu(s): 4
on-line cpu(s) list: 0-3
型號名稱: intel(r) xeon(r) cpu e5-2640 v3 @ 2.60ghz
cpu mhz: 2594.040
l1d 快取: 32k
l1i 快取: 32k
l2 快取: 256k
l3 快取: 20480k
$ uname -srm
linux 3.10.0-327.el7.x86_64 x86_64
即主頻為2.60ghz、4核支援64位運算、擁有4級cache(速度最快的資料和指令cache分別32k)的cpu搭配核心版本為3的linux os。
在實際測試之前先對cpu主頻進行乙個粗略
感觀。假設
[1] 乙個簡單的c語句平均對應10條彙編指令;
[2] 指令執行的平均週期為10個cpu週期;
[3] cpu獲取一條指令的平均時間為5個cpu週期(cpu 讀 l1i/l1d 約1-3個週期;讀記憶體約幾個到10個週期)。
那麼主頻為2.6ghz的單核cpu 1秒鐘大約能執行5200000條簡單的c語句(若cache區域性性好,能執行更多的c語句)。
測試物件是uds(unix domain socket, unix套接字域——用於本機程序通訊)中的connect()的開銷,測試方法是將包含uds connet() 程式的程序置於linux中執行,並隨機取100組來分析
st.sec=1585985495 st.nsec=956157019
et.sec=1585985495 et.nsec=956188018
st.sec=1585985495 st.nsec=956213321
et.sec=1585985495 et.nsec=956216422
st.sec=1585985495 st.nsec=957371430
et.sec=1585985495 et.nsec=957380706
st.sec=1585985496 st.nsec=50087302
et.sec=1585985496 et.nsec=50106971
st.sec=1585985496 st.nsec=74541241
et.sec=1585985496 et.nsec=74564802
...
uds connect() 在以上環境時間開銷約為26微秒。該時間包含了connect()功能**執行的時間以及系統呼叫相關(如描述符解析、流水線重新整理、現場備份與恢復;但應該不包含資源等待)的時間開銷。即在系統資源正常情況下,若我們自己實現connect()的功能**,所能節約的時間小於該值。
該測試結果在不同的硬體環境以及不同的linux版本上會有差異。
Linux 0 11 系統呼叫學習
通過增加乙個系統呼叫來了解系統呼叫的實現原理。增加 int fun void 1 在include unistd.h 中加入 define nr fun72 加入系統函式呼叫宣告 int fun void 2.在include linux sys.h 加入系統函式宣告 extern int sys ...
Linux 0 11 系統呼叫原理
一 概述 系統呼叫是乙個軟中斷,中斷號是0x80,它是上層應用程式與linux系統核心進行互動通訊的唯一介面。通過int 0x80,就可使用核心資源。不過,通常應用程式都是使用具有標準介面定義的c函式庫間接的使用核心的系統呼叫,即應用程式呼叫c函式庫中的函式,c函式庫中再通過int 0x80進行系統...
如何向Linux0 11新增乙個系統呼叫?
我們假設這個呼叫是foo 返回值型別是void。linux0.11實現系統呼叫的基本過程如下 舉例說明 include linux sys.h extern intsys iam sys iam include unistd.h define nr iam 72 intiam const char ...