性能瓶頸--CPU(上下文切換)

CPU的性能瓶頸不僅僅是cpu負(fù)載枫甲。因?yàn)長inux的性能問題可能是牽一發(fā)而動全身的源武。
比如一個占用內(nèi)存較高的java程序,導(dǎo)致問題的根本原因是內(nèi)存不足想幻,但是反映最直觀的可能是cpu使用率很高粱栖。因?yàn)閖ava開啟了大量的線程進(jìn)行GC操作。進(jìn)而導(dǎo)致cpu使用率高脏毯,平均負(fù)載也隨之升高闹究。所以問題的關(guān)鍵還是追根溯源。再比如進(jìn)程在競爭CPU的時候并沒有真正的運(yùn)行食店,但是為什么還會導(dǎo)致系統(tǒng)平均負(fù)載升高渣淤,這就是上下文切換導(dǎo)致的了。

CPU上下文切換

Linux 是一個多任務(wù)的操作系統(tǒng)吉嫩,它支持遠(yuǎn)大于CPU數(shù)量的任務(wù)同時運(yùn)行价认,當(dāng)然并不是真正的同時運(yùn)行,是每個任務(wù)輪流執(zhí)行CPU分給他們的時間片自娩,讓人感覺是同時在運(yùn)行用踩。
每一個任務(wù)運(yùn)行前,CPU都需要知道任務(wù)從哪里加載,又從哪里運(yùn)行捶箱,也就是說智什,需要系統(tǒng)事先設(shè)置好CPU寄存器。
CPU寄存器包含指令寄存器(IR)和程序計數(shù)器(PC)丁屎。他們用來暫存指令荠锭,數(shù)據(jù)和地址,程序運(yùn)行的下一條指令地址晨川,這些都是任務(wù)運(yùn)行時的必要環(huán)境证九。因此也被稱作CPU上下文
上下文切換就是把前一個任務(wù)的CPU上下文保存起來,然后加載新任務(wù)的上下文到這些指令寄存器(IR)和程序寄存器(PC)等寄存器中共虑。這些被保存下來的上下文會存儲在操作系統(tǒng)的內(nèi)核中愧怜,等待任務(wù)重新調(diào)度執(zhí)行時再次加載進(jìn)來,這樣就能保證任務(wù)的原來狀態(tài)不受影響妈拌,讓任務(wù)看起來是連續(xù)運(yùn)行的拥坛。
根據(jù)場景不同,CPU的上下文切換又分為進(jìn)程上下文切換尘分,線程上下文切換以及中斷上下文切換猜惋。

進(jìn)程上下文切換

在介紹進(jìn)程上下文切換前,需要先了解進(jìn)程執(zhí)行過程中所涉及到的CPU上下文切換培愁,我們稱之為特權(quán)模式切換著摔。
Linux 按照特權(quán)等級,將進(jìn)程的運(yùn)行空間分為內(nèi)核空間和用戶空間定续。對應(yīng)的是CPU的環(huán)0(Ring 0) 和 環(huán)3(Ring3)谍咆。(環(huán)2和環(huán)1,Linux沒用到)

  • 內(nèi)核空間(Ring0)具有最高權(quán)限私股,可以訪問所有資源摹察。
  • 用戶空間(Ring3)只能訪問受限資源,想要訪問物理設(shè)備需要陷入內(nèi)核態(tài)中庇茫,在內(nèi)核空間(Ring3)中港粱,才可以訪問特權(quán)資源。

