自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

系統(tǒng)性能分析從入門到進(jìn)階

原創(chuàng) 精選
開發(fā) 前端
本文以系統(tǒng)為中心, 結(jié)合日常工作和用例, 由淺入深地介紹了性能分析的一些方法和體會, 希望對想了解系統(tǒng)性能分析的同學(xué)有所幫助。

作者| 勿非

一、入門篇

1.資源角度

USE

產(chǎn)品跑在系統(tǒng)的各種資源上面, 從系統(tǒng)資源的角度入門性能分析是個不錯的選擇, 我們以業(yè)界知名大牛Brendan Gregg的USE方法開始, USE特點就是簡單有效適合入門, 用Brendan的話描述USE的效果:

I find it solves about 80% of server issues with 5% of the effort.

USE從系統(tǒng)資源的角度, 包括但不限于CPU, 內(nèi)存, 磁盤, 網(wǎng)絡(luò)等, 關(guān)注以下3個方面

  • Utilization (U): as a percent over a time interval. eg, "one disk is running at 90% utilization". 大多數(shù)情況可以合理推測利用率高可能會影響性能。
  • Saturation (S): as a queue length. eg, "the CPUs have an average run queue length of four". 資源競爭的激烈程度。
  • Errors (E). scalar counts. eg, "this network interface has had fifty late collisions". Errors相對直觀。

CPU

對于CPU, 主要關(guān)注以下指標(biāo):

  • Utilization. CPU的利用率。
  • Saturation. 可以是load average, runqueue length, sched latency等

CPU利用率用top看下

top - 17:13:49 up 83 days, 23:10,  1 user,  load average: 433.52, 422.54, 438.70
Tasks: 2765 total, 23 running, 1621 sleeping, 0 stopped, 34 zombie
%Cpu(s): 23.4 us, 9.5 sy, 0.0 ni, 65.5 id, 0.7 wa, 0.0 hi, 1.0 si, 0.0 st

CPU利用率拆分成了更細(xì)粒度的幾部分

  • us, sys, ni - 對應(yīng)un-niced user, kernel, niced user的CPU利用率。
  • id, wa - 對應(yīng)到idle, io wait的比例, io wait本質(zhì)上也是一種idle, 區(qū)別在于對應(yīng)cpu上有等待io的任務(wù)
  • hi, si - 對應(yīng)hardirq, softirq的比例。
  • st - 因為超賣等原因, hypervisor從該vm偷走的時間 (todo: docker)

繼續(xù)看load average, 3個數(shù)值分別對應(yīng)到系統(tǒng)1/5/15分鐘內(nèi)的系統(tǒng)平均load, load是個比較模糊的概念, 可以簡單認(rèn)為是對資源有需求的任務(wù)數(shù), 包括on cpu, runnable的任務(wù), 也包括等待IO及任意D狀態(tài)的任務(wù). load使用采樣的方式, 每隔5秒采樣一樣, 越近的采樣權(quán)重越大, 這樣從1/5/15的趨勢可以看出系統(tǒng)壓力的變化。

load average: 433.52, 422.54, 438.70

在這臺128個CPU的機(jī)器上, loadavg看起來有些偏高, 但是具體影響目前不得而知, 性能低是相對具體目標(biāo)而言的, load高只是現(xiàn)象, 它可能相關(guān)也可能無關(guān), 但至少是值得注意的。

再看下dstat關(guān)于任務(wù)狀態(tài)的統(tǒng)計

  • run - 對應(yīng)到/proc/stat里面的procs_running, 也就是runnable任務(wù)數(shù)
  • blk - 對應(yīng)到/proc/stat里面的procs_blocked, 阻塞在I/O的任務(wù)數(shù)。

實際上和loadavg沒有本質(zhì)區(qū)別, 只是load模糊了runnable和D狀態(tài), 同時load使用1/5/15分鐘的力度, 而dstat可以使用更細(xì)粒度, 如果只看某一時間點用load, 如果要觀察長時間的變化使用dstat (/proc/stat)。

#dstat -tp
----system---- ---procs---
time |run blk new
07-03 17:56:50|204 1.0 202
07-03 17:56:51|212 0 238
07-03 17:56:52|346 1.0 266
07-03 17:56:53|279 5.0 262
07-03 17:56:54|435 7.0 177
07-03 17:56:55|442 3.0 251
07-03 17:56:56|792 8.0 419
07-03 17:56:57|504 16 152
07-03 17:56:58|547 3.0 156
07-03 17:56:59|606 2.0 212
07-03 17:57:00|770 0 186

內(nèi)存

這里主要關(guān)注內(nèi)存容量方面, 不關(guān)注訪存的性能。

  • Utilization. 內(nèi)存利用率。
  • Saturation. 這里主要考察內(nèi)存回收算法的效率

簡單的內(nèi)存利用率用free命令

  • total - MemTotal + SwapTotal, 一般來說MemTotal會略小于真實的物理內(nèi)存。
  • free - 未使用的內(nèi)存. Linux傾向于緩存更多頁面以提高性能, 所以不能簡通過free來判斷內(nèi)存是否不足。
  • buff/cache - 系統(tǒng)緩存, 一般不需要嚴(yán)格區(qū)分buffer和cache。
  • available - 估計的可用物理內(nèi)存大小。
  • used - 等于total - free - buffers - cache。
  • Swap - 該機(jī)器上未配置。
#free -g
total used free shared buff/cache available
Mem: 503 193 7 2 301 301
Swap: 0 0 0

更詳細(xì)的信息可以直接去讀/proc/meminfo

#cat /proc/meminfo
MemTotal: 527624224 kB
MemFree: 8177852 kB
MemAvailable: 316023388 kB
Buffers: 23920716 kB
Cached: 275403332 kB
SwapCached: 0 kB
Active: 59079772 kB
Inactive: 431064908 kB
Active(anon): 1593580 kB
Inactive(anon): 191649352 kB
Active(file): 57486192 kB
Inactive(file): 239415556 kB
Unevictable: 249700 kB
Mlocked: 249700 kB
SwapTotal: 0 kB
SwapFree: 0 kB
[...]

再來看下內(nèi)存回收相關(guān)的信息, sar的數(shù)據(jù)主要從/proc/vmstat采集, 主要關(guān)注

  • pgscank/pgscand - 分別對應(yīng)kswapd/direct內(nèi)存回收時掃描的page數(shù)。
  • pgsteal - 回收的page數(shù)。
  • %vmeff - pgsteal/(pgscank+pgscand)

