我們對系統(tǒng)性能進行優(yōu)化時,一般會使用top命令來查看系統(tǒng)負載和系統(tǒng)中各個進程的運行情況,從而找出影響系統(tǒng)性能的因素。如下圖所示:
top
top命令會輸出很多系統(tǒng)相關的信息,如:系統(tǒng)負載、系統(tǒng)中的進程數(shù)、CPU使用率和內(nèi)存使用率等,這些信息對排查系統(tǒng)性能問題起著至關重要的作用。
本文主要介紹top命令中的iowait指標(如上圖中紅色方框所示)的含義和作用。
什么是iowait
什么是iowait?我們來看看 Linux 的解釋:
Show the percentage of time that the CPU or CPUs were idle during which the system had an outstanding disk I/O request.
中文翻譯的意思就是:CPU 在等待磁盤 I/O 請求完成時,處于空閑狀態(tài)的時間百分比(此時正在運行著idle進程)。
可以看出,如果系統(tǒng)處于iowait狀態(tài),那么必須滿足以下兩個條件:
系統(tǒng)中存在等待 I/O 請求完成的進程。
系統(tǒng)當前正處于空閑狀態(tài),也就是說沒有可運行的進程。
iowait統(tǒng)計原理
既然我們知道了iowait的含義,那么接下來看看 Linux 是怎么統(tǒng)計iowait的比率的。
Linux 會把iowait占用的時間輸出到/proc/stat文件中,我們可以通過一下命令來獲取到iowait占用的時間:
cat/proc/stat
命令輸出如下圖所示:
stat
紅色方框中的數(shù)據(jù)就是iowait占用的時間。
我們可以每隔一段時間讀取一次/proc/stat文件,然后把兩次獲取到的iowait時間進行相減,得到的結(jié)果是這段時間內(nèi),CPU處于iowait狀態(tài)的時間。接著再將其除以總時間,得到iowait占用總時間的比率。
現(xiàn)在我們來看看/proc/stat文件是怎樣獲取iowait的時間的。
在內(nèi)核中,每個 CPU 都有一個cpu_usage_stat結(jié)構(gòu),主要用于統(tǒng)計 CPU 一些信息,其定義如下:
structcpu_usage_stat{ cputime64_tuser; cputime64_tnice; cputime64_tsystem; cputime64_tsoftirq; cputime64_tirq; cputime64_tidle; cputime64_tiowait; cputime64_tsteal; cputime64_tguest; cputime64_tguest_nice; };
cpu_usage_stat結(jié)構(gòu)的iowait字段記錄了 CPU 處于iowait狀態(tài)的時間。
所以要獲取系統(tǒng)處于iowait狀態(tài)的總時間,只需要將所有 CPU 的iowait時間相加即可,代碼如下(位于源文件fs/proc/stat.c):
staticintshow_stat(structseq_file*p,void*v) { u64iowait; ... //1.遍歷系統(tǒng)中的所有CPU for_each_possible_cpu(i){ ... //2.獲取CPU對應的iowait時間,并相加 iowait=cputime64_add(iowait,kstat_cpu(i).cpustat.iowait); ... } ... return0; }
show_stat()函數(shù)首先會遍歷所有 CPU,然后讀取其iowait時間,并且將它們相加。
增加iowait時間
從上面的分析可知,每個 CPU 都有一個用于統(tǒng)計iowait時間的計數(shù)器,那么什么時候會增加這個計數(shù)器呢?
答案是:系統(tǒng)時鐘中斷。
在系統(tǒng)時鐘中斷中,會調(diào)用account_process_tick()函數(shù)來更新 CPU 的時間,代碼如下:
voidaccount_process_tick(structtask_struct*p,intuser_tick) { cputime_tone_jiffy_scaled=cputime_to_scaled(cputime_one_jiffy); structrq*rq=this_rq(); //1.如果當前進程處于用戶態(tài),那么增加用戶態(tài)的CPU時間 if(user_tick){ account_user_time(p,cputime_one_jiffy,one_jiffy_scaled); } //2.如果前進程處于內(nèi)核態(tài),并且不是idle進程,那么增加內(nèi)核態(tài)CPU時間 elseif((p!=rq->idle)||(irq_count()!=HARDIRQ_OFFSET)){ account_system_time(p,HARDIRQ_OFFSET,cputime_one_jiffy, one_jiffy_scaled); } //3.如果當前進程是idle進程,那么調(diào)用account_idle_time()函數(shù)進行處理 else{ account_idle_time(cputime_one_jiffy); } }
我們主要關注當前進程是idle進程的情況,這是內(nèi)核會調(diào)用account_idle_time()函數(shù)進行處理,其代碼如下:
voidaccount_idle_time(cputime_tcputime) { structcpu_usage_stat*cpustat=&kstat_this_cpu.cpustat; cputime64_tcputime64=cputime_to_cputime64(cputime); structrq*rq=this_rq(); //1.如果當前有進程在等待IO請求的話,那么增加iowait的時間 if(atomic_read(&rq->nr_iowait)>0){ cpustat->iowait=cputime64_add(cpustat->iowait,cputime64); } //2.否則增加idle的時間 else{ cpustat->idle=cputime64_add(cpustat->idle,cputime64); } }
account_idle_time()函數(shù)的邏輯比較簡單,主要分以下兩種情況進行處理:
如果當前有進程在等待 I/O 請求的話,那么增加iowait的時間。
如果當前沒有進程在等待 I/O 請求的話,那么增加idle的時間。
所以,從上面的分析可知,要增加iowait的時間需要滿足以下兩個條件:
當前進程是idle進程,也就是說 CPU 處于空閑狀態(tài)。
有進程在等待 I/O 請求完成。
進一步說,當 CPU 處于iowait狀態(tài)時,說明 CPU 處于空閑狀態(tài),并且系統(tǒng)中有進程因為等待 I/O 請求而阻塞,也說明了 CPU 的利用率不夠充分。
這時,我們可以使用異步 I/O(如iouring)來優(yōu)化程序,使得進程不會被 I/O 請求阻塞。
審核編輯:劉清
-
cpu
+關注
關注
68文章
10803瀏覽量
210786 -
LINUX內(nèi)核
+關注
關注
1文章
316瀏覽量
21605 -
時鐘中斷
+關注
關注
0文章
4瀏覽量
7684
原文標題:系統(tǒng)性能分析之|iowait是什么?
文章出處:【微信號:LinuxHub,微信公眾號:Linux愛好者】歡迎添加關注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關推薦
評論