那么從用戶態(tài)到內(nèi)核態(tài)的轉(zhuǎn)變就發(fā)生一次特權(quán)模式切換旦签,如從磁盤上讀取一個文件,就發(fā)生了一次內(nèi)核調(diào)用寸宏,也就發(fā)生一次特權(quán)模式切換宁炫。CPU需要將寄存器中的用戶態(tài)的指令位置保存起來,截至執(zhí)行內(nèi)核態(tài)的代碼氮凝,CPU寄存器需要更新為內(nèi)核態(tài)的新位置羔巢,最后跳轉(zhuǎn)到內(nèi)核態(tài)執(zhí)行內(nèi)核調(diào)用。之后再恢復(fù)之前的用戶態(tài)。這樣的一次系統(tǒng)調(diào)用過程實(shí)際上發(fā)生了兩次CPU上下文切換竿秆。
那這就是進(jìn)程上下文切換嗎启摄?不是的,進(jìn)程上下文切換只是說一個進(jìn)程切換到另一個進(jìn)程上去幽钢。
那特權(quán)模式切換和進(jìn)程上下文切換有什么區(qū)別嗎歉备?
首先進(jìn)程的管理是有內(nèi)核進(jìn)行管理和調(diào)度的。進(jìn)程的切換只能發(fā)生在內(nèi)核態(tài)匪燕,所以蕾羊,進(jìn)程的上下文切換不僅僅包括了虛擬內(nèi)存,棧帽驯,全局變量等用戶空間資源龟再,還包括了內(nèi)核態(tài)堆棧,寄存器等內(nèi)核空間狀態(tài)尼变。
特別需要注意的是操作系統(tǒng)會將當(dāng)前任務(wù)的虛擬內(nèi)存一并保存利凑。而Linux中通過TLB來管理虛擬內(nèi)存到物理內(nèi)存的映射關(guān)系。TLB用于虛擬地址與實(shí)地址之間的交互嫌术,提供一個尋找實(shí)地址的緩存區(qū)截碴,能夠有效減少尋找物理地址所消耗時間。當(dāng)虛擬內(nèi)存被刷新后蛉威,TLB也會被更新日丹。如果沒有TLB,則每次取數(shù)據(jù)都需要兩次訪問內(nèi)存蚯嫌,即查頁表獲得物理地址和取數(shù)據(jù)哲虾。在多核的技術(shù)下,這會極大的降低程序的執(zhí)行效率择示。因?yàn)榫彺鍸3 Cache 是被所有核共享的束凑。當(dāng)TLB被更新后,緩存中的TLB數(shù)據(jù)會失效栅盲,每個CPU都需要從主存中重新載入汪诉,一個進(jìn)程的上下文切換,同時可能影響其他CPU核心上的進(jìn)程的執(zhí)行效率谈秫。

TLB 三級緩存.png

當(dāng)需要進(jìn)程調(diào)度的時候扒寄,會需要切換上下文,Linux為每個CPU維護(hù)一個就緒隊(duì)列拟烫,將活躍的進(jìn)程按照優(yōu)先級和等待CPU的時間排序该编,然后選擇需要CPU的進(jìn)程(優(yōu)先級高或者等待時間最長的進(jìn)程)來運(yùn)行。
什么時候會發(fā)生進(jìn)程調(diào)度硕淑?

  • 進(jìn)程的CPU時間片耗盡课竣,被系統(tǒng)掛起嘉赎,切換到其他等待CPU的進(jìn)程運(yùn)行。
  • 進(jìn)程所需要的系統(tǒng)資源不足于樟。要等待資源滿足后才可以運(yùn)行公条。這個時候會被系統(tǒng)掛起。
  • 進(jìn)程通過sleep函數(shù)主動將自己掛起迂曲。
  • 當(dāng)有優(yōu)先級更高的進(jìn)程運(yùn)行時靶橱,當(dāng)前進(jìn)程會被掛起,由高優(yōu)先級的進(jìn)程運(yùn)行奢米。
  • 硬中斷發(fā)生時抓韩,CPU上的進(jìn)程會被掛起,轉(zhuǎn)而執(zhí)行內(nèi)核的中斷服務(wù)程序鬓长。

線程上下文切換

線程的上下文切換就十分的簡單了谒拴,線程是調(diào)度的基本單位,而進(jìn)程是資源擁有的基本單位涉波。

  • 當(dāng)進(jìn)程只有一個線程時英上,進(jìn)程可理解就是線程。
  • 當(dāng)進(jìn)程擁有多個線程時啤覆,線程會共享虛擬內(nèi)存和全局變量等資源苍日,這些資源在上下文切換中不需要修改。
  • 線程的上下文切換也需要保存自己的一些數(shù)據(jù)窗声,比如棧相恃,寄存器。這些在上下文切換時是需要保存的笨觅。
    也就是當(dāng)
    1拦耐、兩個不同進(jìn)程的線程上下文切換時,此時的切換構(gòu)成和進(jìn)程上下文切換一樣见剩。
    2杀糯、兩個線程處于同一進(jìn)程時,切換只需要切換棧苍苞,寄存器等少部分資源固翰。

中斷上下文切換

中斷時為了快速響應(yīng)硬件事件的,跟進(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ù)。

查看系統(tǒng)的上下文切換情況

既然過多的上下文切換會把CPU的時間消耗在上下文環(huán)境的保存上拳话,并沒有充分利用其計算功能先匪。那就需要查看當(dāng)前系統(tǒng)的上下文切換情況了。

