中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何理解Linux的CPU上下文切換

發布時間:2021-11-01 10:36:20 來源:億速云 閱讀:110 作者:柒染 欄目:系統運維

今天就跟大家聊聊有關如何理解Linux的CPU上下文切換,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,希望大家根據這篇文章可以有所收獲。

如何理解Linux的上下文切換

  • Linux 是一個多任務操作系統,它支持同時運行的任務數量遠大于 CPU 個數。其實這些任務沒有真正的同時運行,是因為系統在很短的時間內,將 CPU  輪流分配給它們,造成多任務同時運行的錯覺。

  • 而在每個任務運行前,CPU 都需要知道任務從哪里加載、從哪里開始運行,需要系統事先設置好 CPU 寄存器和程序計數器。CPU 寄存器是 CPU  內置的容量小、速度極快的內存。而程序計數器則是用來存儲 CPU 正在執行的指令位置、或即將執行的下一條指令位置。它們都是 CPU  在運行任務前必須依賴的環境,也被叫做 CPU 上下文。

  • 上下文切換,就是先把前一個任務的 CPU  上下文保存起來,然后加載新任務的上下文到這些寄存器和程序計數器,最后再跳到程序計數器所指的新位置,運行新任務。而這些保存下來的上下文,會存儲在系統內核中,并在任務重新調度執行時再次加載進來。這樣就能保證任務原來的狀態不受影響,讓任務看起來還是連續運行。

根據任務的不同,CPU 的上下文切換可以分為幾個不同的場景,也就是:進程上下文切換、線程上下文切換、中斷上下文切換。

如何理解Linux的CPU上下文切換

進程上下文切換

1. 用戶空間與內核空間

Linux 按照特權等級,把進程的運行空間分為內核空間和用戶空間,分別對應著 CPU 特權等級的 Ring 0 和 Ring 3。

  • 內核空間(Ring 0)具有最高權限,可以直接訪問所有資源。

  • 用戶空間(Ring 3)只能訪問受限資源,不能直接訪問內存等硬件設備,必須通過系統調用陷入內核中才能訪問這些特權資源。

  • 進程既可以在用戶空間運行,又可以在內核空間運行。在用戶空間運行時被稱為進程的用戶態,而陷入內核空間的時候,被稱為進程的內核態。

2. 系統調用

從用戶態到內核態的轉變,需要通過系統調用來完成。比如查看文件時,需要執行多次系統調用:open、read、write、close等。系統調用的過程如下:

  • 首先,把 CPU 寄存器里原來用戶態的指令位置保存起來

  • 為了執行內核代碼,CPU 寄存器需要更新為內核態指令的新位置,最后跳轉到內核態運行內核任務。

  • 系統調用結束后,CPU 寄存器需要恢復原來保存的用戶態,然后再切換到用戶空間,繼續運行進程

  • 所以,一次系統調用的過程,其實是發生了兩次 CPU 上下文切換。

但系統調用的過程中并不會涉及虛擬內存等進程用戶態的資源,也不會切換進程,這和平時說的進程上下文切換是不一樣的:

  • 進程上下文切換,是指從一個進程切換到另一個進程運行

  • 系統調用過程中一直是同一個進程在運行

因此,系統調用的過程通常稱為特權模式切換,而不是上下文切換。

3. 進程上下文切換

進程是由內核來管理和調度的,進程的切換只能發生在內核態,因此進程的上下文不僅包括了虛擬內存、棧、全局變量等用戶空間的資源,還包括了內核堆棧、寄存器等內核空間的狀態。

因此進程的上下文切換就比系統調用時多了一步:在保存當前進程的內核狀態和 CPU  寄存器之前,需先把該進程的虛擬內存、棧等保存下來;而加載了下一進程的內核態后,還需要刷新進程的虛擬內存和用戶棧。

保存上下文和恢復上下文的過程并不是免費的,需要內核在 CPU 上運行才能完成。據測試,每次上下文切換都需要幾十納秒到數微妙的 CPU  時間。特別是在進程上下文切換次數較多的情況下,很容易導致 CPU  將大量時間消耗在寄存器、內核棧、虛擬內存等資源的保存和恢復上,從而大大縮短了真正運行進程的時間。

Linux 通過 TLB 來管理虛擬內存到物理內存的映射關系。當虛擬內存更新后,TLB  也需要刷新,內存的訪問也會隨之變慢。特別是多處理器系統上,緩存是被多個處理器共享的,刷新緩存不僅會影響當前處理器的進程,還會影響共享緩存的其它處理器的進程。

4. 進程上下文何時切換