要理解這些數(shù)據(jù)的具體含義, 需要對內(nèi)存管理算法有一定了解, 比如這里的pgscan/pgsteal只是針對inactive list而言的, 在內(nèi)存回收的時候可能還需要先把頁面從active list搬到inactive list等. 如果這里有異常, 我們可以先把這當(dāng)成入口, 再慢慢深入, 具體到這里的%vmeff, 最好情況就是每個掃描的page都能回收, 也就是vmeff越高越好。

#sar -B 1

11:00:16 AM pgscank/s pgscand/s pgsteal/s %vmeff
11:00:17 AM 0.00 0.00 3591.00 0.00
11:00:18 AM 0.00 0.00 10313.00 0.00
11:00:19 AM 0.00 0.00 8452.00 0.00

I/O

存儲I/O的USE模型

  • Utilization. 存儲設(shè)備的利用率, 單位時間內(nèi)設(shè)備在處理I/O請求的時間。
  • Saturation. 隊列長度。

我們一般關(guān)注這些部分

  • %util - 利用率. 注意即使達(dá)到100%的util, 也不代表設(shè)備沒有性能余量了, 特別地現(xiàn)在的SSD盤內(nèi)部都支持并發(fā). 打個比方, 一家旅館有10間房, 每天只要有1個房間入住, util就是100%。
  • svctm - 新版iostat已經(jīng)刪掉。
  • await/r_await/w_await - I/O延遲, 包括排隊時間
  • avgrq-sz - 平均request size, 請求處理時間和大小有一定關(guān)系, 不一定線性。
  • argqu-sz - 評估queue size, 可以用來判斷是否有積壓。
  • rMB/s, wMB/s, r/s, w/s - 基本語義。

資源粒度

當(dāng)我們判斷資源是否是瓶頸的時候, 只看系統(tǒng)級別的資源是不夠的, 比如可以用htop看下每個CPU的利用率, 目標(biāo)任務(wù)運行在不同CPU上的性能可能相差很大。

內(nèi)存也有類似情況, 運行numastat -m。

                          Node 0          Node 1          Node 2          Node 3
--------------- --------------- --------------- ---------------
MemTotal 31511.92 32255.18 32255.18 32255.18
MemFree 2738.79 131.89 806.50 10352.02
MemUsed 28773.12 32123.29 31448.69 21903.16
Active 7580.58 419.80 9597.45 5780.64
Inactive 17081.27 26844.28 19806.99 13504.79
Active(anon) 6.63 0.93 2.08 5.64
Inactive(anon) 12635.75 25560.53 12754.29 9053.80
Active(file) 7573.95 418.87 9595.37 5775.00
Inactive(file) 4445.52 1283.75 7052.70 4450.98

系統(tǒng)不一定就是物理機(jī), 如果產(chǎn)品跑在cgroup, 那么這個cgroup是更需要關(guān)注的系統(tǒng), 比如在空閑系統(tǒng)上執(zhí)行如下命令

#mkdir /sys/fs/cgroup/cpuset/overloaded
#echo 0-1 > /sys/fs/cgroup/cpuset/cpuset.cpus
#echo 0 > /sys/fs/cgroup/cpuset/cpuset.mems
#echo $$
#for i in {0..1023}; do /tmp/busy & done

此時從物理機(jī)級別看, 系統(tǒng)的load很高, 但是因為cpuset的限制, 競爭約束在cpu 0和1上, 對運行在其他cpu上的產(chǎn)品影響并不大。

#uptime
14:10:54 up 6 days, 18:52, 10 users, load average: 920.92, 411.61, 166.95

2.應(yīng)用角度

系統(tǒng)資源和應(yīng)用的性能可能會有某種關(guān)聯(lián), 但是也可以更直接地從應(yīng)用的角度出發(fā)定位問題

  • 應(yīng)用能使用多少資源, 而不是系統(tǒng)提供了多少資源, 這里面可能會有g(shù)ap, 系統(tǒng)是個模糊的概念, 而應(yīng)用本身卻相對具體. 以上面cpuset為例, 物理機(jī)是個系統(tǒng)cpuset管理的資源也可以成為系統(tǒng), 但是應(yīng)用在cpuset里面還是外面是確定的。
  • 應(yīng)用對資源的需求, 即使系統(tǒng)資源再多, 應(yīng)用用不上性能也上不去, 也就是系統(tǒng)可能沒問題, 而是應(yīng)用本身的原因。

以下面的myserv為例, 它的4個線程%cpu都達(dá)到了100, 這個時候再去分析整個系統(tǒng)的load什么用處不大, 系統(tǒng)有再多的空閑cpu對myserv來說已經(jīng)沒有意義。

#pidstat -p `pgrep myserv` -t 1
15:47:05 UID TGID TID %usr %system %guest %CPU CPU Command
15:47:06 0 71942 - 415.00 0.00 0.00 415.00 22 myserv
15:47:06 0 - 71942 0.00 0.00 0.00 0.00 22 |__myserv
...
15:47:06 0 - 72079 7.00 94.00 0.00 101.00 21 |__myserv
15:47:06 0 - 72080 10.00 90.00 0.00 100.00 19 |__myserv
15:47:06 0 - 72081 9.00 91.00 0.00 100.00 35 |__myserv
15:47:06 0 - 72082 5.00 95.00 0.00 100.00 29 |__myserv

3.常用命令

基本命令

基本命令一般用來讀取內(nèi)核中記錄的各種統(tǒng)計信息, 特別是/proc下面的各種文件, 這里簡單列舉部分

  • top - 提供了交互模式和batch模式, 不帶參數(shù)進(jìn)入交互模式, 按下h鍵可以看到各種功能
  • ps - 提供了各種參數(shù)查看系統(tǒng)中任務(wù)的狀態(tài), 比如ps aux或者ps -eLf, 很多參數(shù)可以在需要的時候查看手冊。
  • free - 內(nèi)存信息
  • iostat - I/O性能。
  • pidstat - 查看進(jìn)程相關(guān)的信息, 上面已經(jīng)介紹過
  • mpstat - 可以查看單獨cpu的利用率, softirq, hardirq個數(shù)等。
  • vmstat - 可以查看虛擬內(nèi)存及各種系統(tǒng)信息。
  • netstat - 網(wǎng)絡(luò)相關(guān)
  • dstat - 可以查看cpu/disk/mem/net等各種信息, 這些stat命令哪個方便用哪個。
  • htop - 上面介紹過
  • irqstat - 方便觀察中斷信息。
  • sar/tsar/ssar - 收集和查看系統(tǒng)運行的各種歷史信息, 也提供實時模式。