vmstat

查看系統(tǒng)的上下文切換情況

$ 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
 1  0      0 2453028   2108 1211540    0    0     3    10   27   35  0  0 99  0  0
 0  0      0 2453004   2108 1211572    0    0     0     0   52   66  0  0 100  0  0

  • cs (centext switch) 每秒的上下文切換次數(shù)
  • in (interrupt) 每秒的中斷次數(shù)
  • r (Runing or Runnable) 就緒隊(duì)列的長度弃衍,也就是正在運(yùn)行和等待CPU的進(jìn)程數(shù)呀非。
  • b (Blocked) 不可中斷睡眠狀態(tài)的進(jìn)程數(shù)
pidstat

pidstat 可以看到具體的某個應(yīng)用程序的上下文切換情況。

$ pidstat -w 1
Linux 3.10.0-957.el7.x86_64 (localhost.localdomain)     2019年03月23日     _x86_64_    (2 CPU)

13時51分31秒   UID       PID   cswch/s nvcswch/s  Command
13時51分32秒     0         9      9.80      0.00  rcu_sched
13時51分32秒     0        11      0.98      0.00  watchdog/0
13時51分32秒     0        12      0.98      0.00  watchdog/1
13時51分32秒     0       481      0.98      0.00  kworker/1:3
13時51分32秒     0      4683     18.63      0.00  xfsaild/dm-0
13時51分32秒     0      9433      9.80      0.00  vmtoolsd
13時51分32秒     0     27261      0.98      0.00  kworker/u256:0
13時51分32秒     0     40878      2.94      0.00  kworker/0:1
13時51分32秒     0     40880      0.98      0.00  pidstat
  • cswch (voluntary context switches) 自愿上下文切換镜盯,指的是進(jìn)程無法獲得所需的資源導(dǎo)致的上下文切換岸裙。比如I/O不足,內(nèi)存不足速缆。
  • nvcswch (non voluntary context switches) 非自愿上下文切換降允,指的是 進(jìn)程由于時間片已到等原因,被系統(tǒng)強(qiáng)制調(diào)度艺糜,進(jìn)而發(fā)生上下文切換剧董。比如大量進(jìn)程在爭搶CPU

模擬上下文切換的場景

這里使用的sysbench,模擬操作系統(tǒng)的多線程調(diào)度瓶頸破停。以10個線程運(yùn)行5分鐘的基準(zhǔn)測試翅楼。模擬多線程切換

$  sysbench --threads=100 --max-time=300 threads run

觀察vmstat的輸出

 $ 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
17  0      0 2442576   2108 1217720    0    0     3    10   27   80  0  0 99  0  0
11  0      0 2442576   2108 1217720    0    0     0     0 23882 1325686 10 89  1  0  0
10  0      0 2442576   2108 1217720    0    0     0     0 22815 1348568 11 89  0  0  0
17  0      0 2442576   2108 1217720    0    0     0     0 23978 1328481 10 89  1  0  0
11  0      0 2442576   2108 1217720    0    0     0    25 23081 1344558 11 89  0  0  0
14  0      0 2442576   2108 1217720    0    0     0     0 23804 1305193 11 89  1  0  0
19  0      0 2442576   2108 1217720    0    0     0     0 22418 1254798 11 89  0  0  0

可觀察到 cs 瞬間上升(第一行是開機(jī)以來的參數(shù)的平均值)。
接下來觀察pidstat 真慢,這里需要加上 -t 參數(shù)毅臊,顯示線程,要不不帶參數(shù)黑界,看不到sysbench管嬉。

$ pidstat -u -w 1
平均時間:   UID       PID    %usr %system  %guest    %CPU   CPU  Command
平均時間:     0     42213    0.00    0.05    0.00    0.05     -  kworker/0:0
平均時間:     0     42218   19.82  100.00    0.00  100.00     -  sysbench
平均時間:     0     42321    0.33    1.00    0.00    1.33     -  pidstat

平均時間:   UID       PID   cswch/s nvcswch/s  Command
平均時間:     0         2      0.05      0.00  kthreadd
平均時間:     0         3      0.29      0.00  ksoftirqd/0
平均時間:     0         9      8.32      0.00  rcu_sched
平均時間:     0        11      0.24      0.00  watchdog/0
平均時間:     0        12      0.24      0.00  watchdog/1
平均時間:     0        14      0.90      0.00  ksoftirqd/1
平均時間:     0        37      0.10      0.00  khugepaged

