CPU性能篇
第一篇 如何理解平均負(fù)載
系統(tǒng)變慢首先想到的兩個命令top和uptime
uptime
02:34:03 up 2 days, 20:14, 1 user, load average: 0.63, 0.83, 0.88
//當(dāng)前時間、系統(tǒng)運行時間、當(dāng)前系統(tǒng)登錄用戶數(shù)、過去1分鐘、5分鐘、15分鐘平均負(fù)載
平均負(fù)載:簡單來說就是單位時間內(nèi)系統(tǒng)處于可運行狀態(tài)和不可中斷狀態(tài)的平均進(jìn)程數(shù),也就是平均活躍進(jìn)程數(shù)。
可運行狀態(tài) 處于Runable狀態(tài)的進(jìn)程,進(jìn)程狀態(tài)標(biāo)志為R
不可中斷狀態(tài) 一般是等待I/O的進(jìn)程,進(jìn)程狀態(tài)標(biāo)志位D
- 如果平均負(fù)載為2意味著什么呢?
- 在一個2核cpu上意味著所有cpu剛好都被占用
- 在一個4核cpu上意味著cpu有50%的空閑
- 在一個1核cpu上意味著有一半進(jìn)程競爭不到cpu
- 平均負(fù)載多少為合理?
平均負(fù)載理想的情況為cpu的核數(shù),查詢cpu核數(shù)通過top命令或者從/proc/cpuinfo中讀取。
[root@fengniaoweb proc]# grep 'model name' /proc/cpuinfo | wc -l
4
- 如果1、5、15分鐘都表現(xiàn)很平穩(wěn)說明系統(tǒng)很平穩(wěn)不存在過載
- 如果1、5、15分鐘負(fù)載是逐漸升高的就要引起注意了,尤其是超過70%的時候
平均負(fù)載與CPU使用率
CPU使用率是指單位時間內(nèi)CPU繁忙情況的統(tǒng)計,而平均負(fù)載還包含了不可中斷的進(jìn)程(實際并未使用CPU)
- CPU密集型進(jìn)程,平均負(fù)載一般與CPU使用率一致
- I/O密集型進(jìn)程,平均負(fù)載升高CPU使用率不一定會升高
- 大量等待調(diào)度的進(jìn)程也會讓平均負(fù)載和CPU使用率一起升高
工具篇
stress是一個linux系統(tǒng)壓力測試工具,可以用來模擬系統(tǒng)負(fù)載升高的場景
apt install stress #安裝
sysstat包含了linux常用的性能監(jiān)控分析工具
- mpstat是一個常用的多核cpu性能分析工具,用來實時查看cpu的性能,以及所有cpu的平均指標(biāo)
- pidstat是一個常用的進(jìn)程性能分析工具,用來實時查看系統(tǒng)的CPU、內(nèi)存、I/O以及上下文切換等多個指標(biāo)
第二篇 CPU的上下文切換
背景
Linux是個多任務(wù)操作系統(tǒng),在執(zhí)行遠(yuǎn)大于CPU核數(shù)的任務(wù)時,任務(wù)并不是同時進(jìn)行的,而是操作系統(tǒng)根據(jù)調(diào)度算法將CPU輪流分配給多個任務(wù)執(zhí)行。
由此任務(wù)從哪里開始加載,又從哪里開始執(zhí)行?
這就需要引入CPU 寄存器和程序計數(shù)器(Program Counter,PC)
CPU寄存器:CUP內(nèi)容量小速度極快的內(nèi)存
程序計數(shù)器:用于存儲正在執(zhí)行的指令位置或者即將執(zhí)行的下一條指令位置
CPU寄存器和程序計數(shù)器是CPU運行任何任務(wù)前必須依賴的環(huán)境因此也叫CPU上下文

理解CUP上下文切換
先把前一個任務(wù)的CPU上下文(也就是CPU寄存器和程序計數(shù)器)保存起來,然后加載新任務(wù)的上下文并跳轉(zhuǎn)到新任務(wù)程序計數(shù)器所指位置開始執(zhí)行新任務(wù)的過程。
Linux權(quán)限等級
- 內(nèi)核空間(Ring0)
? 擁有最高的權(quán)限等級,可以訪問系統(tǒng)內(nèi)所有資源
- 用戶空間(Ring3)
? 只能訪問受限資源,不能直接訪問硬件設(shè)備,需要通過系統(tǒng)調(diào)用才能間訪問特權(quán)設(shè)備