這里舉個ps的例子, 我們監(jiān)控mysqld服務(wù), 當(dāng)該進(jìn)程使用的內(nèi)存超過系統(tǒng)內(nèi)存70%的時候, 通過gdb調(diào)用jemalloc的malloc_stats_print函數(shù)來分析可能的內(nèi)存泄漏。

largest=70

while :; do
mem=$(ps -p `pidof mysqld` -o %mem | tail -1)
imem=$(printf %.0f $mem)
if [ $imem -gt $largest ]; then
echo 'p malloc_stats_print(0,0,0)' | gdb --quiet -nx -p `pidof mysqld`
fi
sleep 10
done

perf

perf是性能分析的必備工具, 它最核心的能力是能訪問硬件上的Performance Monitor Unit (PMU), 對分析CPU bound的問題很有幫助, 當(dāng)然perf也支持各種軟件event. perf的主要能力包括

  • 通過采樣發(fā)現(xiàn)程序熱點。
  • 通過硬件PMU深入分析問題的根源, 特別是配合硬件上的優(yōu)化。

perf list可以列出支持的event, 我們可以通過perf來獲取cache misses, cycles等等。

#perf list | grep Hardware
branch-misses [Hardware event]
bus-cycles [Hardware event]
cache-misses [Hardware event]
cache-references [Hardware event]
cpu-cycles OR cycles [Hardware event]
instructions [Hardware event]
L1-dcache-load-misses [Hardware cache event]
L1-dcache-loads [Hardware cache event]
L1-dcache-store-misses [Hardware cache event]
L1-dcache-stores [Hardware cache event]
L1-icache-load-misses [Hardware cache event]
L1-icache-loads [Hardware cache event]
branch-load-misses [Hardware cache event]
branch-loads [Hardware cache event]
dTLB-load-misses [Hardware cache event]
iTLB-load-misses [Hardware cache event]
mem:<addr>[/len][:access] [Hardware breakpoint]

perf使用的時候一般會傳入以下參數(shù)

  • 通過-e指定感興趣的一個或多個event。
  • 指定采樣的范圍, 比如進(jìn)程級別 (-p), 線程級別 (-t), cpu級別 (-C), 系統(tǒng)級別 (-a)。

這里使用默認(rèn)的event看下進(jìn)程31925的執(zhí)行情況. 一個比較重要的信息是insns per cycle (IPC), 也就是每個cycle能執(zhí)行多少指令, 其他pmu event像cache misses, branch misses如果有問題最終都會反映到IPC上. 雖然沒有一個明確的標(biāo)準(zhǔn), 但是下面0.09的IPC是比較低的, 有必要繼續(xù)深入。

#perf stat -p 31925  sleep 1

Performance counter stats for process id '31925':

2184.986720 task-clock (msec) # 2.180 CPUs utilized
3,210 context-switches # 0.001 M/sec
345 cpu-migrations # 0.158 K/sec
0 page-faults # 0.000 K/sec
4,311,798,055 cycles # 1.973 GHz
<not supported> stalled-cycles-frontend
<not supported> stalled-cycles-backend
409,465,681 instructions # 0.09 insns per cycle
<not supported> branches
8,680,257 branch-misses # 0.00% of all branches

1.002506001 seconds time elapsed

除了stat外, perf另一個可能更常用的方式是采樣來確定程序的熱點, 現(xiàn)在有如下程序

void busy(long us) {
struct timeval tv1, tv2;
long delta = 0;
gettimeofday(&tv1, NULL);
do {
gettimeofday(&tv2, NULL);
delta = (tv2.tv_sec - tv1.tv_sec) * 1000000 + tv2.tv_usec - tv1.tv_usec;
} while (delta < us);
}

void A() { busy(2000); }
void B() { busy(8000); }

int main() {
while (1) {
A(); B();
}
return 0;
}

函數(shù)A和B執(zhí)行時間的比例, perf的采樣結(jié)果和我們期望的2:8基本一致。

#perf record -g -e cycles ./a.out
#perf report
Samples: 27K of event 'cycles', Event count (approx.): 14381317911
Children Self Command Shared Object Symbol
+ 99.99% 0.00% a.out [unknown] [.] 0x0000fffffb925137
+ 99.99% 0.00% a.out a.out [.] _start
+ 99.99% 0.00% a.out libc-2.17.so [.] __libc_start_main
+ 99.99% 0.00% a.out a.out [.] main
+ 99.06% 25.95% a.out a.out [.] busy
+ 79.98% 0.00% a.out a.out [.] B
- 71.31% 71.31% a.out [vdso] [.] __kernel_gettimeofday
__kernel_gettimeofday
- busy
+ 79.84% B
+ 20.16% A
+ 20.01% 0.00% a.out a.out [.] A

strace

trace相對于采樣最大的優(yōu)勢在于精度, trace能抓住每次操作, 這給調(diào)試和理解帶來很大方便. strace專門用來trace系統(tǒng)調(diào)用。

strace通過捕獲所有的系統(tǒng)調(diào)用能快速幫助理解應(yīng)用的某些行為, 這里使用strace來看下上面提到的perf-record的實現(xiàn), 很容易發(fā)現(xiàn)系統(tǒng)調(diào)用perf_event_open以及它的參數(shù), 因為有128個cpu, 針對每個cpu都會調(diào)用一次該系統(tǒng)調(diào)用。

#strace -v perf record -g -e cycles ./a.out
perf_event_open({type=PERF_TYPE_HARDWARE, size=PERF_ATTR_SIZE_VER5, config=PERF_COUNT_HW_CPU_CYCLES, sample_freq=4000, sample_type=PERF_SAMPLE_IP|PERF_SAMPLE_TID|PERF_SAMPLE_TIME|PERF_SAMPLE_CALLCHAIN|PERF_SAMPLE_PERIOD, read_format=0, disabled=1, inherit=1, pinned=0, exclusive=0, exclusive_user=0, exclude_kernel=0, exclude_hv=0, exclude_idle=0, mmap=1, comm=1, freq=1, inherit_stat=0, enable_on_exec=1, task=1, watermark=0, precise_ip=0 /* arbitrary skid */, mmap_data=0, sample_id_all=1, exclude_host=0, exclude_guest=1, exclude_callchain_kernel=0, exclude_callchain_user=0, mmap2=1, comm_exec=1, use_clockid=0, context_switch=0, write_backward=0, namespaces=0, wakeup_events=0, config1=0, config2=0, sample_regs_user=0, sample_regs_intr=0, aux_watermark=0, sample_max_stack=0}, 51876, 25, -1, PERF_FLAG_FD_CLOEXEC) = 30

blktrace

