Linux性能優化篇-瞭解CPU上下文切換

 

 

我們瞭解到導致平均負載,有可能是以下幾種方面:

  1. CPU密集型(造成cpu利用率升高,可以理解)
  2. I/O密集型(io和cpu互斥的,也造成cpu利用率增高-不可中斷進程的
  3. 大量進程(???)

根據平均負載的解釋,單位時間內的處於可運行的進程和不可中斷進程的進程數

System load averages is the average number of processes that are either in a runnable or uninterruptable state. A process in uninterruptable state is waiting for some I/O access, eg waiting for disk

所以我們會比較好了解CPU密集型,需要大量計算資源,會非常消耗cpu,I/O密集型需要等待I/O,會有大量的不可中斷進程,

那麼大量進程的情況下是如何導致平均負載升高的?

存在大量的進程競爭cpu,也就是存在大量的可運行進程,但是我們都知道cpu一個時間段其實只能運行一個進程,其他的進程也都只是在等待,並不會大量耗盡cpu資源的情況,而是cpu按照時間片給大量進程運行,所以可以想象在不停的切換不停的進程的情況下是不是也在消耗cpu資源能力,也就是我們今天要說的cpu上下文切換

Linux是一個多用戶用任務的操作系統,他支持遠遠大於cpu的進程數運行,而cpu每次卻只能運行一個任務,所以其實這些任務其實並不是在同時運行,整個過程是cpu輪流運行任務,給用戶帶來的假象。而當一個任務需要運行前,cpu需要知道從那裏加載,從哪裏開始運行,也就是系統需要事先設置好cpu寄存器和程序計數器。

  1. cpu寄存器: cpu內置的容量小,但是速度極快的內存。
  2. 程序計數器: 用來存儲cpu正在執行的指令位置,或者即將執行的下一條指令位置。

它們是CPU在運行任何任務前,必須依賴的,所以也被稱爲CPU上下文。

所以根據上下文的瞭解,所謂的上下文切換:

  1. 把前一個任務的CPU上下文保存下來
  2. 找到並加載新任務的上下文
  3. 切換到新的cpu寄存器和程序計數器最後跳到程序計數器所指的新位置,開始運行新任務。

保存下來的上下文會存儲在內核,並在任務重新調度時再加載進去,這樣任務不受影響,任務看起來來也是連續運行的。

根據任務的不同,CPU上下文切換可以分幾種不同場景:

  •  
  • 進程上下文切換
  • 線程上下文切換
  • 中斷上下文切換
  •  

進程上下文切換

Linux分爲內核空間和用戶空間:

 

所以根據內核空間劃分,一個進程可以被稱爲進程的用戶態和進程的內核態,

當一個系統調用發生市必然會發生CPU上下文切換的,

比如我們加載存在磁盤裏的一個文件,我們觸發的指令是進程的用戶態,而我們需要操作磁盤就需要系統調用陷入內核態,而我們原先的用戶態就需要保存起來,執行內核態的指令,加載完數據就需要恢復用戶態,繼續運行進程,

 

所以可以知道一次系統調用會發生兩次CPU上下文切換。

這裏說的系統調用和進程上下文切換又是不同的:

  1. 進程上下文切換是指從一個進程切換到另一個進程
  2. 系統調用始終在一個進程中運行

所以系統調用還是被稱爲特權模式調用,而不是上下文切換,但是系統調用導致的cpu上下文切換還是不可避免。

 

 

那麼進程的上下文切換和系統調用存在什麼關係?

進程是需要系統內核來管理和調度的,進程的上下文切換隻能發生在內核態,

所以進程的上下文不僅包括虛擬內存、棧、全局變量等用戶空間資源,還有內核堆棧、寄存器等內核空間狀態

所以進程的上下文切換和系統調用(軟中斷)多了一個保存用戶空間和恢復用戶空間。

進程上下文切換過程:

  1. 接受切換信號,掛起進程,記錄當前的進程的虛擬內存、棧等資源存儲
  2. 將這個進程在CPU的上下文狀態存儲
  3. 然後檢索下一個進程的CPU的上下文
  4. 加載到CPU的寄存器中恢復
  5. 還需要刷新進程保存的虛擬內存和用戶棧
  6. 最後跳轉到程序計數器所指向的位置,恢復進程運行

而保存上下文和恢復上下文過程不是免費的,大概每次上下文切換會花費幾十納秒到數微妙之間,當大量進程時,這個cpu上下文切換是相當可觀的,會花費大量時間在保存和恢復cpu上下文和用戶空間狀態,cpu分配給進程的時間片是一定的,導致cpu實際運行進程時間大大減少,而當時間片用完,進程必須掛起,這也是導致平均負載升高的一個因素。

什麼時候需要進行進程上下文切換?

Linux會爲每個cpu都維護一個就緒隊列,也就是進程狀態爲R狀態的的進程,最理想狀態是之前的進程完成,cpu得到釋放,下一個進程得到cpu使用,但是實際情況是不同的。

  1. 爲了保證所有進程得到公平調度,CPU時間被劃分一段段時間片,這些時間片輪流分給進程,當時間片耗盡,進程會被掛起,等待下一次分配cpu時間片。
  2. 進程運行的系統資源不足,比如內存不足,進程必須得倒資源滿足纔可以運行,這個時候會被掛起,系統會調度其他可運行的進程。
  3. 當進程通過睡眠函數主動掛起,會重新調度。
  4. 當有高優先級的進程運行時,爲保障高優先級運行,當前進程會被掛起,由高優先級進程運行。
  5. 發生硬件中斷,cpu上的進程會被掛起,而由內核中的中斷服務運行。

線程上下文切換

線程和進程的最大區別在於,線程是調度的基本單位,而進程則是資源擁有的基本單位,說白了,內核中的任務調度,調度的對象就是線程,而進程給線程提供虛擬內存、全局變量等資源。

進程與線程的比較:

  1. 當進程只有一個線程的時候,進程就等於線程
  2. 當進程由多個線程的時候,這些線程會共享相同的虛擬內存與全局變量等資源,這些在上下文切換的時候不需要修改
  3. 線程也是有私有數據的,這些數據在上下文切換的時候是需要保存的

所以這裏也可以看出,相對於比較多進程與多線程,

多線程間的切換會比多進程間的切換消耗更少的資源。

中斷上下文切換

  • 中斷
  1. 軟中斷可以觸發內核執行 We know that we can trigger the kernel to execute by generating a software interrupt.
  2. int 指令可以產生軟中斷

Kernel-side: int $0x80 entry point

 

爲了快速響應硬件事件,中斷處理會打斷進程的正常調度和執行,轉而執行調用中斷處理程序,響應設備事件。但是和進程的上下文不同的是,

中斷上下文切換不會涉及到進程的用戶態,只是需要內核態中斷程序執行必需的狀態,並且對於一個cpu來說,中斷處理比進程擁有更高的優先級。

怎麼查看系統上下文切換情況

過多的cpu上下文切換會導致花費大量的時間消耗在寄存器、內核棧及虛擬內存的保存與恢復中,縮短cpu在規定時間片內真正運行的時間,導致系統性能大幅下降。

vmstat可以用來分析系統內存使用情況,也可以用來分析cpu上下文切換和中斷的次數。


 
  1. r: Running or Runnable Task 是就緒隊列的長度,也就是正在運行和等待CPU的進程數
  2. b: Blocked Task 處於不可中斷睡眠狀態的進程數
  3. cs: Context switch 是每秒上下文切換的次數
  4. in: Interrupt 則是每秒中斷的次數

vmstat可以給出總體的上下文切換情況,如果想要查看每個進程的詳細情況,

需要pidstat來查看:


 
  1. cswch: 表示每秒自願上下文切換的次數
  2. nvcswch: 表示每秒非自願上下文切換

這兩種概念意味着不同的性能問題:

  • 自願上下文切換,是指進程無法獲取所需資源,導致的上下文切換,如I/O,內存不足等問題,就會發生大量的自願上下文切換。
  • 非自願上下文切換,是指進程由於時間片已到,被系統強制調度,而發生的上下文切換,比如大量進程爭搶cpu,會發生大量非自願上下文切換。

上下文切換頻率多少纔算合適

使用sysbench模擬多線程調度瓶頸:


 

查看vmstat:


 

cs(上下文切換)突然增大到300多萬,同時觀測到r增大到9,遠遠超過了操作系統的2核,us(user)和sy(system)這兩列cpu的使用率開始突增,cpu主要被內核空間佔有,in列也開始增加一倍,說明中斷也是一個原因。

我們從vmstat大體可以看出cpu上下文切換和中斷,並且存在多個進程競爭情況,內核空間異常繁忙,接下來我們需要分析原因,需要繼續分析:


 

很明顯看出來cpu使用率升高是sysbench導致的,而上下文切換則是其他進程,包括非自願上下文切換最高的pidstat,但是我們會發現自願上下文切換比vmstat來說的300多萬來說小太多了,我們需要考慮線程問題。


 

還有我們要如何查看中斷突然增大:

watch -d cat /proc/interrupts


 

Rescheduling interrupts are the Linux kernel's way to wake-up an idle CPU-core to schedule a thread on it. On SMP systems, this is often done by the scheduler in a effort to spread the load across multiple CPU-cores. 重新安排中斷是Linux內核喚醒空閒CPU核心以在其上安排線程的方法.在SMP系統上,這通常由調度程序完成,以便將負載分散到多個CPU核心 Function call interrupts:: software-interrupts to 軟中斷

所以回到上下文切換多少合適,這個數值還是取決於cpu性能,如果想要系統比較穩定,這個值可以儘量控制在幾百到一萬之間,如果超過一萬或者指數級增量,一般都是出現性能問題。

總結:

sysbench是一款開源的多線程性能測試工具,可以執行CPU/內存/線程/IO/數據庫等方面的性能測試

  • 自願上下文切換變多,說明進程在等待資源,可能I/O等其他問題
  • 非自願上下文切換變多,說明進程被強制調度,爭搶cpu,cpu是瓶頸
  • 中斷次數增多,說明cpu被中斷處理程序佔用,要通過/proc/interrupts文件來分析具體的中斷類

來源:極客

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章