1. 程式人生 > >Linux效能優化-上下文切換

Linux效能優化-上下文切換

目錄

CPU上下文

程序上下文切換

執行緒上下文切換

中斷上下文切換

上下文切換的兩個指標

簡單案例


 

CPU上下文

CPU的平均負載升高,上下文切換是罪歸禍首
Linux支援遠大於CPU數量的任務同時執行,通過將時間分片造成同時執行的錯覺

每個任務執行前,需要設定好CPU暫存器和程式計數器Program Counter PC
CPU暫存器,是CPU內建的cache,儲存資料和指令
程式計數器,用來儲存CPU正在執行的指令位置,或者即將執行的下一條指令位置,他們都是CPU在執行任何任務
前,必須依賴的環境,因此被叫做 CPU上下文


CPU上下文切換,先把前一個任務的CPU上下文(暫存器和程式計數器)儲存起來,然後載入新任務的上下文到這些暫存器和程式計數器中,最後再跳轉到程式計數器所指的新位置,執行新任務
儲存的這些上下文,會儲存在系統核心中,並在任務重新排程執行時再次載入進來,這樣就能保證任務原來的狀態不受影響,讓任務看起來是連續的
根據任務的不同,CPU的上下文切換可以分為幾個不同的場景
1.程序上下文切換
2.執行緒上下文切換
3.中斷上下文切換

 

程序上下文切換

Linux 按照特權等級,把程序的執行空間分為核心空間和使用者空間,對應下圖
核心空間Ring 0 有最高許可權,可以直接訪問所有資源
使用者空間Ring 3 只能訪問受限資源,不能直接訪問記憶體等硬體裝置,必須通過系統呼叫陷入到核心
  中,才能訪問這些特權資源

程序既可以在使用者空間執行,又可以在核心空間中執行,程序在使用者空間執行時,稱為程序的使用者態
而陷入核心空間時,被成為程序的核心態
從使用者態到 核心態,需要通過系統呼叫來完成,比如呼叫open,read,write等

系統呼叫需要儲存CPU暫存器相關資訊,再更新為核心態指令的新位置,接著跳轉到核心態執行核心任務,等系統呼叫結束後
CPU暫存器再恢復到使用者態,切換到使用者空間
一次系統呼叫過程,發生了 兩次 CPU上下文切換
系統呼叫過程,不會涉及到虛擬記憶體等程序使用者態的資源,也不會切換程序
1.程序上下文切換,是指從一個程序切換到另一個程序執行
2.系統呼叫過程一直是在同一個程序中執行
所以系統呼叫也被稱為 特權模式切換,而不是上下文切換,但呼叫過程中CPU的上下文切換無法避免

程序的上下文切換比系統呼叫多了一步,需要儲存該程序的虛擬記憶體,棧等資訊,載入了下一程序的核心態之後,還需要重新整理程序的虛擬記憶體和使用者棧

程序上下文切換,需要核心在CPU上執行才能完成


Linux通過TLB Translation Lookaside Buffer,來管理虛擬記憶體到實體記憶體的對映管理,當虛擬記憶體更新後,TLB也要重新整理,記憶體的訪問也會變慢,如果是在多處理器上,快取是被多個處理器共享的,重新整理快取不僅會影響當前處理器的程序,還會影響共享快取的其他處理器的程序

系統為每個CPU都維護了一個就緒佇列,將活躍程序(正在執行和正在等待CPU的程序)按照優先順序和等待CPU的時間排序,然後選擇最需要CPU的程序,也就是優先順序最高和等待CPU時間最長的程序來執行
觸發程序切換的場景
1.CPU時間片到了就會切換
2.系統在資源不足(如記憶體不足)時,等到資源滿足後才可以允許,這個時候程序也會被掛起,系統會
  排程其他程序
3.當程序通過sleep函式將自己掛起,系統也會重新排程
4.有更高優先順序的程序執行時,當前程序會被掛起
5.當硬體發生中斷時,CPU上的程序會被中斷掛起

 

執行緒上下文切換

