CPU上下文切換

椪髯郑空間

  1. 用戶態(tài)函數(shù)棧
    主要用于用戶態(tài)的函數(shù)調(diào)用


    image.png
  2. 內(nèi)核棧
    Linux 給每個 task 都分配了內(nèi)核棧,主要用于內(nèi)核態(tài)的函數(shù)調(diào)用
    除了內(nèi)核棧赌结,還有內(nèi)核寄存器吃环,pt_regs主要應(yīng)用于態(tài)轉(zhuǎn)換內(nèi)核態(tài)時,保護(hù)應(yīng)用態(tài)上下文的(保存寄存器)。


    image.png
  3. 總結(jié)


    image.png

上下文切換含義

什么是上下文

在每個任務(wù)運行前碳却,CPU 都需要知道任務(wù)從哪里加載队秩、又從哪里開始運行,也就是說昼浦,需要系統(tǒng)事先幫它設(shè)置好 CPU 寄存器和程序計數(shù)器(Program Counter馍资,PC)。
CPU 寄存器关噪,是 CPU 內(nèi)置的容量小鸟蟹、但速度極快的內(nèi)存。而程序計數(shù)器使兔,則是用來存儲 CPU 正在執(zhí)行的指令位置建钥、或者即將執(zhí)行的下一條指令位置。它們都是 CPU 在運行任何任務(wù)前虐沥,必須的依賴環(huán)境锦针,因此也被叫做 CPU 上下文。
下文是指某一時間點CPU寄存器(CPU register)和程序計數(shù)器(PC)的內(nèi)容, 廣義上還包括內(nèi)存中進(jìn)程的虛擬地址映射信息.

什么是上下文切換

CPU 上下文切換置蜀,就是先把前一個任務(wù)的 CPU 上下文(也就是 CPU 寄存器和程序計數(shù)器)保存起來奈搜,然后加載新任務(wù)的上下文到這些寄存器和程序計數(shù)器,最后再跳轉(zhuǎn)到程序計數(shù)器所指的新位置盯荤,運行新任務(wù)馋吗。
而這些保存下來的上下文宅此,會存儲在系統(tǒng)內(nèi)核中中姜,并在任務(wù)重新調(diào)度執(zhí)行時再次加載進(jìn)來。這樣就能保證任務(wù)原來的狀態(tài)不受影響骂因,讓任務(wù)看起來還是連續(xù)運行灼卢。

