Optimizing Linux Performance: A Hands-On Guide to Linux Performance Toolsnode
記錄一切能夠蒐集的信息,即便其中的一些信息在當時看起來沒有太大的用途。linux
在Linux下,進程有可運行和阻塞兩種狀態。可運行進程有分爲兩類:已經得到CPU時間正在運行的一類,和等待CPU時間的一類。在Linux系統中,運行隊列長度就是系統中可運行狀態的進程數量(平均值)。被阻塞的進程也能夠分爲兩類:被I/O阻塞的進程,以及被系統調用阻塞的進程。一個CPU一次只能執行一個進程。在進程調度時,CPU須要把當前進程的信息保存起來,從內存中加載下一個進程的信息。這個過程叫作上下文切換。上下文切換會致使CPU中的高速緩存和流水線刷新,對性能有負面影響。爲了公平的分配CPU時間,Linux會週期性的中斷進程。一般,這種週期性上下文切換的數據能夠做爲考察系統上下文切換數量的基準:ios
cat /proc/interrupts | grep timer; sleep 10; cat /proc/interrupts | grep timer;
若是系統中斷頻率高於定時器的頻率,說明進程常常陷入I/O等待或系統調用(好比休眠)等待之中。typescript
在任意時刻,CPU能夠處於如下幾種狀態: -空閒。CPU沒有任務須要執行。 -執行用戶代碼,即「用戶」時間。 -執行內核代碼,即「系統」時間。 -執行低優先級的用戶代碼,即「nice」時間。 -等待I/O(磁盤或網絡),即「iowait」時間。 -處理硬中斷,即irq。 -處理軟終端,softirq。shell
vmstat命令提供了系統CPU統計信息:緩存
vmstat [-n] [-s] [delay [count]]
| -n | 再也不重複顯示列標題 | | -s | 輸出系統啓動以來的累計數據 | | delay | 採樣間隔 |性能優化
vmstat顯示的各列以下:bash
| r | 運行隊列長度 | | b | 等待I/O操做的進程數 | | forks | 建立新進程的次數 | | in | 系統中斷次數 | | cs | 系統上下文切換次數 | | us | 用戶代碼消耗的時間佔比,即用戶時間和nice時間之和 | | sy | 系統代碼消耗的時間佔比,即系統時間、irq和softirq時間之和 | | wa | 等待I/O的時間佔比 | | id | 空閒時間佔比 |網絡
top命令也提供了CPU信息:架構
top [-d delay] [-n iter] [-i] [-b]
| -d delay | 更新間隔 | | -n iteration | 迭代次數 | | -i | 顯示空閒進程 | | -b | 以批處理方式運行 |
top顯示的各列以下:
| us | 用戶時間 | | sy | 系統時間 | | ni | nice時間 | | id | 空閒時間 | | wa | 等待I/O的時間 | | hi | irq時間 | | si | softirq時間 | | load average | 系統平均負載 | | %CPU | 特定線程CPU佔比 | | PRI | 進程優先級 | | NI | 進程nice值 | | WCHAN | 等待在哪一個系統調用中 | | TIME | 進程消耗的CPU總時間(用戶時間和系統時間) | | COMMAND | 進程執行的命令 | | s | 進程狀態:睡眠S、運行R、殭屍Z、不可中斷睡眠D、跟蹤T |
另一個經常使用的命令是procinfo:
procinfo [-f] [-b] [-D] [-n sec] [-F file]
| -f | 全屏 | | -d | 顯示變化量 | | -D | 顯示總量 | | -n sec | 採用間隔 | | -F file | 輸出到文件 |
top輸出的各列爲:
| user | CPU消耗的總用戶時間 | | nice | CPU消耗的總nice時間 | | system | CPU消耗的總系統時間 | | idle | CPU消耗的總空閒時間 | | irq 0-N | irq編號,已啓動次數即內存程序 |
mpstat命令能夠查看指定CPU上的時間分配:
mpstat [-P {cpu|ALL}] [delay [count]]
| -P | 監視哪一個CPU,從0開始 | | delay | 採樣間隔 |
mpstat輸出的各列爲:
| user | 用戶時間 | | nice | nice時間 | | system | 系統時間 | | iowait | I/O時間 | | irq | irq時間 | | softirq | softirq時間 | | idle | 空閒時間 |
sar能夠收集系統信息:
sar [options] [delay [count]]
| -c | 報告每秒建立的進程數 | | -I {irq SUM ALL XALL } | 中斷速度 | | -P {cpu ALL} | 指定CPU | | -q | 運行隊列長度 | | -u | CPU使用狀況 | | -w | 上下文切換數 | | -o file | 輸出到文件 | | -f file | 從文件讀取選項 | | delay | 採用間隔 | | count | 樣本數 |
sar統計的CPU數據有:
| user | 用戶時間 | | nice | nice時間 | | system | 系統時間 | | iowait | I/O時間 | | idle | 空閒時間 | | runq-sz | 運行隊列長度 | | plist-sz | 進程數 | | ldavg-1 | 1分鐘負載 | | ldavg-5 | 5分鐘負載 | | ldavg-15 | 15分鐘負載 | | proc/s | 每秒新建線程數(等於vmstat中的forks) | | cswch | 每秒上下文切換 | | intr/s | 每秒中斷數 |
oprofile也能夠收集系統信息:
opcontrol [--start] [--stop] [--dump] opcontrol [--list-events] [-event=:name:count:unitmask:kernel:user:] opreport [-r] [-t]
| -s –start | 開始分析 | | -d –dump | 導出文件 | | –stop | 中止分析 | | -l –list-events | 列出能夠採樣的事件 | | -event=:name:count:unitmask:kernel:user: | | | –vmlinux=kernel | 內核 |
opreport選項:
| -r –reverse-sort | 逆序顯示 | | -t –threshold | |
Linux將內存劃分爲「頁」,這是內存管理的單位。下面的程序能夠輸出系統中一個頁有多少字節:
#include <unistd.h> int main(int argc, char *argv[]) { printf("System page size: %d\n", getpagesize()); }
IA32架構下,頁一般是4KB。爲了提升性能,Linux可使用HugePage來管理單元。HugePage一般是2MB。
爲了提供更多的虛擬內存,當物理內存不足時,Linux將部份內存保存在磁盤上,這部分空間叫作交換分區(swap space)。Linux也會把文件系統中近期訪問過的文件緩存在內存中,這部分叫作緩存(cache)。此外,爲每一個已經打開的文件,Linux會分配讀寫緩衝區,避免每次寫入都執行磁盤IO。
vmstat命令能夠提供內存統計信息:
vmstat [-a] [-s] [-m]
| -a | 顯示活躍內存和非活躍內存。非活躍內存是已分配未使用的內存。 | | -s | 打印vm表 | | -m | 輸出分片信息,同/proc/slabinfo |
vmstat輸出的各列以下:
| swpd | 交換到磁盤的內存總量 | | free | 未使用的內存 | | buff | 緩衝區大小,單位KB | | cache | 緩存大小,單位KB | | active | 活躍內存 | | inactive | 非活躍內存 | | si | 磁盤到內存的交換速率,單位KB/s | | so | 內存到磁盤的交換速率,單位KB/s | | pages paged in | 從磁盤讀入緩衝區的內存,單位頁 | | pages paged out | 從緩衝區寫入磁盤的內存,單位頁 | | used swap | 已使用的交換分區 | | free swap | 空閒交換分區 | | total swap | 交換分區總量 |
top命令也能夠查看內存狀況。top輸出的各列以下:
| %MEM | 進程內存佔比 | | VIRT | 進程虛擬內存總量,含已分配未使用的內存 | | SWAP | 進程使用的交換分區總量,單位KB | | RES | 進程使用的物理內存 | | CODE | 進程可執行代碼使用的內存 | | DATA | 進程保存數據和堆棧使用的內存 | | SHR | 和其餘進程共享的內存 | | nDRT | 髒頁面數量 | | Mem: total, used, free | 內存總量、使用量、空閒量 | | swap: total, used, free | 交換分區總量、使用量、空閒量 | | buffers | 緩衝區大小 |
procinfo提供的內存信息以下:
| Total | 物理內存大小 | | Used | 已使用的物理內存 | | Free | 未使用的物理內存 | | Shared | 再也不使用 | | Buffers | 緩衝區 | | Page in | 從磁盤讀入的塊數量 | | Page out | 向磁盤寫入的塊數量 | | Swap in | 從交換分區讀入的頁數量 | | Swap out | 向交換分區寫入的頁數量 |
free命令也能夠提供內存狀況:
free [-l] [-t] [-s delay] [-c count]
| -s delay | 採樣間隔 | | -c count | 採樣次數 | | -l | 顯示高端內存和低端內存 | | -t | 顯示物理內存和交換分區之和 |
free輸出的內容以下:
| Total | 物理內存和交換空間總和 | | Used | 已使用的物理內存和交換空間 | | Free | 未使用的物理內存和交換空間 | | Shared | 已廢棄 | | Buffers | 緩衝區 | | Cached | 緩存 | | -/+ buffers/cache | 是否統計緩衝區和緩存 | | Low | 低端內存,便可由內核直接訪問的內存 | | High | 高端內存 |
slabtop能夠顯示內存分配狀況:
slabtop [--delay n -sort={a|b|c|l|v|n|o|p|s|u}
| –delay | 採樣間隔 | | 排序 | | | a | 活躍對象 | | b | 所有對象 | | c | 緩存內存總量 | | l | 緩存分片數 | | v | 緩存活躍分片數 | | n | 緩存名 | | o | 對象數量 | | p | 每一個分片使用的頁數量 | | s | 對象大小 |
sar能夠輸出內存信息:
sar [-B] [-r] [-R]
| -B | 缺頁數量 | | -W | 交換頁數量 | | -r | 內存信息 |
sar輸出的內容有:
| pgpgin/s | 每秒從磁盤讀入的數據,單位KB | | pgpgout/s | 每秒向磁盤寫入的數據,單位KB | | fault/s | 每秒缺頁,可能不用訪問磁盤 | | majflt/s | 每秒缺頁(major fault),須要訪問磁盤 | | pswpin/s | 每秒讀入內存的交換分區頁數 | | pswpin/s | 每秒寫入交換分區的頁數 | | kbmemfree | 空閒物理內存,單位KB | | kbmemused | 已使用物理內存,單位KB | | %memused | 已使用物理內存佔比 | | kbbuffers | 緩衝區 | | kbcached | 緩存 | | kbswpfree | 空閒交換分區 | | kbswpused | 已使用交換分區 | | %swpused | 已使用交換分區佔比 | | kbswpcad | 在物理內存和交換分區都存在的內存 | | frmpg/s | 系統釋放頁的速度。若是是負數,說明系統正在分配頁。 | | bufpg/s | 系統將新頁做爲緩衝區的速度。若是是負數,說明緩衝區正在減小。 |
查看文件文件/proc/meminfo也能夠獲得內存信息:
| MemTotal | 物理內存 | | MemFree | 物理內存空閒 | | Buffers | 緩衝區 | | Cached | 緩存 | | SwapCached | 在交換分區和物理內存中都存在的內存 | | Active | 活躍內存 | | Inactive | 非活躍內存 | | HighTotal | 高端內存 | | HighFree | 空閒高端內存 | | LowTotal | 低端內存 | | LowFree | 空閒低端內存 | | SwapTotal | 交換內存 | | SwapFree | 空閒交換內存 | | Dirty | 待刷新到磁盤的內存 | | Writeback | 刷新到磁盤的內存 | | Mapped | mmap映射的內存 | | Slab | 內核分片內存 | | Committed_AS | | | PageTables | | | VmallocTotal | vmalloc可用內核內存 | | VmallocUsed | vmalloc已用內核內存 | | VmallocChunk | vmalloc最大可用連續內存 | | HugePages_Total | HugePage總大小 | | HugePages_Free | 空閒HugePage |
time命令(/usr/bin/time,不是bash內置的time函數)能夠輸出
time [-v] application
time命令的輸出以下
| User time | 應用程序消耗的用戶時間 | | System time | 程序在Linux內核中消耗的時間 | | Elapsed(wall-clock) | 應用程序執行的時間 | | Percent of CPU this job got | 進程消耗的CPU佔比 | | Major(requiring I/O) page faults | 主缺頁錯誤數 | | Minor(reclaiming a frame) page faults | 次缺頁錯誤數 | | Swaps | 交換到磁盤的次數 | | Voluntary context switches | 進程主動讓出CPU(好比休眠)的次數 | | Involuntary context switchs | 進程被動讓出CPU(如中斷)的次數 | | Page size | 頁大小 | | Exit status | 退出碼 |
strace是一個觀察系統調用執行狀況的工具:
strace [-c] [-p pid] [-o file] [command [arg ...]]
| -c | 打印統計信息 | | -p pid | 跟蹤進程 | | -o file | 輸出到文件 |
strace輸出各種內容爲:
| % time | 系統調用耗時佔所有系統調用耗時總和的比例 | | seconds | 系統調用消耗的秒數 | | usecs/call | 平均每場調用消耗的微秒數 | | calls | 調用次數 | | errors | 調用失敗次數 |
ltrace和strace相似,區別在於ltrace跟蹤程序對庫的調用:
ltrace [-c] [-p pid] [-o filename] [-S] command
| -c | 顯示彙總信息 | | -s | 跟蹤庫調用和系統調用 | | -p pid | 跟蹤指定進程 | | -o file | 輸出到文件 |
ltrace輸出各種內容和strace相似:
| % time | 庫調用耗時佔所有庫調用耗時總和的比例 | | seconds | 庫調用消耗的秒數 | | usecs/call | 平均每場調用消耗的微秒數 | | calls | 調用次數 | | function | 函數名 |
ps也是一個很好的工具:
ps [-o etime,time,pcpu,command] [-u user] [-U user] [PID]
| etime | 從程序開始執行的總時間 | | time | CPU時間,即系統時間和用戶時間之和 | | pcpu | 消耗CPU佔比 |
在執行動態連接程序時,首先運行的是Linux加載器ld.so。要觀察程序啓動時ld消耗的時間,能夠用:
env LD_DEBUG=statistics,help LD_DEUBG_OUTPUT=filename <command>
gprof [-p -flat-profile -q --graph --brief -A -annotated-source] app
ps [-o vsz,rss,tsiz,dsiz,majflt,minflt,pmem,command] <pid>
| vsz | 進程使用的虛擬內存 | | rss | 進程使用的物理內存 | | tsiz | 程序代碼的虛擬大小 | | dsiz | 數據的虛擬大小 | | majflt | 主缺頁故障,須要從執行磁盤IO | | minflt | 次缺頁故障,不須要執行磁盤IO | | pmep | 進程內存佔比 | | command | 命令 |
/proc/<PID>/status
| VmSize | 進程的虛擬內存大小 | | VmLck | 被鎖定的虛擬內存大小,被鎖定的虛擬內存不能交換到磁盤 | | VmRSS | 物理內存大小,同ps中的rss | | VmData | 數據大小,不含堆棧 | | VmStk | 堆棧大小 | | VmExec | 可執行虛擬內存大小,不含庫 | | VmLib | 庫大小 |
/proc/<PID>/maps
| Address | 地址 | | Permissions | 權限。r:讀,w:寫,x:執行,s:共享,p:私有 | | Offset | 偏移量 | | Device | 設備 | | Inode | 文件節點 | | Pathname | 文件路徑 |
valgrind --skin-cachegrind application cg_annotation --pid [--auto=yes|no]
kcachegrind能夠檢測高速緩存。
calltree application kcachegrind cachegrind.out.pid
ipcs [-t] [-c] [-l] [-u] [-p]
Linux上IDE驅動的磁盤多被命名爲hda、hdb、hdc等,SCSI驅動的硬盤被命名爲sda、sdb、sdc等。分區名是在磁盤名後面添加分區號,好比首個IDE磁盤的第二個分區是/dev/hda2。
vmstat能夠用來觀察磁盤I/O狀況:
vmstat [-D] [-d] [-p partition] [interval [count]]
| -D | 顯示I/O系通通計信息,顯示總量 | | -d | 顯示從系統啓動後的總量 | | -p partition | 顯示分區 | | interval | 採樣間隔 | | count | 採樣次數 |
vmstat輸出的I/O統計信息有:
| bo | 寫入磁盤的塊數,一個塊一般KB | | bi | 讀取磁盤的塊數 | | wa | 等待I/O消耗的CPU時間 | | reads: total | 讀請求總數 | | reads: merged | 合併的讀請求數 | | reads: sectors | 讀取的扇區數 | | reads: ms | 讀取磁盤消耗的時間 | | writes: total | 寫請求總數 | | writes: merged | 合併的寫請求數量 | | writes: sectors | 寫扇區數量 | | IO: cur | 當前處理的I/O數 | | IO: s | 等待I/O完成消耗的時間 |
iostat [-d] [-k] [-x] [device] [interval] [count]
| -d | 值顯示磁盤I/O統計信息 | | -k | 以KB爲單位,默認以塊爲單位 | | -x | 顯示擴展性能I/O統計信息 | | device | 指定設備 | | interval | 採樣間隔 | | count | 採樣數 |
iostat輸出的內容以下:
| tps | 每秒傳輸次數 | | Blk_read/s | 每秒讀取的塊數 | | Blk_wrtn/s | 每秒寫入的塊數 | | Blk_read | 讀取的塊總量 | | Blk_wrtn | 寫入的塊總量 | | rrqm/s | 合併的讀請求數 | | wrqm/s | 合併的寫請求數 | | r/s | 每秒提交讀請求數 | | w/s | 每秒提交寫請求數 | | rsec/s | 每秒讀取扇區數 | | wsec/s | 每秒寫入扇區數 | | rkB/s | 每秒讀取的KB數 | | wkB/s | 每秒寫入的KB數 | | avgrq-sz | 請求平均大小,單位是扇區 | | avgqu-sz | 請求隊列平均大小 | | await | 完成一個請求的平均時間,即在隊列中的等待時間和磁盤操做時間之和 | | svctm | 執行操做的平均時間,即await減去隊列中的等待時間 |
sar -d [interval [count]]
| tps | 每秒傳輸數 | | rd_sec/s | 每秒讀取數量 | | wr_sec/s | 每秒寫入數量 |
lsof [-r delay] [+D directory] [+d directory] [file]
| -r delay | 採樣間隔 | | +D directory | 遞歸監視指定目錄,報告使用目錄中文件的進程 | | +d directory | 監視指定目錄,報告使用目錄中文件的進程 |
lsof輸出的內容有:
| COMMAND | 進程命令 | | PID | 進程編號 | | USER | 用戶 | | FD | txt表示可執行文件,mem表示內存映射文件 | | TYPE | 文件類型,REG表示普通文件 | | DEVICE | 設備,能夠由ls -al /dev獲得 | | SIZE | 文件大小 | | NODE | 索引節點 |
當數據幀通過內核時,Linux會統計以下信息:
-發送/接收。正常收發的數據。 -錯誤。多是電纜損壞或雙工不匹配。 -丟棄。因爲內存或緩衝區不足丟棄的數據。 -溢出。因爲內核或網卡收到太多的幀,被網絡丟棄的數據。 -幀。因爲物理層面緣由被丟棄的幀,如CRC校驗錯誤。 -多播。 -壓縮。如PPP(點對點)協議或SLIP(串行線路網際)協議會壓縮幀數據。
在Linux下,以太網設備被命名爲ethN,如eth0就是第一個以太網設備。PPP設備以pppN命名。
mii-tool能夠檢測以太網設備信息:
mii-tool [-v] [device]
ethtool [device]
ifconfig [device]
| RX packets | 設備已經接收的數據包數 | | TX packets | 設備已經發送的數據包數 | | errors | 發送或接收時的錯誤數 | | dropped | 發送或接收時丟棄的包數 | | overruns | 發生緩衝區不足的次數 | | frame | 底層幀錯誤數 | | carrier | 因爲鏈路(如電纜)故障丟失的數據包數 |
ip -s [-s] link
| bytes | 發送或接收的字節數 | | packets | 發送或接收的數據包數 | | errors | 發送或接收時發生的錯誤數 | | dropped | 因爲網卡缺乏資源,致使沒有發送或接收的數據包數 | | overruns | 發生緩衝區不足的次數 | | mcast | 接收的多播數據包的數量 | | carrier | 因爲鏈路故障而丟棄的數據包數 | | collsns | 傳送時設備發送衝突的次數,當多個設備試圖同時使用網絡時會發送衝突 |
sar [-n DEV | EDEV | SOCK | FULL] [DEVICE] [interval] [count]
| -n DEV | 顯示每一個設備發送和接收的字節數 | | -n EDEV | 顯示每一個設備發送和接收的錯誤信息 | | -n SOCK | 顯示使用套接字(TCP、UDP、RAW)的總數信息 | | -n FULL | 顯示全部網絡統計信息 | | interval | 採樣間隔 | | count | 採樣總數 |
sar輸出以下:
| rxpck/s | 數據包接收速率 | | txpck/s | 數據包發送速率 | | rxbyt/s | 字節發送速率 | | txbyt/s | 字節接收速率 | | rxcmp/s | 壓縮包接收速率 | | txcmp/s | 壓縮包發送速率 | | rxmcst/s | 多播包發送速率 | | rxerr/s | 接收錯誤率 | | txerr/s | 發送錯誤率 | | coll/s | 發送時以太網衝突率 | | rxdrop/s | 因爲linux內核緩衝區不足致使的接收幀丟失率 | | txdrop/s | 因爲linux內核緩衝區不足致使的發送幀丟失率 | | rxfram/s | 幀對齊錯誤致使的接收幀丟失率 | | rxfifo/s | 因爲FIFO錯誤致使的接收幀丟失率 | | txfifo/s | 因爲FIFO錯誤而致使的發送幀丟失率 | | totsck | 正在使用的套接字數量 | | tcpsck | TCP套接字數量 | | udpsck | UDP套接字數量 | | rawsck | RAW套接字數量 | | ip-frag | IP分片總數 |
iptraf [-d interface] [-s interface] [-t <minutes>]
| -d interface | 顯示詳細的接口信息 | | -s interface | 顯示接口上哪些端口在使用 | | -t <minutes> | 運行時間 |
netstat [-p] [-c] [-interfaces=<name>] [-s] [-t] [-u] [-w]
| -p | 顯示套接字對應的PID | | -c | 每秒刷新 | | –interfaces=<name> | 顯示指定接口 | | –statistics, -s | 顯示IP、UDP、ICMP、TCP統計信息 | | –tcp, -t | 顯示TCP套接字信息 | | –udp, -u | 顯示UDP套接字信息 | | –raw, -w | 顯示RAW套接字信息 |
while true; do sleep 1; /sbin/ifconfig eth0 | grep 'RX packets'; done;
script命令會啓動一個新shell,記錄shell中的全部輸入和輸出。
script [-a] [-t] [file]
| -a | 追加寫入文件 | | -t | 計時 | | file | 輸出文件名,默認是typescript |
在使用時,最好先設置爲啞終端:
export TERM=dumb script ps_output
watch每秒運行一次命令,並將命令輸出的變化突出顯示:
watch [-d [=cumulative]] [-n sec] <command>
| -d[=cumulative] | 突出顯示變化 | | -n sec | 採樣間隔 |
watch -n 10 "ps -o minflt,cmd"
ldd <binary>
objdump -T <binary>