檢測LINUX程式的實時IO情況
Linux Kernel 2.6.20 以上的核心支援程式 IO 統計,可以用類似 iotop 這樣的工具來監測每個程式對 IO 操作的情況,就像用 top 來實時檢視程式記憶體、CPU 等佔用情況那樣。但是對於 2.6.20 以下的 Linux 核心版本就沒那麼幸運了。筆者寫了一個簡單的 Python 指令碼用來在 linux kernel < 2.6.20 下列印程式 IO 狀況。
Kernel < 2.6.20
這個指令碼的想法很簡單,把 dmesg 的結果重定向到一個檔案後再解析出來,每隔1秒鐘列印一次程式 IO 讀寫的統計資訊,執行這個指令碼需要 root:
1. #!/usr/bin/python
2. # Monitoring per-process disk I/O activity
3. # written by http://www.vpsee.com
4.
5. import sys, os, time, signal, re
6.
7. class DiskIO:
8. def __init__(self, pname=None, pid=None, reads=0, writes=0):
9. self.pname = pname
10. self.pid = pid
11. self.reads = 0
12. self.writes = 0
13.
14. def main():
15. argc = len(sys.argv)
16. if argc != 1:
17. print "usage: ./iotop"
18. sys.exit(0)
19.
20. if os.getuid() != 0:
21. print "must be run as root"
22. sys.exit(0)
23.
24. signal.signal(signal.SIGINT, signal_handler)
25. os.system('echo 1 > /proc/sys/vm/block_dump')
26. print "TASK PID READ WRITE"
27. while True:
28. os.system('dmesg -c > /tmp/diskio.log')
29. l = []
30. f = open('/tmp/diskio.log', 'r')
31. line = f.readline()
32. while line:
33. m = re.match(\
34. '^(\S+)\((\d+)\): (READ|WRITE) block (\d+) on (\S+)', line)
35. if m != None:
36. if not l:
37. l.append(DiskIO(m.group(1), m.group(2)))
38. line = f.readline()
39. continue
40. found = False
41. for item in l:
42. if item.pid == m.group(2):
43. found = True
44. if m.group(3) == "READ":
45. item.reads = item.reads + 1
46. elif m.group(3) == "WRITE":
47. item.writes = item.writes + 1
48. if not found:
49. l.append(DiskIO(m.group(1), m.group(2)))
50. line = f.readline()
51. time.sleep(1)
52. for item in l:
53. print "%-10s %10s %10d %10d" % \
54. (item.pname, item.pid, item.reads, item.writes)
55.
56. def signal_handler(signal, frame):
57. os.system('echo 0 > /proc/sys/vm/block_dump')
58. sys.exit(0)
59.
60. if __name__=="__main__":
61. main()
62.
Kernel >= 2.6.20
如果想用 iotop 來實時檢視程式 IO 活動狀況的話,需要下載和升級新核心(2.6.20 或以上版本)。編譯新核心時需要開啟 TASK_DELAY_ACCT 和 TASK_IO_ACCOUNTING 選項。解壓核心後進入配置介面:
# tar jxvf linux-2.6.30.5.tar.bz2
# mv linux-2.6.30.5 /usr/src/
# cd /usr/src/linux-2.6.30.5
# make menuconfig
選擇 Kernel hacking –> Collect scheduler debugging info 和 Collect scheduler statistics,儲存核心後編譯核心:
# make; make modules; make modules_install; make install
修改 grub,確認能正確啟動新核心:
# vi /boot/grub/menu.lst
出了新核心外,iotop 還需要 Python 2.5 或以上才能執行,所以如果當前 Python 是 2.4 的話需要下載和安裝最新的 Python 包。這裡使用原始碼編譯安裝:
# tar jxvf Python-2.6.2.tar.bz2
# cd Python-2.6.2
# ./configure
# make; make install
別忘了下載 setuptools:
# mv setuptools-0.6c9-py2.6.egg.sh setuptools-0.6c9-py2.6.egg
# sh setuptools-0.6c9-py2.6.egg
有網友對以上指令碼提出問題,問到 WRITE 為什麼會出現是 0 的情況,這是個好問題,筆者在這裡好好解釋一下。首先看看我們怎麼樣才能實時監測不同程式的 IO 活動狀況。
block_dump
Linux 核心裡提供了一個 block_dump 引數用來把 block 讀寫(WRITE/READ)狀況 dump 到日誌裡,這樣可以通過 dmesg 命令來檢視,具體操作步驟是:
# sysctl vm.block_dump=1
or
# echo 1 > /proc/sys/vm/block_dump
然後就可以通過 dmesg 就可以觀察到各個程式 IO 活動的狀況了:
# dmesg -c
kjournald(542): WRITE block 222528 on dm-0
kjournald(542): WRITE block 222552 on dm-0
bash(18498): dirtied inode 5892488 (ld-linux-x86-64.so.2) on dm-0
bash(18498): dirtied inode 5892482 (ld-2.5.so) on dm-0
dmesg(18498): dirtied inode 11262038 (ld.so.cache) on dm-0
dmesg(18498): dirtied inode 5892496 (libc.so.6) on dm-0
dmesg(18498): dirtied inode 5892489 (libc-2.5.so) on dm-0
問題
一位細心的網友提到這樣一個問題:為什麼會有 WRITE block 0 的情況出現呢?筆者跟蹤了一段時間,發現確實有 WRITE 0 的情況出現,比如:
# dmesg -c
...
pdflush(23123): WRITE block 0 on sdb1
pdflush(23123): WRITE block 16 on sdb1
pdflush(23123): WRITE block 104 on sdb1
pdflush(23123): WRITE block 40884480 on sdb1
...
答案
原來我們把 WRITE block 0,WRITE block 16, WRITE block 104 這裡麵包含的數字理解錯了,這些數字不是代表寫了多少 blocks,是代表寫到哪個 block,為了尋找真相,筆者追到 Linux 2.6.18 核心程式碼裡,在 ll_rw_blk.c 裡找到了答案:
$ vi linux-2.6.18/block/ll_rw_blk.c
1. void submit_bio(int rw, struct bio *bio)
2. {
3. int count = bio_sectors(bio);
4.
5. BIO_BUG_ON(!bio->bi_size);
6. BIO_BUG_ON(!bio->bi_io_vec);
7. bio->bi_rw |= rw;
8. if (rw & WRITE)
9. count_vm_events(PGPGOUT, count);
10. else
11. count_vm_events(PGPGIN, count);
12.
13. if (unlikely(block_dump)) {
14. char b[BDEVNAME_SIZE];
15. printk(KERN_DEBUG "%s(%d): %s block %Lu on %s\n",
16. current->comm, current->pid,
17. (rw & WRITE) ? "WRITE" : "READ",
18. (unsigned long long)bio->bi_sector,
19. bdevname(bio->bi_bdev,b));
20. }
21.
22. generic_make_request(bio);
23. }
很明顯從上面程式碼可以看出 WRITE block 0 on sdb1,這裡的 0 是 bio->bi_sector,是寫到哪個 sector,不是 WRITE 了多少 blocks 的意思。還有,如果 block 裝置被分成多個區的話,這個 bi_sector(sector number)是從這個分割槽開始計數,比如 block 0 on sdb1 就是 sdb1 分割槽上的第0個 sector 開始。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/16978544/viewspace-697548/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Linux 檢視程式情況Linux
- 檢測手機對MMAPI支援的情況API
- 程式設計師修bug時的真實情況程式設計師
- 【TUNE_ORACLE】檢視系統CPU和IO情況SQL參考OracleSQL
- Nagios 被動檢測oracle Rman備份情況iOSOracle
- linux系統檢視網路連線情況Linux
- 如何快速檢視Linux系統重啟情況Linux
- linux 網路 cat /proc/net/dev 檢視測試網路丟包情況Linuxdev
- 程式碼檢測HTML5/CSS3新特性的瀏覽器支援情況HTMLCSSS3瀏覽器
- 檢視ASM的Extent分佈情況ASM
- 檢查備份情況的指令碼指令碼
- 檢視mount掛載情況
- jstat命令檢視jvm的GC情況 (以Linux為例)JSJVMGCLinux
- 如何在零JS程式碼情況下實現一個實時聊天功能❓JS
- 檢查oracle的patch的升級情況Oracle
- Linux TCP RST情況LinuxTCP
- 【STC8H】低功耗情況下的IO口配置
- Linux上檢視造成IO高負載的程式Linux負載
- Linux檢視程式埠占用情況Linux
- 檢視SQLServer的LCK資源等待情況SQLServer
- linux系統檢視系統資源分析效能情況Linux
- IOSTAT對linux硬碟IO效能進行檢測iOSLinux硬碟
- Oracle 時段負載情況Oracle負載
- 為什麼靜態程式碼安全檢測工具會有誤報、漏報的情況出現?
- 使用shell指令碼檢測資料庫連線訪問情況指令碼資料庫
- 檢視過去的session鎖情況指令碼Session指令碼
- iostat命令——監控系統裝置的IO負載情況iOS負載
- Linux程式之如何檢視程式詳情?(ps命令)Linux
- 檢視LINUX程式記憶體佔用情況Linux記憶體
- 測試在cursor_sharing為force情況下執行計劃的共享情況
- 檢視PG資料庫的許可權情況資料庫
- 以實際情況切入,檢視MySQL複製問題的解決方案MySql
- Linux 效能監測:IOLinux
- php倒數計時出現-0的情況PHP
- Linux中什麼情況下會發生程式排程?Linux
- Android下檢視SO庫被依賴的情況Android
- 透過閃回事務檢視資料dml的情況
- 通過閃回事務檢視資料dml的情況