Linux 為每個 CPU 維護了一個就緒隊列,將活躍進程按照優先級和等待 CPU 的時間排序,然后選擇最需要 CPU 的進程,也就是優先級最高和等待  CPU 時間最長的進程來運行。那么,進程在什么時候才會被調度到 CPU 上運行呢?

  • 進程執行完終止了,它之前使用的 CPU 會釋放出來,這時再從就緒隊列中拿一個新的進程來運行

  • 為了保證所有進程可以得到公平調度,CPU 時間被劃分為一段段的時間片,這些時間片被輪流分配給各個進程。當某個進程時間片耗盡了就會被系統掛起,切換到其它等待  CPU 的進程運行。

  • 進程在系統資源不足時,要等待資源滿足后才可以運行,這時進程也會被掛起,并由系統調度其它進程運行。

  • 當進程通過睡眠函數 sleep 主動掛起時,也會重新調度。

  • 當有優先級更高的進程運行時,為了保證高優先級進程的運行,當前進程會被掛起,由高優先級進程來運行。

  • 發生硬件中斷時,CPU 上的進程會被中斷掛起,轉而執行內核中的中斷服務程序。

線程上下文切換

線程與進程最大的區別在于,線程是操作系統調度的最小單位,而進程是操作系統分配資源的最小單位。所謂內核調度,實際上的調度對象是線程,而進程只是給線程提供了虛擬內存、全局變量等資源。對于線程和進程我們可以這么理解:

  • 當進程只有一個線程時,可以認為進程就等于線程

  • 當進程擁有多個線程時,這些線程會共享相同的虛擬內存和全局變量等資源。這些資源在上下文切換時是不需要修改的。

  • 另外線程也有自己的私有數據,比如棧和寄存器等,這些在上下文切換時也時需要保存的。

其實線程的上下文切換可以分為兩種情況:

  • 前后兩個線程屬于不同進程。此時因為資源不共享,所以切換過程就跟進程上下文切換是一樣的。

  • 前后兩個線程屬于同一個進程。此時虛擬內存是共享的,上下文切換時,虛擬內存這些資源保持不動,只需要切換線程的私有數、寄存器等不共享的數據。

可以發現同進程內的線程切換,要比多進程間的切換消耗更少的資源,這也正是多線程代替多進程的一個優勢。

中斷上下文切換

為了快速響應硬件的事件,中斷處理會打斷進程的正常調度和執行,轉而調用中斷處理程序,響應設備事件。而在打斷其它進程時,就需要將進程當前的狀態保存下來,這樣在中斷結束后,進程仍然可以從原來的狀態恢復運行。

  • 跟進程上下文不同,中斷上下文切換并不涉及到進程的用戶態。所以即便中斷過程打斷了一個正在用戶態的進程,也不需要保存和恢復這個進程的虛擬內存、全局變量等用戶態資源。中斷上下文其實只包括內核態中斷服務程序執行所必需的狀態,包括  CPU 寄存器、內核堆棧、硬件中斷參數等。

  • 對同一個 CPU  來說,中斷處理比進程擁有更高的優先級,由于中斷會打斷正常進程的調度和執行,所以大部分中斷處理程序都短小精悍,以便盡可能快的執行結束。

  • 跟進程上下文切換一樣,中斷上下文切換也需要消耗 CPU,當發現中斷次數過多時,就需要注意去排查它是否會給你的系統帶來嚴重的性能問題。

概念小結

總結一下,不管是哪種場景導致的上下文切換,你都應該知道:

  • CPU 上下文切換是保證 Linux 系統正常工作的核心功能之一,一般情況下我們無需特別關注。

  • 過多的上下文切換,會把 CPU 時間消耗在寄存器、內核棧、虛擬內存等數據的保存和恢復上,從而縮短進程真正運行的時間,導致系統的整體性能大幅下降。

如何查看系統的上下文切換

我們可以通過 vmstat 工具來查看系統的上下文切換情況。vmstat 主要用來分析系統內存使用情況,也常用來分析 CPU  上下文切換和中斷的次數。

# 每隔 5 秒輸出 1 組數據 $ 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) 是每秒上下文切換的次數。

  • in(interrupt) 是每秒中斷的次數。

  • r(Running or Runnable) 是就緒隊列的長度,也就是正在運行和等待 CPU 的進程數。

  • b(Blocked) 是處于不可中斷睡眠狀態的進程數。

想要查看每個進程的詳細情況,需要使用 pidstat,給它加上 -w 選項,就可以查看每個進程上下文切換的情況。

# 每隔 5 秒輸出 1 組數據 $ 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,表示每秒自愿上下文切換的次數;另一個是 nvcswch,表示每秒非自愿上下文切換的次數。

  • 自愿上下文切換,是指進程無法獲取所需資源,導致的上下文切換。比如,IO、內存等系統資源不足時,就會發生自愿上下文切換。

  • 非自愿上下文切換,則是指進程由于時間片已到等原因,被系統強制調度,進而發生的上下文切換。比如說,大量進程都在搶占 CPU  時,就容易發生非自愿上下文切換。