iostat因為粒度太粗有的時候并不能很好地定位問題, blktrace通過跟蹤每個I/O, 并在I/O的關(guān)鍵路徑打樁, 可以獲得更精確的信息, 從而幫忙分析問題. blktrace封裝了幾個命令:

  • blktrace: 收集。
  • blkparse: 處理
  • btt: 強(qiáng)大的分析工具。
  • btrace: blktrace/blkparse的一個簡單封裝, 相當(dāng)于blktrace -d /dev/sda -o - | blkparse -i 。

簡單看下blktrace的輸出, 里面記錄了I/O路徑上的關(guān)鍵信息, 特別地

  • 時間戳, 性能分析的關(guān)鍵信息之一
  • event, 第6列, 對應(yīng)到I/O路徑上的關(guān)鍵點, 具體對應(yīng)關(guān)系可以查找相應(yīng)手冊或源碼, 理解這些關(guān)鍵點是調(diào)試I/O性能的必要技能。
  • I/O sector. I/O請求對應(yīng)的扇區(qū)和大小。
$ sudo btrace /dev/sda
8,0 0 1 0.000000000 1024 A WS 302266328 + 8 <- (8,5) 79435736
8,0 0 2 0.000001654 1024 Q WS 302266328 + 8 [jbd2/sda5-8]
8,0 0 3 0.000010042 1024 G WS 302266328 + 8 [jbd2/sda5-8]
8,0 0 4 0.000011605 1024 P N [jbd2/sda5-8]
8,0 0 5 0.000014993 1024 I WS 302266328 + 8 [jbd2/sda5-8]
8,0 0 0 0.000018026 0 m N cfq1024SN / insert_request
8,0 0 0 0.000019598 0 m N cfq1024SN / add_to_rr
8,0 0 6 0.000022546 1024 U N [jbd2/sda5-8] 1

這是btt的一個輸出, 可以看到S2G的個數(shù)和延遲, 正常情況不應(yīng)該出現(xiàn)這個問題, 這樣就找到了一條可以深入的線索。

$ sudo blktrace -d /dev/sdb -w 5
$ blkparse sdb -d sdb.bin
$ btt -i sdb.bin
==================== All Devices ====================

ALL MIN AVG MAX N
--------------- ------------- ------------- ------------- -----------

Q2Q 0.000000001 0.000014397 0.008275391 347303
Q2G 0.000000499 0.000071615 0.010518692 347298
S2G 0.000128160 0.002107990 0.010517875 11512
G2I 0.000000600 0.000001570 0.000040010 347298
I2D 0.000000395 0.000000929 0.000003743 347298
D2C 0.000116199 0.000144157 0.008443855 347288
Q2C 0.000118211 0.000218273 0.010678657 347288

==================== Device Overhead ====================

DEV | Q2G G2I Q2M I2D D2C
---------- | --------- --------- --------- --------- ---------
( 8, 16) | 32.8106% 0.7191% 0.0000% 0.4256% 66.0447%
---------- | --------- --------- --------- --------- ---------
Overall | 32.8106% 0.7191% 0.0000% 0.4256% 66.0447%

二、進(jìn)階篇

1.大學(xué)教材

通過教程能夠系統(tǒng)地了解一門課的全貌, 網(wǎng)上搜到的大部分性能分析的教程都是基于Raj Jain的The Art of Computer Systems Performance Analysis, 這本書里面主要包括幾個部分

  • Part I: AN OVERVIEW OF PERFORMANCE EVALUATION.
  • Part II: MEASUREMENT TECHNIQUES AND TOOLS.
  • Part III: PROBABILITY THEORY AND STATISTICS.
  • Part IV: EXPERIMENTAL DESIGN AND ANALYSIS.
  • Part V: SIMULATION.
  • Part VI: QUEUEING MODELS.

書的重心放在performance analysis上面, 涉及較多概率和統(tǒng)計的計算, 另外rice大學(xué)的這個教程寫得挺不錯[1]。

2.技術(shù)博客

  • 參考文末[2]有時間可以都過一遍, 總的來說主要包括3個部分

性能分析的方法集. 代表作 USE方法。

性能數(shù)據(jù)的搜集. 代表作 "工具大圖"。

性能數(shù)據(jù)的可視化. 代表作 火焰圖。

  • 文末鏈接[3]
  • 文末鏈接[4]
  • 文末鏈接[5]

3.知識結(jié)構(gòu)

系統(tǒng)性能分析在深度和廣度上都有要求, 對底層包括OS和硬件, 以及一些通用能力要做到足夠深, 對上層產(chǎn)品的理解又需要有足夠的廣度, 近一年在混合云親手摸過的產(chǎn)品估計不下二十款, 當(dāng)然重點分析過的只有幾個。

操作系統(tǒng)

操作系統(tǒng)是系統(tǒng)分析的基礎(chǔ), 不管是I/O, 內(nèi)存, 網(wǎng)絡(luò), 調(diào)度, docker等等都離不開操作系統(tǒng), 操作系統(tǒng)知識可以從Understanding the Linux Kernel開始, 這本書雖然老了但不妨礙理解OS的基本概念, 慢慢做到能閱讀內(nèi)核文檔和源碼。

在適配某款arm平臺的時候發(fā)現(xiàn), 在numa off的情況下

  • ecs綁在socket 0上性能好;
  • mysql綁在socket 1上性能好

能確定的是, 該平臺跨socket性能訪問不管是latency還是throughput和本地訪問都有較大差距, 所以一個合理的方向是跨socket的內(nèi)存訪問, 如果有類似x86 pcm的話會比較直接, 但是該平臺上缺少該類pmu來查看跨socket的信息, 我們嘗試從OS的角度來回答這個問題。

首先通過將內(nèi)存壓測工具跑在不同的socket/node上, 發(fā)現(xiàn)numa off表現(xiàn)出了和numa on相同的性能特征, 和硬件產(chǎn)生確認(rèn)該平臺numa off和on的實現(xiàn)在硬件上并沒有區(qū)別, 只是bios不傳遞numa信息給操作系統(tǒng), 這樣是可以知道物理地址在哪個socket/node上的。

接下來只要確定ecs/mysql的物理內(nèi)存位置, 就可以用于判斷性能和跨socket的相關(guān)性. Linux在用戶態(tài)可以通過pagemap將虛擬地址對應(yīng)到物理地址, 只需要稍加修改tools/vm/page-types.c就能拿到進(jìn)程對應(yīng)的所有物理地址. 經(jīng)確認(rèn), 確實ecs/mysql的性能和它們使用的物理內(nèi)存的位置強(qiáng)相關(guān)。