上下文切換場景

  1. 系統(tǒng)調(diào)用
    Linux 按照特權(quán)等級绍哎,把進(jìn)程的運行空間分為內(nèi)核空間和用戶空間,分別對應(yīng)著下圖中鞋真, CPU 特權(quán)等級的 Ring 0 和 Ring 3崇堰。
  • 內(nèi)核空間(Ring 0)具有最高權(quán)限,可以直接訪問所有資源涩咖;
  • 用戶空間(Ring 3)只能訪問受限資源海诲,不能直接訪問內(nèi)存等硬件設(shè)備,必須通過系統(tǒng)調(diào)用陷入到內(nèi)核中檩互,才能訪問這些特權(quán)資源特幔。


    image.png

    換個角度看,也就是說闸昨,進(jìn)程既可以在用戶空間運行蚯斯,又可以在內(nèi)核空間中運行薄风。進(jìn)程在用戶空間運行時,被稱為進(jìn)程的用戶態(tài)拍嵌,而陷入內(nèi)核空間的時候村刨,被稱為進(jìn)程的內(nèi)核態(tài)。從用戶態(tài)到內(nèi)核態(tài)的轉(zhuǎn)變撰茎,需要通過系統(tǒng)調(diào)用來完成。內(nèi)核空間態(tài)資源包括內(nèi)核的堆棧打洼、寄存器等龄糊;用戶空間態(tài)資源包括虛擬內(nèi)存、棧募疮、變量炫惩、正文、數(shù)據(jù)等阿浓。


    image.png

    CPU 寄存器里原來用戶態(tài)的指令位置他嚷,需要先保存起來。接著芭毙,為了執(zhí)行內(nèi)核態(tài)代碼筋蓖,CPU 寄存器需要更新為內(nèi)核態(tài)指令的新位置。最后才是跳轉(zhuǎn)到內(nèi)核態(tài)運行內(nèi)核任務(wù)退敦。
    而系統(tǒng)調(diào)用結(jié)束后粘咖,CPU 寄存器需要恢復(fù)原來保存的用戶態(tài),然后再切換到用戶空間侈百,繼續(xù)運行進(jìn)程瓮下。所以,一次系統(tǒng)調(diào)用的過程钝域,其實是發(fā)生了兩次 CPU 上下文切換讽坏。
    image.png
  1. 進(jìn)程切換
    進(jìn)程是由內(nèi)核來管理和調(diào)度的,進(jìn)程的切換只能發(fā)生在內(nèi)核態(tài)例证。所以路呜,進(jìn)程的上下文不僅包括了虛擬內(nèi)存、棧织咧、全局變量等用戶空間的資源拣宰,還包括了內(nèi)核堆棧、寄存器等內(nèi)核空間的狀態(tài)烦感。因此巡社,進(jìn)程的上下文切換就比系統(tǒng)調(diào)用時多了一步:在保存當(dāng)前進(jìn)程的內(nèi)核狀態(tài)和 CPU 寄存器之前,需要先把該進(jìn)程的虛擬內(nèi)存手趣、棧等保存下來晌该;而加載了下一進(jìn)程的內(nèi)核態(tài)后肥荔,還需要刷新進(jìn)程的虛擬內(nèi)存和用戶棧。即除了cpu上下文切換朝群,還有進(jìn)程空間虛擬內(nèi)存切換燕耿。
    如下圖所示,保存上下文和恢復(fù)上下文的過程并不是“免費”的姜胖,需要內(nèi)核在 CPU 上運行才能完成誉帅。


    image.png

    每次上下文切換都需要幾十納秒到數(shù)微秒的 CPU 時間。這個時間還是相當(dāng)可觀的右莱,特別是在進(jìn)程上下文切換次數(shù)較多的情況下蚜锨,很容易導(dǎo)致 CPU 將大量時間耗費在寄存器、內(nèi)核棧以及虛擬內(nèi)存等資源的保存和恢復(fù)上慢蜓,進(jìn)而大大縮短了真正運行進(jìn)程的時間亚再。
    另外,Linux 通過 TLB(Translation Lookaside Buffer)來管理虛擬內(nèi)存到物理內(nèi)存的映射關(guān)系晨抡。當(dāng)虛擬內(nèi)存更新后氛悬,TLB 也需要刷新,內(nèi)存的訪問也會隨之變慢耘柱。特別是在多處理器系統(tǒng)上如捅,緩存是被多個處理器共享的,刷新緩存不僅會影響當(dāng)前處理器的進(jìn)程调煎,還會影響共享緩存的其他處理器的進(jìn)程伪朽。

  2. 同進(jìn)程不同線程間切換
    在切換時,虛擬內(nèi)存這些資源就保持不動汛蝙,只需要切換線程的私有數(shù)據(jù)烈涮、寄存器等不共享的數(shù)據(jù)

  3. 中斷上下文切換
    為了快速響應(yīng)硬件的事件,中斷處理會打斷進(jìn)程的正常調(diào)度和執(zhí)行窖剑,轉(zhuǎn)而調(diào)用中斷處理程序坚洽,響應(yīng)設(shè)備事件。而在打斷其他進(jìn)程時西土,就需要將進(jìn)程當(dāng)前的狀態(tài)保存下來讶舰,這樣在中斷結(jié)束后,進(jìn)程仍然可以從原來的狀態(tài)恢復(fù)運行需了。
    跟進(jìn)程上下文不同跳昼,中斷上下文切換并不涉及到進(jìn)程的用戶態(tài)。所以肋乍,即便中斷過程打斷了一個正處在用戶態(tài)的進(jìn)程鹅颊,也不需要保存和恢復(fù)這個進(jìn)程的虛擬內(nèi)存、全局變量等用戶態(tài)資源墓造。中斷上下文堪伍,其實只包括內(nèi)核態(tài)中斷服務(wù)程序執(zhí)行所必需的狀態(tài)锚烦,包括 CPU 寄存器、內(nèi)核堆棧帝雇、硬件中斷參數(shù)等涮俄。
    對同一個 CPU 來說,中斷處理比進(jìn)程擁有更高的優(yōu)先級尸闸,所以中斷上下文切換并不會與進(jìn)程上下文切換同時發(fā)生彻亲。同樣道理,由于中斷會打斷正常進(jìn)程的調(diào)度和執(zhí)行吮廉,所以大部分中斷處理程序都短小精悍苞尝,以便盡可能快的執(zhí)行結(jié)束。

  4. 總結(jié)
    正常情況下茧痕,損耗對比關(guān)系如下:
    進(jìn)程上下文切換>同進(jìn)程線程上下文切換>中斷上下文切換>內(nèi)核模式切換>協(xié)程上下文切換>用戶態(tài)函數(shù)調(diào)用上下文切換