執行緒是排程的基本單位,而程序是資源擁有的基本單位
核心中任務排程,實際上排程的物件是執行緒
程序只是給執行緒提供了虛擬記憶體,全域性變數等資源
1.當程序只有一個執行緒時,可以認為程序就等於執行緒
2.當程序擁有多個執行緒時,這些執行緒會共享相同的虛擬記憶體和全域性變數等資源,在上下文切換時不需要修改
3.執行緒私有資料,比如棧和暫存器等,這些在上下文切換的時候需要儲存

執行緒的上下文切換分為兩種情況
1.前後兩個執行緒屬於不同程序,此時資源不共享,切換過程中就跟程序上下文切換是一樣的
2.前後兩個執行緒屬於同一個程序,此時虛擬記憶體是共享的,在切換時,虛擬記憶體這些資源就保持不動,只要切換
  執行緒私有資料,暫存器等不共享的資料

 

中斷上下文切換

中斷會打斷程序的政策排程和執行,轉而呼叫中斷處理程式,響應裝置事件,而在打斷其他程序時,就需要將程序當前的狀態儲存下來,這樣再中斷結束後,程序仍然可以從原來的狀態恢復執行
中斷上下文切換並不涉及到程序的使用者態,即便中斷過程打斷了一個正在處理使用者態的程序,也不需要儲存和恢復這個程序的虛擬記憶體,全域性變數等使用者態資源,中斷上下文,其實只包括核心態中斷服務程式執行鎖必須的狀態,包括CPU暫存器,核心堆疊,硬體中斷引數等

對同一個CPU來說,中斷處理比程序擁有更高的優先順序,所以中斷上下文切換並不會與程序上下文切換同時發生,同樣由於中斷會打斷正常程序的排程和執行,所以大部分中斷程式都短小精悍,以便快速執行結束
中斷上下文切換也會消耗CPU,切換次數過多會耗費大量CPU,降低系統整體效能

 

 

上下文切換的兩個指標

pidstat -w 輸出之後有兩個指標
一個是 cswch 表示每秒自願上下文切換(voluntary context switches)的次數,另一個是nvcswch 表示每秒非自願上下文切換(non voluntary context switches)的次數
這種模式會導致不同的效能問題
1.自願上下文切換,是指程序無法獲得所需自願,導致上下文切換,比如I/O,記憶體等系統資源不足時,就會
  發生自願上下文切換
2.非自願上下文切換,是指程序由於時間片已經到等原因,被系統強制排程,進而發生的上下文切換,比如
  大量程序都在爭搶CPU時,就容易發生非自願上下文切換

//目前的場景是線上伺服器有大量的網路I/O,檢視bond0 這個程序的結果
//機器是萬M網絡卡,通過dstat -n 的結果為
-net/total-
 recv  send
   0     0 
 292M  176M
 291M  179M
 285M  175M
 291M  176M
 308M  191M
 284M  180M
 309M  191M

//bound0 這個程序的 上下文切換情況
pidstat -p 3246 -w  1
12:35:35 PM       PID   cswch/s nvcswch/s  Command
12:35:36 PM      3246     10.00      0.00  bond0
12:35:37 PM      3246     10.00      0.00  bond0
12:35:38 PM      3246     10.00      0.00  bond0
12:35:39 PM      3246     10.00      0.00  bond0
12:35:40 PM      3246     10.00      0.00  bond0
12:35:41 PM      3246     10.00      0.00  bond0
12:35:42 PM      3246     10.00      0.00  bond0

 

 

簡單案例

用壓測工具模擬上下文切換場景,安裝 sysbench 壓測工具

//壓測
sysbench --threads=10 --max-time=300 threads run

//通過 vmstat,或者 dstat,可以發現 中斷和上下文切換瞬間變高了

//每兩秒顯示一次,-u表示cpu使用率
pidstat -w -u -2

//找到CPU使用率高的程序,然後 -w 看上下文切換情況,-u 看使用率, -t 看執行緒指標
pidstat -p 29938 -w -u -t 2 