最后要回答的是為什么ecs和mysql表現(xiàn)恰好相反, 注意到ecs使用hugepage而mysql使用normal page, 有如下假設(shè), 具體代碼這里不再列出。

  • 系統(tǒng)啟動的時候, 物理內(nèi)存加到伙伴系統(tǒng)是先socket 0后socket 1
  • socket 1上的內(nèi)存會被先分出來, 所以mysql分配的內(nèi)存在socket 1. 特定集群的機(jī)器不會隨意跑其他進(jìn)程。
  • 在ecs的host上, 因為要分配的hugepage已經(jīng)超過了socket 1上的所有內(nèi)存, 所以后面分配的hugepage已經(jīng)落在了socket 0。
  • hugepage的分配是后進(jìn)先出, 意味著ecs一開始分配到的hugepage在socket 0, 而該機(jī)器資源并沒全部用完, 測試用的幾個ecs內(nèi)存全落在了socket 0上, 所以將ecs進(jìn)程綁到socket 0的性能更好

硬件知識

如果一直是x86架構(gòu), 事情會簡單很多, 一是x86的知識大家耳濡目染很久了, 多多少少都了解一些, 二是架構(gòu)變化相對較小, 各種應(yīng)用都適配較好, 需要調(diào)優(yōu)的用例較少. 隨著各種新平臺的崛起, 它們性能各異, 對整個系統(tǒng)性能帶來的沖擊是巨大的, 這不是影響某個產(chǎn)品, 這影響的幾乎是所有產(chǎn)品. 最基本地, 我們要處理以下問題

  • 新的平臺上, 應(yīng)用原有的很多假設(shè)被打破, 需要重新適配, 否則性能可能不及預(yù)期. 比如在Intel上面, 開關(guān)numa的性能差距不大,在其他平臺上可能就不一樣
  • 新的平臺要取代老的平臺, 就存在性能的比較. 由于平臺性能差異大并且差異點多,雖然speccpu之類的benchmark能一定程度反應(yīng)平臺整體的計算性能, 但很多時候還需要結(jié)合不同場景分別進(jìn)行性能調(diào)優(yōu)
  • 不排除新平臺存在某種bug或者未知的feature, 都需要我們?nèi)ッ鹘鉀Q的辦法。

數(shù)據(jù)分析

在收集了大量數(shù)據(jù)后, 經(jīng)過數(shù)據(jù)分析可以放大數(shù)據(jù)的價值

  • 數(shù)據(jù)提取. 利用各種工具比如awk/sed/perl等腳本語言提取所需的數(shù)據(jù)。
  • 數(shù)據(jù)抽象. 從不同角度加工數(shù)據(jù), 識別異常, 比如單機(jī)/集群分別是什么表現(xiàn), 統(tǒng)計哪些值
  • 可視化. 可視化是數(shù)據(jù)處理非常重要的能力, 一圖勝千言, 火焰圖就是最好的例子. 常用畫圖工具有g(shù)nuplot, excel等。

比如分析MapReduce任務(wù)在10臺機(jī)器的集群上的性能, 即使每臺機(jī)器都體現(xiàn)出一定的共性, 但是如果從集群角度看的話則更加明顯, 也很容易驗證這種共性。

換種顯示方式則更加明顯, 很容易知道在不同階段的表現(xiàn), 比如正常Map和Reduce階段cpu利用率也只有80%, 這個是否符合預(yù)期, 另外在Map和Reduce切換的時候, 系統(tǒng)idle很明顯, 會不會是潛在優(yōu)化點。

如果有對照的話, 可以直觀地看不到不同表現(xiàn), 特別是巨大的長尾時間有進(jìn)一步優(yōu)化的空間。

Benchmarking

Benchmarking是獲取性能指標(biāo)最基本的手段, 也是測試常用的方法, 每個領(lǐng)域幾乎都有自己的一套測試用例. 對于benchmarking, 首先需要知道它測的是什么. 以spec cpu2017為例, 它主要測試的是處理器, 內(nèi)存子系統(tǒng)以及編譯器的性能, 那么在測試的時候我們除了關(guān)注CPU型號, 還要考慮內(nèi)存大小插法型號, 以及編譯器及其參數(shù)等等, 在做性能比對時也能清楚它的使用范圍。

Benchmark的一個特點是可重復(fù)性, spec.org做得很好的一點是上面有大量公布的測試結(jié)果, 可以參考這些測試結(jié)果來驗證我們自己的測試方法參數(shù)是否合理. 如果想測試cpu2017, 第一件事就是先重做別人的測試, 直到能復(fù)現(xiàn)別人的數(shù)據(jù), 這個過程可能會有很多收獲, 對benchmark也會有更多了解. 以intel 8160為例, 在硬件基本一致的情況下, 不經(jīng)額外的配置自己環(huán)境cpu2017 integer rate只能跑到140, 而spec.org上面的測試用例能達(dá)到240, 性能逐步逼近240的過程, 也是深入理解cpu2017的過程。

關(guān)于性能數(shù)據(jù), 首先想要強(qiáng)調(diào)的是有數(shù)據(jù)并不一定比沒數(shù)據(jù)強(qiáng), 只有解釋過的數(shù)據(jù)才是有效數(shù)據(jù), 沒解釋過的數(shù)據(jù)反而會引起不必要的誤判, 比如上面cpu2017的例子, 在做不同平臺性能對比的時候, 8160到底用140還是240呢, 得出的結(jié)論會十萬八千里. 再比如使用下面的命令測試某新平臺的內(nèi)存延遲

lat_mem_rd -P 1 -N 1 10240 512

測試出的延遲是7.4ns, 不加分析采用該結(jié)果就可能得出新平臺延遲太好的錯誤結(jié)論. 所以對待數(shù)據(jù)要足夠謹(jǐn)慎, 一般會有幾個階段

  • 在信任關(guān)系建立前, 對別人的數(shù)據(jù)保持謹(jǐn)慎. 一是有可能自己對這塊還沒有足夠理解, 二是需要測試報告提供足夠的信息供他人做判斷。
  • 相信自己的數(shù)據(jù). 必須相信自己, 但是選擇相信自己的數(shù)據(jù), 是因為有過詳細(xì)合理的分析。
  • 相信別人的數(shù)據(jù). 信任鏈建立之后, 以及自己有了足夠理解后, 選擇相信。

4.更多工具

ftrace

想要快速理解代碼實現(xiàn), 沒有什么比打印調(diào)用路徑更直接了. ftrace可以用來解決2個問題

  • 誰調(diào)用了我. 這個只要在執(zhí)行對應(yīng)函數(shù)的時候拿到對應(yīng)的棧就可以, 多種工具可以實現(xiàn);
  • 我調(diào)用了誰. 這個是ftrace比較unique的功能。