上下文切換定量查看

  1. 系統(tǒng)層面
    vmstat 是一個常用的系統(tǒng)性能分析工具,主要用來分析系統(tǒng)的內(nèi)存使用情況恼除,也常用來分析 CPU 上下文切換和中斷的次數(shù)踪旷。
# 每隔5秒輸出1組數(shù)據(jù)
$ vmstat 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 0  0      0 7005360  91564 818900    0    0     0     0   25   33  0  0 100  0  0
  • cs(context switch)是每秒上下文切換的次數(shù)。
  • in(interrupt)則是每秒中斷的次數(shù)豁辉。
  • r(Running or Runnable)是就緒隊列的長度令野,也就是正在運行和等待 CPU 的進(jìn)程數(shù)。
  • b(Blocked)則是處于不可中斷睡眠狀態(tài)的進(jìn)程數(shù)徽级。
    上下文切換過多气破,體現(xiàn)在CPU使用率上是sys%升高。
  1. 進(jìn)程線程層面
    vmstat 只給出了系統(tǒng)總體的上下文切換情況餐抢,要想查看每個進(jìn)程的詳細(xì)情況现使,就需要使用我們前面提到過的 pidstat 了。給它加上 -w 選項旷痕,你就可以查看每個進(jìn)程上下文切換的情況了碳锈。加上-t選項,可以查看線程上下文切換情況欺抗。
# 每隔5秒輸出1組數(shù)據(jù)
$ pidstat -w 5
Linux 4.15.0 (ubuntu)  09/23/18  _x86_64_  (2 CPU)

08:18:26      UID       PID   cswch/s nvcswch/s  Command
08:18:31        0         1      0.20      0.00  systemd
08:18:31        0         8      5.40      0.00  rcu_sched
...
  • cswch 售碳,表示每秒自愿上下文切換(voluntary context switches)的次數(shù),自愿上下文切換绞呈,是指進(jìn)程無法獲取所需資源贸人,導(dǎo)致的上下文切換。比如說佃声, I/O艺智、內(nèi)存等系統(tǒng)資源不足時,就會發(fā)生自愿上下文切換圾亏。

  • 另一個則是 nvcswch 力惯,表示每秒非自愿上下文切換(non voluntary context switches)的次數(shù)碗誉。非自愿上下文切換,則是指進(jìn)程由于時間片已到等原因父晶,被系統(tǒng)強制調(diào)度哮缺,進(jìn)而發(fā)生的上下文切換。比如說甲喝,大量進(jìn)程都在爭搶 CPU 時尝苇,就容易發(fā)生非自愿上下文切換。

示例

構(gòu)造多線程應(yīng)用并啟動

  1. 查看系統(tǒng)cpu使用情況及上下文切換情況
# 每隔1秒輸出1組數(shù)據(jù)(需要Ctrl+C才結(jié)束)
$ vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 6  0      0 6487428 118240 1292772    0    0     0     0 9019 1398830 16 84  0  0  0
 8  0      0 6487428 118240 1292772    0    0     0     0 10191 1392312 16 84  0  0  0
  1. 查看CPU 和進(jìn)程上下文切換的情況

# 每隔1秒輸出1組數(shù)據(jù)(需要 Ctrl+C 才結(jié)束)
# -w參數(shù)表示輸出進(jìn)程切換指標(biāo)埠胖,而-u參數(shù)則表示輸出CPU使用指標(biāo)
$ pidstat -w -u 1
08:06:33      UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
08:06:34        0     10488   30.00  100.00    0.00    0.00  100.00     0  sysbench
08:06:34        0     26326    0.00    1.00    0.00    0.00    1.00     0  kworker/u4:2

08:06:33      UID       PID   cswch/s nvcswch/s  Command
08:06:34        0         8     11.00      0.00  rcu_sched
08:06:34        0        16      1.00      0.00  ksoftirqd/1
08:06:34        0       471      1.00      0.00  hv_balloon
08:06:34        0      1230      1.00      0.00  iscsid
08:06:34        0      4089      1.00      0.00  kworker/1:5
08:06:34        0      4333      1.00      0.00  kworker/0:3
08:06:34        0     10499      1.00    224.00  pidstat
08:06:34        0     26326    236.00      0.00  kworker/u4:2
08:06:34     1000     26784    223.00      0.00  sshd
  1. 查看線程上下文切換狀況