用戶態(tài)與內(nèi)核態(tài)
進(jìn)程既可能在用戶空間運行,此時稱作用戶態(tài),又可能在在內(nèi)核空間運行此時稱作內(nèi)核態(tài),進(jìn)程一旦發(fā)生系統(tǒng)調(diào)用就需要從用戶態(tài)切換到內(nèi)核態(tài),調(diào)用完成后又要從內(nèi)核態(tài)切換回用戶態(tài)。所以一次系統(tǒng)調(diào)用會至少發(fā)生兩次CPU上下文切換
系統(tǒng)調(diào)用發(fā)生的上下文切換實際上還是在同一個進(jìn)程內(nèi),所以不會涉及到虛擬內(nèi)存等進(jìn)程資源的切換,因此也叫特權(quán)模式切換注意與進(jìn)程上下文切換區(qū)分
CPU上下文切換類型
-
進(jìn)程的上下文切換
919-3.png ? 虛擬內(nèi)存、棧、全局變量等用戶態(tài)空間資源切換
? 內(nèi)核堆棧、寄存器等內(nèi)核態(tài)空間資源切換
線程的上下文切換
同一個進(jìn)程內(nèi)的線程切換,不需要切換虛擬內(nèi)存、全局變量等共享資源
跨進(jìn)程的線程切換,等同于進(jìn)程切換
線程私有的棧和寄存器數(shù)據(jù)也在切換時也需要考慮保存
中斷的上下文切換
中斷不涉及到用戶態(tài),因此中斷的上下文切換只包含CPU寄存器、內(nèi)核堆棧、中斷參數(shù)等
什么時候發(fā)生切換?CPU的執(zhí)行周期以時間片為單位,執(zhí)行完成后如果還有其他任務(wù)等待執(zhí)行,則自動讓出時間片由操作系統(tǒng)從任務(wù)隊列中選擇最靠前的任務(wù)執(zhí)行
進(jìn)程在等待系統(tǒng)資源(如內(nèi)存、IO等)時,任務(wù)被掛起,操作系統(tǒng)調(diào)度其他任務(wù)執(zhí)行
進(jìn)程調(diào)用系統(tǒng)休眠函數(shù)比如sleep時,任務(wù)被掛起,操作系統(tǒng)調(diào)度其他任務(wù)執(zhí)行
有更高優(yōu)先級任務(wù)到來,為保證高優(yōu)先級任務(wù)先執(zhí)行,當(dāng)前任務(wù)也會被掛起
發(fā)生硬件中斷時,任務(wù)被掛起,轉(zhuǎn)而執(zhí)行內(nèi)核中的中斷服務(wù)程序
怎么查看CPU上下文切換?
VMSTAT是一款常用的系統(tǒng)性能分析工具,主要用來分析系統(tǒng)的內(nèi)存使用情況、也常用來分析CPU上下文切換和中斷的次數(shù)。下面為使用示例:
# 每隔 5 秒輸出 1 組數(shù)據(jù)
$ 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
重點關(guān)注以下4列
cs(context switch)是每秒上下文切換的次數(shù)。
in(interrupt)則是每秒中斷的次數(shù)。
r(Running or Runnable)是就緒隊列的長度,也就是正在運行和等待CPU的進(jìn)程數(shù)。
b(Blocked)則是處于不可中斷睡眠狀態(tài)的進(jìn)程數(shù)。
VMSTAT只能給出系統(tǒng)總體的上下文切換情況,想要查看每個進(jìn)程的詳細(xì)切換情況,就要使用pidstat命令了,加上-w選項。
# 每隔 5 秒輸出 1 組數(shù)據(jù)
$ 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 ,表示每秒自愿上下文切換(voluntary context switches)的次數(shù)
nvcswch ,表示每秒非自愿上下文切換(non voluntary context switches)的次數(shù)
自愿上下文切換指進(jìn)程無法獲取到資源導(dǎo)致的切換,如等待IO、內(nèi)存等系統(tǒng)資源時
非自愿上下文切換指大量進(jìn)程爭搶CPU時,由于時間片已到等原因,被迫發(fā)生的切換
pidstat使用舉例
# 每隔 1 秒輸出 1 組數(shù)據(jù)(需要 Ctrl+C 才結(jié)束)
# -w 參數(shù)表示輸出進(jìn)程切換指標(biāo),而 -u 參數(shù)則表示輸出 CPU 使用指標(biāo)
$ 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
# 每隔 1 秒輸出一組數(shù)據(jù)(需要 Ctrl+C 才結(jié)束)
# -wt 參數(shù)表示輸出線程的上下文切換指標(biāo)
$ 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
...
如何查看中斷次數(shù)?
因為中斷發(fā)生在內(nèi)核態(tài),所以不能通過pidstat查看,需要從/proc/interrupts 這個只讀文件中讀取。/proc 實際上是 Linux 的一個虛擬文件系統(tǒng),用于內(nèi)核空間與用戶空間之間的通信。/proc/interrupts就是這種通信機(jī)制的一部分,提供了一個只讀的中斷使用情況。
# -d 參數(shù)表示高亮顯示變化的區(qū)域
$ watch -d cat /proc/interrupts
CPU0 CPU1
...
RES: 2450431 5279697 Rescheduling interrupts
...
- 重調(diào)度中斷(RES)喚醒空閑狀態(tài)的CPU來調(diào)度新的任務(wù)運行
如何通過切換次數(shù)發(fā)現(xiàn)問題?
- 自愿上下文切換變多,說明都在等待資源,有可能發(fā)生了IO等其他問題
- 非自愿上下文切換變多,說明都在爭搶CPU資源,CPU成為了瓶頸
- 中斷次數(shù)變多了,說明CPU都被中斷處理程序占用,需要根據(jù)中斷類型具體分析原因
此為個人筆記,不涉及其他,僅做參考