為了方便我們使用ftrace的wrapper trace-cmd, 假設(shè)我們已經(jīng)知道I/O路徑會經(jīng)過generic_make_request, 為了查看完整的路徑我們可以這樣

#trace-cmd record -p function --func-stack -l generic_make_request dd if=/dev/zero of=file bs=4k count=1 oflag=direct

通過report來查看就一目了然了

#trace-cmd report
cpus=128
dd-11344 [104] 4148325.319997: function: generic_make_request
dd-11344 [104] 4148325.320002: kernel_stack: <stack trace>
=> ftrace_graph_call (ffff00000809849c)
=> generic_make_request (ffff000008445b80)
=> submit_bio (ffff000008445f00)
=> __blockdev_direct_IO (ffff00000835a0a8)
=> ext4_direct_IO_write (ffff000001615ff8)
=> ext4_direct_IO (ffff0000016164c4)
=> generic_file_direct_write (ffff00000825c4e0)
=> __generic_file_write_iter (ffff00000825c684)
=> ext4_file_write_iter (ffff0000016013b8)
=> __vfs_write (ffff00000830c308)
=> vfs_write (ffff00000830c564)
=> ksys_write (ffff00000830c884)
=> __arm64_sys_write (ffff00000830c918)
=> el0_svc_common (ffff000008095f38)
=> el0_svc_handler (ffff0000080960b0)
=> el0_svc (ffff000008084088)

現(xiàn)在如果我們想繼續(xù)深入generic_make_request, 使用function_graph plugin

$ sudo trace-cmd record -p function_graph -g generic_make_request dd if=/dev/zero of=file bs=4k count=1 oflag=direct

這樣就可以拿到整個調(diào)用過程 (report結(jié)果稍微整理過)

$ trace-cmd report
dd-22961 | generic_make_request() {
dd-22961 | generic_make_request_checks() {
dd-22961 0.080 us | _cond_resched();
dd-22961 | create_task_io_context() {
dd-22961 0.485 us | kmem_cache_alloc_node();
dd-22961 0.042 us | _raw_spin_lock();
dd-22961 0.039 us | _raw_spin_unlock();
dd-22961 1.820 us | }
dd-22961 | blk_throtl_bio() {
dd-22961 0.302 us | throtl_update_dispatch_stats();
dd-22961 1.748 us | }
dd-22961 6.110 us | }
dd-22961 | blk_queue_bio() {
dd-22961 0.491 us | blk_queue_split();
dd-22961 0.299 us | blk_queue_bounce();
dd-22961 0.200 us | bio_integrity_enabled();
dd-22961 0.183 us | blk_attempt_plug_merge();
dd-22961 0.042 us | _raw_spin_lock_irq();
dd-22961 | elv_merge() {
dd-22961 0.176 us | elv_rqhash_find.isra.9();
dd-22961 | deadline_merge() {
dd-22961 0.108 us | elv_rb_find();
dd-22961 0.852 us | }
dd-22961 2.229 us | }
dd-22961 | get_request() {
dd-22961 0.130 us | elv_may_queue();
dd-22961 | mempool_alloc() {
dd-22961 0.040 us | _cond_resched();
dd-22961 | mempool_alloc_slab() {
dd-22961 0.395 us | kmem_cache_alloc();
dd-22961 0.744 us | }
dd-22961 1.650 us | }
dd-22961 0.334 us | blk_rq_init();
dd-22961 0.055 us | elv_set_request();
dd-22961 4.565 us | }
dd-22961 | init_request_from_bio() {
dd-22961 | blk_rq_bio_prep() {
dd-22961 | blk_recount_segments() {
dd-22961 0.222 us | __blk_recalc_rq_segments();
dd-22961 0.653 us | }
dd-22961 1.141 us | }
dd-22961 1.620 us | }
dd-22961 | blk_account_io_start() {
dd-22961 0.137 us | disk_map_sector_rcu();
dd-22961 | part_round_stats() {
dd-22961 0.195 us | part_round_stats_single();
dd-22961 0.054 us | part_round_stats_single();
dd-22961 0.955 us | }
dd-22961 2.148 us | }
dd-22961 + 15.847 us | }
dd-22961 + 23.642 us | }

uftrace

uftrace在用戶態(tài)實現(xiàn)了一個類似ftrace的功能, 對需要快速理解用戶態(tài)的邏輯會有幫助, 但是需要加上-pg重新編譯源碼, 詳情見[6]。

#gcc -pg a.c
#uftrace ./a.out
# DURATION TID FUNCTION
[ 69439] | main() {
[ 69439] | A() {
0.160 us [ 69439] | busy();
1.080 us [ 69439] | } /* A */
[ 69439] | B() {
0.050 us [ 69439] | busy();
0.240 us [ 69439] | } /* B */
1.720 us [ 69439] | } /* main */

BPF

BPF (eBPF) 是這幾年的熱點, 通過BPF幾乎可以看清系統(tǒng)的各個角落, 給診斷帶來了極大的方便. BPF不是一個工具, BPF是生產(chǎn)工具的工具, BPF工具編寫是性能分析必須掌握的技能之一。

這里舉個使用BPF來分析QEMU I/O延遲的例子. 為了簡化問題, 先確保vm里面的塊設(shè)備只有fio在使用, fio控制設(shè)備只有一個并發(fā)I/O, 這樣我們在host上選擇2個觀察點

  • tracepoint:kvm:kvm_mmio. host捕獲guest mmio操作, guest里面最終通過寫該mmio發(fā)送請求給host;
  • kprobe:kvm_set_msi. 因為guest里面vdb使用msi中斷, 中斷最終通過該函數(shù)注入;

因為host上有多個vm和虛擬盤需要區(qū)分, 使用以下信息捕獲并且只捕獲我們關(guān)注的這個設(shè)備

  • 只關(guān)注該qemu-kvm pid;
  • vbd mmio對應(yīng)的gpa, 這個可以在guest里面通過lspci獲得;

對于kvm_set_msi, 使用如下信息

  • struct kvm的userspace_pid, struct kvm對應(yīng)的qemu-kvm進(jìn)程;
  • struct kvm_kernel_irq_routing_entry的msi.devid, 對應(yīng)到pci設(shè)備id;
#include <linux/kvm_host.h>

BEGIN {
@qemu_pid = $1;
@mmio_start = 0xa000a00000;
@mmio_end = 0xa000a00000 + 16384;
@devid = 1536;
}

tracepoint:kvm:kvm_mmio /pid == @qemu_pid/ {
if (args->gpa >= @mmio_start && args->gpa < @mmio_end) {
@start = nsecs;
}
}