案例分析

1. 準備環境

sysbench  是一個多線程的基準測試工具,一般用來評估不同系統參數下的數據庫負載情況,本次案例把它當作一個異常進程來看,作用是模擬上下文切換過多的問題。

# 預先安裝 sysbench $ yum install sysbench -y

2. 操作和分析

首先在第一個終端里運行 sysbench,模擬系統多線程調度的瓶頸:

# 以 10 個線程運行 5 分鐘的基準測試,模擬多線程切換的問題 $ sysbench --threads=10 --max-time=300 threads run

接著在第二個終端運行 vmstat,觀察上下文切換情況:

# 每隔 1 秒輸出 1 組數據(需要 Ctrl+C 才結束) $ 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

可以發現,cs 列的上下文切換次數從之前的 35 上升到了 139 萬,觀察其他幾個指標:

  • r 列:就緒隊列長度為 8,遠大于 CPU 個數,所以會有大量的 CPU 競爭

  • us 和 sys 列:這兩列加一起上升到 100%,sys 列高達 84%,說明 CPU 主要是被內核占用了。

  • in 列:中斷次數為 1 萬左右,說明中斷也是個潛在的問題。

綜合分析,由于系統的就緒隊列過長,也就是正在運行和等待 CPU 的進程數過多,導致了大量的上下文切換,而上下文切換又導致了系統 CPU  的占用率升高。

我們可以使用 pidstat 繼續分析到底是哪個進程導致了這些問題?

# 每隔 1 秒輸出 1 組數據(需要 Ctrl+C 才結束) # -w 參數表示輸出進程切換指標,而 -u 參數則表示輸出 CPU 使用指標 $ 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

可以發現,CPU 使用率的升高是 sysbench 導致的,但上下文切換則來自其他進程,包括非自愿上下文切換頻率最高的  pidstat,以及自愿上下文切換頻率最高的內核線程 kworker 和 sshd。

默認 pidstat 顯示進程的指標數據,加上 -t 參數后,才會輸出線程的指標

# 每隔 1 秒輸出一組數據(需要 Ctrl+C 才結束) # -wt 參數表示輸出線程的上下文切換指標 $ 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 ...

雖然 sysbench 進程的上下文切換次數不多,但它的子線程的上下文切換次數非常多,可以判定上下文切換罪魁禍首的是 sysbench  進程。還沒完,記得我們通過 vmstat 看到的中斷次數到了 1 萬,到底是什么類型的中斷上升了呢?

我們可以通過 /proc/interrupts 來讀取中斷的使用情況,通過運行下面的命令:

# -d 參數表示高亮顯示變化的區域 $ watch -d cat /proc/interrupts            CPU0       CPU1 ... RES:    2450431    5279697   Rescheduling interrupts ...

可以發現,變化速度最快的是重調度中斷(RES),表示喚醒空閑狀態的 CPU 來調度新的任務運行。這是多處理器系統(SMP)中,調度器用來分散任務隊列到不同  CPU 的機制,通常也被稱為處理器間中斷。根本原因還是因為過多任務的調度問題,跟前邊分析結果是一致的。

每秒上下文切換多少次算正常

這個數值其實取決于系統本身的 CPU  性能。如果系統的上下文切換次數比較穩定,從數百到一萬以內,都應該算是正常的。如果當上下文切換次數超過一萬次,或者切換次數出現數量級增長時,很可能已經出現了性能問題。

這時,你還需要根據上下文切換的類型,再做具體分析,比方說:

  • 自愿上下文切換變多了,說明進程都在等待資源,有可能發生了 IO 等其他問題

  • 非自愿上下文切換變多了,說明進程都在被強制調度,也就是都在爭搶 CPU,說明 CPU 的確成了瓶頸。

  • 中斷次數變多了,說明 CPU 被中斷處理程序占用,還需要通過查看 /proc/interrupts 文件來分析具體的中斷類型。 

看完上述內容,你們對如何理解Linux的CPU上下文切換有進一步的了解嗎?如果還想了解更多知識或者相關內容,請關注億速云行業資訊頻道,感謝大家的支持。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

兰考县| 天全县| 元氏县| 左贡县| 邵武市| 渝中区| 南阳市| 凤台县| 鄱阳县| 大安市| 锦州市| 永寿县| 东至县| 桃园市| 东丰县| 柘荣县| 雷山县| 长宁县| 富阳市| 弥渡县| 东光县| 宁津县| 黄石市| 同江市| 新巴尔虎右旗| 礼泉县| 天峻县| 新河县| 乐陵市| 长岛县| 利川市| 凌云县| 随州市| 台东市| 新化县| 黄山市| 观塘区| 黄冈市| 礼泉县| 高淳县| 浦东新区|