CPU上下文頻繁切換會導致系統性能下降,切換分為進程切換、線程切換及中斷切換,進程切換的開銷較大,除了需要保存寄存器和程式計數器中的值還需保存全局變數、棧等到記憶體中,以便下次運行恢復,而同一進程中的線程切換開銷會小很多,只需更新寄存器和線程獨有的棧,共用資源如打開的文件、全局變數等無需切換,當硬體中... ...
CPU上下文切換包括進程上下文切換、線程上下文切換及中斷上下文切換,當任務進行io或發生時間片事件及發生中斷(如硬體讀取完成)時,就會進入內核態,發生CPU上下文切換。
- 進程上下文切換,進程的上下文信息包括, 指向可執行文件的指針, 棧, 記憶體(數據段和堆), 進程狀態, 優先順序, 程式I/O的狀態, 授予許可權, 調度信息, 審計信息, 有關資源的信息(文件描述符和讀/寫指針), 關事件和信號的信息, 寄存器組(棧指針, 指令計數器)等等,當發生進程切換時,這些保存在寄存器或高速緩存的信息需要記錄到記憶體,以便下次恢復進程的運行。
- 線程上下文切換,同一個進程的線程切換,只需保存線程獨有的信息,比如棧和寄存器,而共用的虛擬記憶體和全局變數則無需切換,因此切換開銷比進程小。
- 中斷上下文切換,中斷會打斷一個正常執行的進程而運行中斷處理程式,因為中斷處理程式是內核態進程,而不涉及到用戶態進程之間的切換,當被中斷的是用戶態進程時,不需保存和恢復這個進程的虛擬記憶體和全局變數,中斷上下文只包括中斷服務程式所需要的狀態,比如CPU寄存器、內核堆棧、硬體中斷等參數。
過多的上下文切換會導致將大量CPU時間浪費在寄存器、內核棧以及虛擬記憶體的保存和恢覆上,導致系統整體性能下降。可以用vmstat查看系統的整體上下文切換情況,如下圖1,空閑系統的上下文切換次數cs(context switch)為100多,中斷次數in(interrupt)為100多,在運行態r(running or runable)的進程數為2,在阻塞態的進程數b為0。
圖1 空閑系統上下文切換和中斷情況
案例:我們用sysbench來模擬多線程頻繁上下文切換的場景,並用vmstat、pidstat和/proc/interrupts來分析定位具體的線程。
用sysbench模擬10個線程,運行300s來觀察線程切換的頻繁場景,如下圖2所示。
圖2 大量線程切換場景模擬
用vmstat查看系統整體的上下文切換和中斷情況,如下圖3,可看到cs和in的數目和空閑的時候比增加了很多。
圖3 系統整體上下文切換情況
發現系統切換情況比較頻繁,可以用pidstat查看具體切換比較頻繁的線程,命令:pidstat -w -t 1,含義如下,
-w Report task switching activity (kernels 2.6.23 and later only). The following values may be displayed:
cswch/s
Total number of voluntary context switches the task made per second. A voluntary context switch occurs when a task blocks because it requires a resource that is unavailable.
每秒自願上下文切換次數,如等待io等。
nvcswch/s
Total number of non voluntary context switches the task made per second. A involuntary context switch takes place when a task executes for the duration of its time slice and then is
forced to relinquish the processor.
每秒非自願上下文切換次數,如時間片用完切換。
-t展示具體的線程情況。
結果如下圖4所示,可以看到,切換頻繁的線程是sysbench
圖4 線程切換情況