kprobe:kvm_set_msi {
$e = (struct kvm_kernel_irq_routing_entry *)arg0;
$kvm = (struct kvm *)arg1;
if (@start > 0 && $kvm->userspace_pid == @qemu_pid && $e->msi.devid == @devid) {
@dur = stats(nsecs - @start);
@start = 0;
}
}

interval:s:1 {
print(@dur); clear(@dur);
}

執(zhí)行結(jié)果如下

@dur: count 598, average 1606320, total 960579533

@dur: count 543, average 1785906, total 969747196

@dur: count 644, average 1495419, total 963049914

@dur: count 624, average 1546575, total 965062935

@dur: count 645, average 1495250, total 964436299

5.更深理解

很多技術(shù)需要反復(fù)去理解驗證, 每一次可能都有不同的收獲, 這里舉個loadavg的例子. 引用kernel/sched/loadavg.c最開始的一段注釋

5  * This file contains the magic bits required to compute the global loadavg
6 * figure. Its a silly number but people think its important. We go through
7 * great pains to make it work on big machines and tickless kernels.

這里的silly我想說的是loadavg有一定的局限性, 總的來說loadavg是有一定語義和價值的, 畢竟它只用了3個數(shù)字描述了過去一段時間的"load", 反過來說如果loadavg is silly, 那么有沒有更好的選擇?

  • 如果是實時觀察的話, vmstat/dstat輸出的runnable和I/O blocked的信息是種更好的選擇, 因為相對于loadavg每5秒的采樣。 vmstat可以做到粒度更細(xì), 而且loadavg的算法某種程度可以理解為有損的。
  • 如果是sar/tsar的話, 假設(shè)收集間隔是10min的話, loadavg因為能覆蓋更大的范圍, 確實比10min一個的數(shù)字包含更多的信息。 但我們需要思考它對調(diào)試的真正價值。

另外, 5秒鐘的采樣間隔是比較大的, 我們可以構(gòu)造個測試用例執(zhí)行了大量時間但跳過采樣。

  • 獲取load采樣點的時間。
  • 測試用例剛好跳過該采樣點

查看calc_load_fold_active在cpu 0上的調(diào)用時間

kprobe:calc_load_fold_active /cpu == 0/ {
printf("%ld\n", nsecs / 1000000000);
}

運行沒有輸出, 監(jiān)控上一層函數(shù)

#include "kernel/sched/sched.h"
kprobe:calc_global_load_tick /cpu == 0/ {
$rq = (struct rq *)arg0;
@[$rq->calc_load_update] = count();
}

interval:s:5 {
print(@); clear(@);
}

執(zhí)行結(jié)果符合預(yù)期

#./calc_load.bt -I /kernel-source
@[4465886482]: 61
@[4465887733]: 1189

@[4465887733]: 62
@[4465888984]: 1188

查看匯編發(fā)現(xiàn)這里代碼被優(yōu)化, 但是剛好id_nr_invalid調(diào)用沒優(yōu)化, 當(dāng)然最方便的是能夠直接在函數(shù)偏移處直接打點:

kprobe:id_nr_invalid /cpu == 0/ {
printf("%ld\n", nsecs / 1000000000);
}

根據(jù)這個時間戳, 可以很容易跳過load的統(tǒng)計

while :; do
sec=$(awk -F. '{print $1}' /proc/uptime)
rem=$((sec % 5))
if [ $rem -eq 2 ]; then # 1s after updating load
break;
fi
sleep 0.1
done

for i in {0..63}; do
./busy 3 & # run 3s
done

大量busy進(jìn)程成功跳過load的統(tǒng)計, 可以設(shè)想像cron執(zhí)行的任務(wù)也是有這個可能的. 雖然不能否認(rèn)loadavg的價值, 但總的來說load有以下缺陷

  • 系統(tǒng)級別的統(tǒng)計, 和具體應(yīng)用產(chǎn)生的聯(lián)系不夠直接。
  • 使用采樣的方式并且采樣間隔 (5s) 較大, 有的場景不能真實反映系統(tǒng)。
  • 統(tǒng)計的間隔較大(1/5/15分鐘), 不利于及時反映當(dāng)時的情況。
  • 語義稍微不夠清晰, 不只包括cpu的load, 還包括D狀態(tài)的任務(wù), 這個本身不是大問題, 更多可以認(rèn)為是feature。

Linux增加了Pressure Stall Information (PSI), PSI從任務(wù)的角度分別統(tǒng)計了10/60/300s內(nèi)因為cpu/io/memory等資源不足而不能運行的時長, 并按照影響范圍分成2類

  • some - 因為缺少資源導(dǎo)致部分任務(wù)不能執(zhí)行。
  • full - 因為缺少資源導(dǎo)致所有任務(wù)不能執(zhí)行, cpu不存在這種情況。

我們在一臺96c的arm機(jī)器上掃描所有cgroup的cpu.pressure

這里會引出幾個問題, 篇幅原因這里不再展開。

  • 父cgroup的avg為什么比子cgroup還小? 是實現(xiàn)問題還是有額外的配置參數(shù)?
  • avg10等于33, 也就是1/3的時間有task因為沒有cpu而得不到執(zhí)行, 考慮到系統(tǒng)cpu利用率在40%左右并不算高,。 我們怎么合理看待和使用這個值:
top - 09:55:41 up 127 days,  1:44,  1 user,  load average: 111.70, 87.08, 79.41
Tasks: 3685 total, 21 running, 2977 sleeping, 1 stopped, 8 zombie
%Cpu(s): 27.3 us, 8.9 sy, 0.0 ni, 59.8 id, 0.1 wa, 0.0 hi, 4.0 si, 0.0 st

6.RTFSC

有的時候RTFM已經(jīng)不夠了, 手冊包括工具本身的更新沒對上內(nèi)核的節(jié)奏, 我們回到上面頁面回收的例子, 估計有的同學(xué)之前就有疑問, 沒有scan哪里來的steal。

#sar -B 1

11:00:16 AM pgscank/s pgscand/s pgsteal/s %vmeff
11:00:17 AM 0.00 0.00 3591.00 0.00
11:00:18 AM 0.00 0.00 10313.00 0.00
11:00:19 AM 0.00 0.00 8452.00 0.00

先看sysstat (sar) 里面的實現(xiàn), 主要是讀取分析/proc/vmstat

  • pgscand: 對應(yīng)到pgscan_direct域
  • pgscank: 對應(yīng)到pgscan_kswapd域
  • pgsteal: 對應(yīng)到pgsteal_開頭的域。