# 每隔1秒輸出一組數(shù)據(jù)(需要 Ctrl+C 才結(jié)束)
# -wt 參數(shù)表示輸出線程的上下文切換指標(biāo)
$ pidstat -wt 1
08:14:05      UID      TGID       TID   cswch/s nvcswch/s  Command
...
08:14:05        0     10551         -      6.00      0.00  sysbench
08:14:05        0         -     10551      6.00      0.00  |__sysbench
08:14:05        0         -     10552  18911.00 103740.00  |__sysbench
08:14:05        0         -     10553  18915.00 100955.00  |__sysbench
08:14:05        0         -     10554  18827.00 103954.00  |__sysbench
...
  1. 查看中斷狀況
# -d 參數(shù)表示高亮顯示變化的區(qū)域
$ watch -d cat /proc/interrupts
           CPU0       CPU1
...
RES:    2450431    5279697   Rescheduling interrupts
...

變化速度最快的是重調(diào)度中斷(RES)糠溜,這個中斷類型表示,喚醒空閑狀態(tài)的 CPU 來調(diào)度新的任務(wù)運行直撤。這是多處理器系統(tǒng)(SMP)中非竿,調(diào)度器用來分散任務(wù)到不同 CPU 的機制,通常也被稱為處理器間中斷(Inter-Processor Interrupts谋竖,IPI)红柱。所以,這里的中斷升高還是因為過多任務(wù)的調(diào)度問題蓖乘。

  1. 總結(jié)
    每秒上下文切換多少次才算正常呢锤悄?這個數(shù)值其實取決于系統(tǒng)本身的 CPU 性能。如果系統(tǒng)的上下文切換次數(shù)比較穩(wěn)定嘉抒,那么從數(shù)百到一萬以內(nèi)零聚,都應(yīng)該算是正常的。但當(dāng)上下文切換次數(shù)超過一萬次些侍,或者切換次數(shù)出現(xiàn)數(shù)量級的增長時隶症,就很可能已經(jīng)出現(xiàn)了性能問題。
    這時岗宣,還需要根據(jù)上下文切換的類型沿腰,再做具體分析。比方說:
  • 自愿上下文切換變多了狈定,說明進(jìn)程都在等待資源颂龙,有可能發(fā)生了 I/O 等其他問題;
  • 非自愿上下文切換變多了纽什,說明進(jìn)程都在被強制調(diào)度措嵌,也就是都在爭搶 CPU,說明 CPU 的確成了瓶頸芦缰;
  • 中斷次數(shù)變多了企巢,說明 CPU 被中斷處理程序占用,還需要通過查看 /proc/interrupts 文件來分析具體的中斷類型让蕾。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末浪规,一起剝皮案震驚了整個濱河市或听,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌笋婿,老刑警劉巖誉裆,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異缸濒,居然都是意外死亡足丢,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進(jìn)店門庇配,熙熙樓的掌柜王于貴愁眉苦臉地迎上來斩跌,“玉大人,你說我怎么就攤上這事捞慌∫唬” “怎么了?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵啸澡,是天一觀的道長袖订。 經(jīng)常有香客問我,道長锻霎,這世上最難降的妖魔是什么著角? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任揪漩,我火速辦了婚禮旋恼,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘奄容。我一直安慰自己冰更,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布昂勒。 她就那樣靜靜地躺著蜀细,像睡著了一般。 火紅的嫁衣襯著肌膚如雪戈盈。 梳的紋絲不亂的頭發(fā)上奠衔,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天,我揣著相機與錄音塘娶,去河邊找鬼归斤。 笑死,一個胖子當(dāng)著我的面吹牛刁岸,可吹牛的內(nèi)容都是我干的脏里。 我是一名探鬼主播,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼虹曙,長吁一口氣:“原來是場噩夢啊……” “哼迫横!你這毒婦竟也來了番舆?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤矾踱,失蹤者是張志新(化名)和其女友劉穎恨狈,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體介返,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡拴事,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了圣蝎。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片刃宵。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖徘公,靈堂內(nèi)的尸體忽然破棺而出牲证,到底是詐尸還是另有隱情,我是刑警寧澤关面,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布坦袍,位于F島的核電站,受9級特大地震影響等太,放射性物質(zhì)發(fā)生泄漏捂齐。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一缩抡、第九天 我趴在偏房一處隱蔽的房頂上張望奠宜。 院中可真熱鬧,春花似錦瞻想、人聲如沸压真。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽滴肿。三九已至,卻和暖如春佃迄,著一層夾襖步出監(jiān)牢的瞬間泼差,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工呵俏, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留堆缘,地道東北人。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓柴信,卻偏偏與公主長得像套啤,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,612評論 2 350

推薦閱讀更多精彩內(nèi)容