聊聊 top 命令中的 CPU 使用率
之前寫過cpu占用率的文章
CPU占用率是什么?
====
平常我們使用?top?命令來查看系統的性能情況,在?top?命令中可以看到很多不同類型的 CPU 使用率,如下圖紅框中標出部分:
下面,我們來介紹一下這些 CPU 使用率的意義:
us:user time,表示 CPU 執行用戶進程的時間,包括 nice 時間。通常都是希望用戶空間CPU越高越好。
sy:system time,表示 CPU 在內核運行的時間,包括 IRQ 和 softirq。系統 CPU 占用越高,表明系統某部分存在瓶頸。通常這個值越低越好。
ni:nice time,具有優先級的用戶進程執行時占用的 CPU 利用率百分比。
id:idle time,表示系統處于空閑期,等待進程運行。
wa:waiting time,表示 CPU 在等待 IO 操作完成所花費的時間。系統不應該花費大量的時間來等待 IO 操作,否則就說明 IO 存在瓶頸。
hi:hard IRQ time,表示系統處理硬中斷所花費的時間。
si:soft IRQ time,表示系統處理軟中斷所花費的時間。
st:steal time,被強制等待(involuntary wait)虛擬 CPU 的時間,此時 Hypervisor 在為另一個虛擬處理器服務。
當然,單靠上面的解釋來理解它們的意義還是比較困難的。所以,本文主要從源碼的角度來分析它們到底代表什么。
時鐘中斷
首先,我們要知道統計 CPU 使用情況在什么地方執行的。在分析之前,我們先來了解下?時鐘中斷:
時鐘中斷:是一種硬中斷,由時間硬件(系統定時器,一種可編程硬件)產生。當 CPU 接收到時鐘中斷信號后,會在處理完當前指令后調用?時鐘中斷處理程序?來完成更新系統時間、執行周期性任務等。
可以發現,統計 CPU 使用情況是在?時鐘中斷處理程序?中完成的。
每個 CPU 的使用情況通過?cpu_usage_stat?結構來記錄,我們來看看其定義:
struct?cpu_usage_stat?{cputime64_t?user;cputime64_t?nice;cputime64_t?system;cputime64_t?softirq;cputime64_t?irq;cputime64_t?idle;cputime64_t?iowait;cputime64_t?steal;cputime64_t?guest; };從?cpu_usage_stat?結構的定義可以看出,其每個字段與?top?命令的 CPU 使用率類型一一對應。在內核初始化時,會為每個 CPU 創建一個?cpu_usage_stat?結構,用于統計 CPU 的使用情況。
OK,現在我們來分析下內核是怎么統計 CPU 的使用情況的。
每次執行?時鐘中斷處理程序?都會調用?account_process_tick?函數進行 CPU 使用情況統計,我們來分析一下?account_process_tick?函數的實現:
void?account_process_tick(struct?task_struct?*p,?int?user_tick) {cputime_t?one_jiffy_scaled?=?cputime_to_scaled(cputime_one_jiffy);struct?rq?*rq?=?this_rq();//?說明:user_tick 變量標識當前是否處于執行用戶應用程序if?(user_tick)?{//?1.?如果?CPU?在執行用戶程序,?那么調用?account_user_time?進行統計account_user_time(p,?cputime_one_jiffy,?one_jiffy_scaled);}?else?if?((p?!=?rq->idle)?||?(irq_count()?!=?HARDIRQ_OFFSET))?{//?2.?如果?CPU?在執行內核代碼,?那么調用?account_system_time?進行統計account_system_time(p,?HARDIRQ_OFFSET,?cputime_one_jiffy,one_jiffy_scaled);}?else?{//?3.?否則說明?CPU?在執行?idle?進程(也就是處于空閑狀態),?那么調用?account_idle_time?進行統計account_idle_time(cputime_one_jiffy);} }account_process_tick?函數主要分 3 種情況進行統計,如下:
如果 CPU 在執行用戶程序,那么調用?account_user_time?進行統計。
如果 CPU 在執行內核代碼,那么調用?account_system_time?進行統計。
否則說明 CPU 在執行 idle 進程(也就是處于空閑狀態),那么調用?account_idle_time?進行統計。
CPU 使用情況統計
下面我們分別對這 3 種統計進行分析。
1. 統計用戶程序執行時間
統計用戶程序的執行時間是通過?account_user_time?函數來完成的,我們來看看其實現:
void?account_user_time(struct?task_struct?*p,?cputime_t?cputime,cputime_t?cputime_scaled) {//?獲取?CPU?的統計結構(每個CPU一個?cpu_usage_stat?結構)struct?cpu_usage_stat?*cpustat?=?&kstat_this_cpu.cpustat;?cputime64_t?tmp;...//?分?2?種情況統計?CPU?的使用情況//?1.?如果進程的?nice?值大于0,?那么將會統計到?nice?字段中//?2.?如果進程的?nice?值小于等于0,?那么將會統計到?user?字段中if?(TASK_NICE(p)?>?0)cpustat->nice?=?cputime64_add(cpustat->nice,?tmp);elsecpustat->user?=?cputime64_add(cpustat->user,?tmp);... }account_user_time?函數主要分兩種情況統計:
如果進程的?nice?值大于0,那么將會增加到 CPU 統計結構的?nice?字段中。
如果進程的?nice?值小于等于0,那么增加到 CPU 統計結構的?user?字段中。
這里說明一下進程?nice?值的作用,nice?值越大,說明進程的優先級越低。所以,nice?統計值主要用來統計低優先級進程的占使用 CPU 的情況。也說明了,user?和?nice?統計值都屬于執行用戶程序的 CPU 時間。
2. 統計內核代碼執行時間
如果在發生時鐘中斷前,CPU 處于內核態,也就是說在執行內核代碼。那么將會調用?account_system_time?函數進行統計,account_system_time?函數實現如下:
void?account_system_time(struct?task_struct?*p,?int?hardirq_offset,cputime_t?cputime,?cputime_t?cputime_scaled) {//?獲取?CPU?的統計結構(每個CPU一個?cpu_usage_stat?結構)struct?cpu_usage_stat?*cpustat?=?&kstat_this_cpu.cpustat;cputime64_t?tmp;...//?主要分?3?種情況進行統計//?1.?如果當前處于硬中斷執行上下文,?那么統計到?irq?字段中//?2.?如果當前處于軟中斷執行上下文,?那么統計到?softirq?字段中//?3.?否則統計到?system?字段中if?(hardirq_count()?-?hardirq_offset)cpustat->irq?=?cputime64_add(cpustat->irq,?tmp);else?if?(softirq_count())cpustat->softirq?=?cputime64_add(cpustat->softirq,?tmp);elsecpustat->system?=?cputime64_add(cpustat->system,?tmp);... }account_system_time?函數主要分 3 種情況進行統計:
如果當前處于硬中斷執行上下文,那么增加到 CPU 統計結構的?irq?字段中。
如果當前處于軟中斷執行上下文,那么增加到 CPU 統計結構的?softirq?字段中。
否則增加到 CPU 統計結構的?system?字段中。
從上面代碼可以看出,irq?和?softirq?統計值也算是內核代碼執行時間。
3. idle 進程執行時間統計
當系統中沒有可運行的進程時,將會執行?idle?進程。也就是說,當系統執行?idle?進程時,表示系統正處于空閑狀態。
idle?進程執行時間統計由?account_idle_time?函數完成,其實現如下:
void?account_idle_time(cputime_t?cputime) {struct?cpu_usage_stat?*cpustat?=?&kstat_this_cpu.cpustat;cputime64_t?cputime64?=?cputime_to_cputime64(cputime);struct?rq?*rq?=?this_rq();//?分?2?種情況統計?CPU?的使用情況//?1.?如果系統有進程正在等待?I/O?操作完成,?那么將統計到?iowait?字段中//?2.?否則將統計到?idle?字段中if?(atomic_read(&rq->nr_iowait)?>?0)cpustat->iowait?=?cputime64_add(cpustat->iowait,?cputime64);elsecpustat->idle?=?cputime64_add(cpustat->idle,?cputime64); }account_idle_time?函數也分兩種情況進行統計:
如果系統中有正在等待 I/O 操作完成的進程,那么增加到 CPU 統計結構的?iowait?字段中。
否則增加到 CPU 統計結構的?idle?字段中。
從上面的分析可以看出,iowait?統計值也屬于空閑時間的一種。
top 命令的 CPU 使用率
通過源碼分析,我們知道?top?命令中 CPU 使用率各種類型的意思,現在我們來介紹一下?top?命令是怎么計算各種類型的 CPU 使用率。
要獲取各個 CPU 的使用情況信息,可以通過讀取?/proc/stat?文件獲取,如下:
[vagrant@localhost?~]$?cat?/proc/stat cpu??245?10?1142?1097923?95?0?28?0?0?0 cpu0?245?10?1142?1097923?95?0?28?0?0?0 ...上面的結果顯示了 CPU 的使用情況信息,第一行代表所有 CPU 的總和,而第二行開始表示每個 CPU 核心的使用情況信息。因為我的電腦只有一個核,所以只有一條數據。
下面說說這些數據的意義,從第一個數值開始分別代表:user?,nice,system,idle,iowait,?irq,softirq,steal。
所以,top?命令的 CPU 使用率計算公式如下:
CPU總時間 = user + nice + system + idle + wait + irq + softirq + steal %us = user / CPU總時間 %ni = nice / CPU總時間 %sy = system / CPU總時間 %id = idel / CPU總時間 %wa = wait / CPU總時間 %hi = irq / CPU總時間 %si = softirq / CPU總時間 %st = steal / CPU總時間嗯,看起來還是挺簡單的。
總結
本文主要分析了?top?命令中的 CPU 使用率的意義和實現原理,希望通過本文,能夠幫助大家對?top?命令有更深的認識。
推薦閱讀:
專輯|Linux文章匯總
專輯|程序人生
專輯|C語言
我的知識小密圈
關注公眾號,后臺回復「1024」獲取學習資料網盤鏈接。
歡迎點贊,關注,轉發,在看,您的每一次鼓勵,我都將銘記于心~
嵌入式Linux
微信掃描二維碼,關注我的公眾號
總結
以上是生活随笔為你收集整理的聊聊 top 命令中的 CPU 使用率的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: (转)【JSON工具】一个JSON格式化
- 下一篇: [Eclipse经验] 如何导入XSD文