01:04:32 PM   UID      TGID       TID    %usr %system  %guest    %CPU   CPU  Command
01:04:34 PM     0     29938         -   19.50   80.00    0.00   99.50     0  sysbench
01:04:34 PM     0         -     29938    0.00    0.00    0.00    0.00     0  |__sysbench
01:04:34 PM     0         -     29939    2.00    8.00    0.00   10.00     0  |__sysbench
01:04:34 PM     0         -     29940    2.00    8.00    0.00   10.00     0  |__sysbench
01:04:34 PM     0         -     29941    2.00    8.50    0.00   10.50     0  |__sysbench
01:04:34 PM     0         -     29942    2.00    8.00    0.00   10.00     0  |__sysbench
01:04:34 PM     0         -     29943    2.00    8.00    0.00   10.00     0  |__sysbench
01:04:34 PM     0         -     29944    2.50    8.00    0.00   10.50     0  |__sysbench
01:04:34 PM     0         -     29945    1.50    8.00    0.00    9.50     0  |__sysbench
01:04:34 PM     0         -     29946    1.50    8.00    0.00    9.50     0  |__sysbench
01:04:34 PM     0         -     29947    2.00    8.00    0.00   10.00     0  |__sysbench
01:04:34 PM     0         -     29948    2.50    7.50    0.00   10.00     0  |__sysbench

01:04:32 PM   UID      TGID       TID   cswch/s nvcswch/s  Command
01:04:34 PM     0     29938         -      0.00      0.00  sysbench
01:04:34 PM     0         -     29938      0.00      0.00  |__sysbench
01:04:34 PM     0         -     29939  14419.00 108190.50  |__sysbench
01:04:34 PM     0         -     29940  14475.00 110001.00  |__sysbench
01:04:34 PM     0         -     29941  14524.50 110557.00  |__sysbench
01:04:34 PM     0         -     29942  13536.50 107055.50  |__sysbench
01:04:34 PM     0         -     29943  12553.50 111592.00  |__sysbench
01:04:34 PM     0         -     29944  10616.50 112754.00  |__sysbench
01:04:34 PM     0         -     29945  19468.00  97932.50  |__sysbench
01:04:34 PM     0         -     29946  13479.50 110462.00  |__sysbench
01:04:34 PM     0         -     29947  16443.00 100000.00  |__sysbench
01:04:34 PM     0         -     29948  19969.50  97967.50  |__sysbench

找到了sysbench這個程序是上下文切換的元凶
除了大量的上下文切換,還有很多中斷
通過 /proc/interrupts 這個只讀檔案分析
/proc是 linux的一個虛擬檔案系統,用於核心空間與使用者空間之間的通訊,/proc/interrupts 就是這種通訊機制的一部分,提供了一個只讀的中斷使用情況
通過 watch -d cat /proc/interrupts  檢視

watch -d cat interrupts  
.....
NMI:          0   Non-maskable interrupts
LOC:   95780367   Local timer interrupts
SPU:          0   Spurious interrupts
PMI:          0   Performance monitoring interrupts
IWI:    1503219   IRQ work interrupts
RTR:          0   APIC ICR read retries
RES:          0   Rescheduling interrupts
CAL:          0   Function call interrupts
TLB:          0   TLB shootdowns
TRM:          0   Thermal event interrupts
THR:          0   Threshold APIC interrupts
DFR:          0   Deferred Error APIC interrupts
MCE:          0   Machine check exceptions
MCP:       2019   Machine check polls
ERR:          0
MIS:          0
PIN:          0   Posted-interrupt notification event
PIW:          0   Posted-interrupt wakeup event


我的是單CPU機器,變化最大的是
LOC:   95780367   Local timer interrupts   這一段

對於多CPU機器,可能變化最大的是RES 重排程中斷,這個中斷型別表示,喚醒空閒狀態的CPU來排程新的任務執行,這是多處理器系統SMP中,排程器用來分散任務到不同CPU的機制,也被稱為 處理器間中斷 Inter-Processor Interrupts IP
所以,這裡的中斷升高還是因為過多工的排程問題,跟前面上下文切換次數分析的結果是一致的


上下文切換數量沒有一個具體的值,取決於系統本身的CPU效能,如果系統的上下文切換次數比較穩定,那麼數量從數百 -- 一萬以內都是正常的, 但超過一萬,或者切換次數出現數量級的增長,就很可能出現效能問題了