【轉】Linux內核源碼詳解——命令篇之iostat

iostat源碼共563行,應該算是Linux系統命令代碼比較少的了。源代碼中主要涉及到如下幾個Linux的內核文件:

  • 1、/proc/diskstats——該文件是內核2.6以上的系統中的,記錄了從Linux系統啓動之後,所有磁盤的相關信息,該文件中每個參數代表的意義可以自行google或者baidu,或者見博客:/proc/diskstats參數含義

  • 2、/proc/partitions——partitions是2.4版本的系統中的,其含義基本與diskstats一樣。

  • 3、/proc/stat——stat記錄了自系統啓動之後,CPU的信息,具體含義可以參考博客:性能測試進階指南——基礎篇一(系統資源的講解)

  • 4、/proc/cpuinfo——iostat主要是從該內核文件中獲取cpu的核心數的。

iostat源碼解析

第一步,從/proc/cpuinfo中獲取系統的cpu核心數,通過計算該文件中processor出現的次數便可以得到cpu的核心數;

第二步,通過判斷文件/proc/diskstats和/proc/partitions是否存在,從而判斷linux的內核是2.4版本還是2.6版本:如果/proc/diskstats文件存在,則爲2.6版本;否則判斷/proc/partitions是否存在,若存在,則爲2.4版本;

第三部,分析iostat命令輸入的參數,每個參數的功能可以在上一篇博客中找到:性能測試進階指南——基礎篇之磁盤IO

第四步,初始化,獲取磁盤名稱。以內核2.6爲例,讀取文件/proc/diskstats

104    0 cciss/c0d0 49787 19805 1597284 159946 20172754 28596938 390157514 1583532 0 1352168 1737502

第一個參數104和第二個參數0分別代表了major和minor,major是8的倍數,minor是16的倍數,只要同時符合這兩個的條件,其對應的第三個參數cciss/c0d0便是所需要獲取的磁盤名稱;

第五步,進入主循環:

(1) 獲取/proc/diskstats中每個磁盤的數據,例如:

104    0 cciss/c0d0 49787 19805 1597284 159946 20172754 28596938 390157514 1583532 0 1352168 1737502

每個參數對應的值爲

104——major  
0——minor  
49787——rd_ios  
19805——rd_merges  
1597284——rd_sectors  
159946——rd_ticks  
20172754——wr_ios  
28596938——wr_merges  
390157514——wr_sectors  
1583532——wr_ticks  
1352168——ticks  
1737502——aveq

(2) 獲取/proc/stat中的數據,計算cpu的平均時間:分別獲取cpu的user時間,nice時間,system時間,idle時間,iowait時間。計算中將nice時間併入user時間,將irq時間和softirq時間併入system時間。此處只計算cpu的平均和狀態,不計算每隔核單獨的狀態。

(3)計算deltams時間,其中HZ是Linux的系統頻率。

deltams = 1000.0 * ((new_cpu.user + new_cpu.system + new_cpu.idle + new_cpu.iowait) - (old_cpu.user + old_cpu.system + old_cpu.idle + old_cpu.iowait)) / ncpu / HZ; `

(4)計算IO

blkio.rd_ios = new_blkio[p].rd_ios - old_blkio[p].rd_ios;
blkio.rd_merges = new_blkio[p].rd_merges - old_blkio[p].rd_merges;
blkio.rd_sectors = new_blkio[p].rd_sectors - old_blkio[p].rd_sectors;
blkio.rd_ticks = new_blkio[p].rd_ticks - old_blkio[p].rd_ticks;
blkio.wr_ios = new_blkio[p].wr_ios - old_blkio[p].wr_ios;
blkio.wr_merges = new_blkio[p].wr_merges - old_blkio[p].wr_merges; 
blkio.wr_sectors = new_blkio[p].wr_sectors - old_blkio[p].wr_sectors;
blkio.wr_ticks = new_blkio[p].wr_ticks - old_blkio[p].wr_ticks;
blkio.ticks = new_blkio[p].ticks - old_blkio[p].ticks;
blkio.aveq = new_blkio[p].aveq - old_blkio[p].aveq;
n_ios  = blkio.rd_ios + blkio.wr_ios;
n_ticks = blkio.rd_ticks + blkio.wr_ticks;
n_kbytes = (blkio.rd_sectors + blkio.wr_sectors) / 2.0;
queue = blkio.aveq / deltams;
size = n_ios ? n_kbytes / n_ios : 0.0;
wait = n_ios ? n_ticks / n_ios : 0.0;
svc_t = n_ios ? blkio.ticks / n_ios : 0.0;
busy = 100.0 * blkio.ticks / deltams; 
if (busy > 100.0) busy = 100.0;

rd_sectors和wr_sectors是扇區數,如果需要換算成KB等單位,需要除以2,1KB=2*512Bytes。512Bytes爲1個扇區數。

(5)計算CPU

cpu.user = new_cpu.user - old_cpu.user;
cpu.system = new_cpu.system - old_cpu.system;
cpu.idle = new_cpu.idle - old_cpu.idle;
cpu.iowait = new_cpu.iowait - old_cpu.iowait;
total = (cpu.user + cpu.system + cpu.idle + cpu.iowait) / 100.0;
printf("%3.0f %3.0f ", cpu.user / total, cpu.system / total);
if (kernel == 6) printf("%3.0f ", cpu.iowait / total);
printf("%3.0f", cpu.idle / total);

(6) Save old stats:

old_blkio[p] = new_blkio[p];
old_cpu = new_cpu;

每隔採樣時間循環執行第五步。

從源碼中可以看出,第一次獲取的時候,是沒有old stats的,所有的old stats值均爲0,即iostat在第一次輸出的值爲Linux啓動之後至當前時間的一個平均狀態值,在之後的輸出值則爲系統當前的實時磁盤I/O信息和CPU信息。


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