Linux內核源碼詳解——命令篇之iostat[zz]

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

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

  • 一、/proc/diskstats——該文件是內核2.6以上的系統中的,記錄了從Linux系統啓動以後,全部磁盤的相關信息,該文件中每一個參數表明的意義能夠自行google或者baidu,或者見博客:/proc/diskstats參數含義
  • 二、/proc/partitions——partitions是2.4版本的系統中的,其含義基本與diskstats同樣。
  • 三、/proc/stat——stat記錄了自系統啓動以後,CPU的信息,具體含義能夠參考博客:性能測試進階指南——基礎篇一(系統資源的講解)
  • 四、/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命令輸入的參數,每一個參數的功能能夠在上一篇博客中找到:性能測試進階指南——基礎篇之磁盤IOui

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

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即是所須要獲取的磁盤名稱;.net

第五步,進入主循環:code

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

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

每一個參數對應的值爲ci

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信息。

相關文章
相關標籤/搜索