加上-t后
可以看到 sysbench 發(fā)生了大量的自愿上下文切換

$ pidstat -wut 1
平均時間:     0     27261         -      1.85      0.00  kworker/u256:0
平均時間:     0         -     27261      1.85      0.00  |__kworker/u256:0
平均時間:   997         -     27300      1.85      0.00  |__grafana-server
平均時間:   997         -     27304      0.93      0.00  |__grafana-server
平均時間:   997         -     27307      1.85      0.00  |__grafana-server
平均時間:   997         -     27341      1.85      0.00  |__grafana-server
平均時間:     0         -     42219   2879.63  11057.41  |__sysbench
平均時間:     0         -     42220   1902.78  13955.56  |__sysbench
平均時間:     0         -     42221   4470.37  11027.78  |__sysbench
平均時間:     0         -     42222   1792.59  17249.07  |__sysbench
平均時間:     0         -     42223   2542.59   7395.37  |__sysbench
平均時間:     0         -     42224   1183.33  16775.93  |__sysbench
平均時間:     0         -     42225   3678.70  12963.89  |__sysbench
平均時間:     0         -     42226   3208.33  15801.85  |__sysbench
平均時間:     0         -     42227   2602.78  13896.30  |__sysbench

通過dstat命令可以看到,除了有很多的資源上下文切換园爷,還有很多中斷宠蚂。

$ dstat
You did not select any stats, using -cdngy by default.
----total-cpu-usage---- -dsk/total- -net/total- ---paging-- ---system--
usr sys idl wai hiq siq| read  writ| recv  send|  in   out | int   csw 
  1   2  97   0   0   0|5683B   19k|   0     0 |   0     0 | 583    30k
  8  85   7   0   0   0|   0     0 | 132B 1060B|   0     0 |  28k  977k
  8  82  10   0   0   0|   0     0 | 132B  620B|   0     0 |  25k 1025k

這是重調(diào)度中斷(RES),在喚醒空閑狀態(tài)的CPU來重新調(diào)度新任務(wù)運(yùn)行童社。具體可看 /proc/interrupts求厕。

小結(jié)

一般上下文切換在數(shù)百到一萬之內(nèi)上下文切換超過1萬,很可能遇到性能問題扰楼。需要具體看看了呀癣。

  • 資源上下文切換時說明進(jìn)程在等待資源,有可能發(fā)生了I/O等問題弦赖;
  • 非自愿上下文切換项栏,說明進(jìn)程在被強(qiáng)制調(diào)度,也就是在爭搶CPU蹬竖;
  • 中斷次數(shù)多了沼沈,說明CPU在被中斷處理程序占用流酬。可以通過/proc/interrupts 查看列另。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末芽腾,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子页衙,更是在濱河造成了極大的恐慌摊滔,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件店乐,死亡現(xiàn)場離奇詭異艰躺,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)眨八,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進(jìn)店門腺兴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人踪古,你說我怎么就攤上這事含长。” “怎么了伏穆?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵拘泞,是天一觀的道長。 經(jīng)常有香客問我枕扫,道長陪腌,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任烟瞧,我火速辦了婚禮诗鸭,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘参滴。我一直安慰自己强岸,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布砾赔。 她就那樣靜靜地躺著蝌箍,像睡著了一般。 火紅的嫁衣襯著肌膚如雪暴心。 梳的紋絲不亂的頭發(fā)上妓盲,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天,我揣著相機(jī)與錄音专普,去河邊找鬼悯衬。 笑死,一個胖子當(dāng)著我的面吹牛檀夹,可吹牛的內(nèi)容都是我干的筋粗。 我是一名探鬼主播策橘,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼亏狰!你這毒婦竟也來了役纹?” 一聲冷哼從身側(cè)響起偶摔,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤暇唾,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后辰斋,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體策州,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年宫仗,在試婚紗的時候發(fā)現(xiàn)自己被綠了够挂。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡藕夫,死狀恐怖孽糖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情毅贮,我是刑警寧澤办悟,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站滩褥,受9級特大地震影響病蛉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜瑰煎,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一铺然、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧酒甸,春花似錦魄健、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至饮六,卻和暖如春其垄,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背卤橄。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工绿满, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人窟扑。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓喇颁,卻偏偏與公主長得像漏健,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子橘霎,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評論 2 354

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