#gdb --args ./sar -B 1
(gdb) b read_vmstat_paging
(gdb) set follow-fork-mode child
(gdb) r
Breakpoint 1, read_vmstat_paging (st_paging=0x424f40) at rd_stats.c:751
751 if ((fp = fopen(VMSTAT, "r")) == NULL)
(gdb) n
754 st_paging->pgsteal = 0;
(gdb)
757 while (fgets(line, sizeof(line), fp) != NULL) {
(gdb)
759 if (!strncmp(line, "pgpgin ", 7)) {
(gdb)
763 else if (!strncmp(line, "pgpgout ", 8)) {
(gdb)
767 else if (!strncmp(line, "pgfault ", 8)) {
(gdb)
771 else if (!strncmp(line, "pgmajfault ", 11)) {
(gdb)
775 else if (!strncmp(line, "pgfree ", 7)) {
(gdb)
779 else if (!strncmp(line, "pgsteal_", 8)) {
(gdb)
784 else if (!strncmp(line, "pgscan_kswapd", 13)) {
(gdb)
789 else if (!strncmp(line, "pgscan_direct", 13)) {
(gdb)
757 while (fgets(line, sizeof(line), fp) != NULL) {
(gdb)

看下/proc/vmstat都有什么

#grep pgsteal_ /proc/vmstat
pgsteal_kswapd 168563
pgsteal_direct 0
pgsteal_anon 0
pgsteal_file 978205

#grep pgscan_ /proc/vmstat
pgscan_kswapd 204242
pgscan_direct 0
pgscan_direct_throttle 0
pgscan_anon 0
pgscan_file 50583828

最后看看內(nèi)核的實現(xiàn), pgsteal和pgscan的邏輯是一樣, 除了nr_scanned換成了nr_reclaimed

if (current_is_kswapd()) {
if (!cgroup_reclaim(sc))
__count_vm_events(PGSCAN_KSWAPD, nr_scanned);
count_memcg_events(lruvec_memcg(lruvec), PGSCAN_KSWAPD,
nr_scanned);
} else {
if (!cgroup_reclaim(sc))
__count_vm_events(PGSCAN_DIRECT, nr_scanned);
count_memcg_events(lruvec_memcg(lruvec), PGSCAN_DIRECT,
nr_scanned);
}
__count_vm_events(PGSCAN_ANON + file, nr_scanned);

現(xiàn)在問題很清晰了

  • 這里sar取得是系統(tǒng)的/proc/vmstat, 而cgroup里面pgscan_kswapd和pgscan_direct只會加到cgroup的統(tǒng)計,不會加到系統(tǒng)級的統(tǒng)計。
  • cgroup里面pgsteal_kswapd和pgsteal_direct同樣只會加到cgroup自己的統(tǒng)計
  • 但是主要pgscan_anon, pgscan_file和pgsteal_anon, pgsteal_file都只加到系統(tǒng)級的統(tǒng)計。
  • sar讀取了pgscan_kswapd, pgscan_direct, 以及pgsteal_*, 這里*還包括了pgsteal_anon和pgsteal_file。

這整個邏輯都亂了, 我們有必要解決這個bug讓sar的輸出變得更加有意義. 那么在cgroup內(nèi)是不是沒問題?

#df -h .
Filesystem Size Used Avail Use% Mounted on
cgroup 0 0 0 - /sys/fs/cgroup/memory
#grep -c 'pgscan\|pgsteal' memory.stat
0

這些統(tǒng)計信息在cgroup v1上完全沒有輸出, 而只在v2版本有輸出. 在以前內(nèi)核沒有專門LRU_UNEVICTABLE的時候, 如果有很多比如mlock page的時候, 碰到過不停掃描卻不能回收內(nèi)存的情況, 這個統(tǒng)計會非常有用, 即使是現(xiàn)在我相信這個統(tǒng)計還是有用的, 只是大部分時候還不用看到這么細(xì)。

7.多上手

紙上得來終覺淺, 自己動手去做帶來很多好處

  • 回答預(yù)設(shè)問題. 調(diào)試分析就是不斷提出問題和驗證的過程, 沒有上手的話就會一直停留在第一個問題上. 比如我想了解某平臺上物理內(nèi)存是怎么編址的, 沒有文檔的話只能自己去實驗。
  • 提出新的問題. 調(diào)試分析中不怕有問題, 怕的是提不出問題。
  • 會有意外收獲. 很多時候并不是有意為之, 比如準(zhǔn)備的是分析cpu調(diào)頻能否降功耗, 上去卻發(fā)現(xiàn)系統(tǒng)一直運行在最低頻率。
  • 熟練. 熟練就是效率。
  • 改進(jìn)產(chǎn)品. 可以試想下在整個云環(huán)境所有機(jī)器上掃描 (類似全面體檢) 會發(fā)現(xiàn)多少潛在問題。

參考資料

[1]https://www.cs.rice.edu/~johnmc/comp528/lecture-notes/

[2]https://brendangregg.com/。

[3]http://dtrace.org/blogs/bmc/。

[4]https://blog.stgolabs.net/。

[5]https://lwn.net/。

[6]https://github.com/namhyung/uftrace。

[7]https://www.brendangregg.com/

[8]The Art of Computer Systems Performance Analysis。

責(zé)任編輯:武曉燕 來源: 阿里開發(fā)者
相關(guān)推薦

2023-12-26 08:40:06

分類算法數(shù)據(jù)分析Python

2013-03-06 10:24:12

ksar工具系統(tǒng)性能

2021-12-12 18:15:06

Python并發(fā)編程

2013-03-20 17:18:07

Linux系統(tǒng)性能調(diào)優(yōu)

2010-04-23 11:44:34

Aix系統(tǒng)

2009-09-29 10:39:04

Linuxlinux系統(tǒng)性能檢測

2025-02-11 07:40:27

2020-07-07 10:50:19

Python丄則表達(dá)文本

2022-07-15 16:31:49

Postman測試

2024-04-01 08:04:05

JProfilerJVM工具

2024-11-08 14:27:52

系統(tǒng)設(shè)計數(shù)據(jù)庫

2011-03-18 11:13:07

LAMP度量性能

2020-03-02 16:25:03

性能系統(tǒng)軟件

2010-04-09 13:26:44

2022-07-26 10:28:00

Linux監(jiān)控命令

2013-02-28 13:37:59

系統(tǒng)性能調(diào)優(yōu)技術(shù)實戰(zhàn)

2018-01-22 09:08:14

存儲系統(tǒng)性能帶寬

2010-05-24 13:29:30

Swap空間

2011-01-05 13:48:55

Linux提高性能

2015-07-02 13:15:58

評測集中系統(tǒng)性能
點贊
收藏

51CTO技術(shù)棧公眾號