天天看點

linux+核心+nice,Linux核心源碼詳解——指令篇之iostat

本文主要分析了Linux的iostat指令的源碼,iostat的主要功能見部落格:性能測試進階指南——基礎篇之磁盤IO

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資訊。