4、IO性能分析工具(下):blktrace/block_dump块层追踪,fio基准测试工具,Systrace/Perfetto抓取IO trace

好,咱们接着聊IO分析工具。上一讲我把几个文件系统层的工具过了一遍,这一讲咱们深入到底层——块设备层。说白了,就是看数据怎么从文件系统出来,经过IO调度器,最后落到磁盘或者闪存上的。这块儿如果出问题,你上层优化做得再好也是白搭。

blktrace:块层的“黑匣子”

blktrace这工具,我个人非常喜欢。它就像块设备层的黑匣子,能把每一个IO请求的完整生命周期记录下来。从IO进入队列,到被调度器合并、分发,再到驱动处理完成,每一步都有时间戳。

我记得有一次线上反馈说某款手机安装应用特别慢。用top看CPU不高,用iostat看磁盘利用率也不高,但就是慢。后来我上了blktrace,才发现问题出在IO调度器上——大量的随机小IO没有被有效合并,导致队列深度一直上不去。

用法其实不复杂:

# 追踪块设备sda
blktrace -d /dev/block/sda -o my_trace

# 等一段时间后,用Ctrl+C停止
# 然后用blkparse解析
blkparse my_trace.blktrace.0 > trace.txt

解析出来的内容长什么样?每一行代表一个IO动作,包含设备号、进程ID、R/W标志、扇区号、大小和时间戳。关键字段我列一下:

动作 含义 我关注的点
Q IO进入队列 看频率,太密集说明上层在狂刷
G IO请求合并 合并率低说明碎片化严重
I IO请求插入调度队列 这里能看到调度策略的影响
D IO请求下发到驱动 从Q到D的延迟,就是调度延迟
C IO完成 从D到C的延迟,就是硬件处理时间
我的小技巧: 用blktrace时,我习惯只追踪感兴趣的进程。加个 -p 参数指定PID,不然系统全局追踪数据量太大,解析起来也慢。

block_dump:轻量级替代方案

blktrace虽然强大,但开销不小。生产环境或者低端设备上,我一般用block_dump。它是个内核参数,开启后会把块层的IO活动打印到内核日志里。

# 开启
echo 1 > /proc/sys/vm/block_dump

# 查看日志
dmesg | grep "block_dump"

# 用完关掉
echo 0 > /proc/sys/vm/block_dump

输出格式大概是这样的:

block_dump: pid(1234) WRITE block 123456 on sda (8 sectors)
block_dump: pid(5678) READ block 789012 on sda (16 sectors)

嗯,这里要注意——block_dump会打印所有进程的块IO活动,日志量可能很大。我曾经在一个测试机上忘了关,跑了半天,结果logcat被撑爆了。所以用完后一定记得关掉。

它适合做什么?快速定位是哪个进程在疯狂写盘。比如你发现手机发烫,怀疑是某个App在后台刷数据,开block_dump看一眼就清楚了。

fio:IO性能的“照妖镜”

fio这工具,做存储性能优化的应该都不陌生。它是个基准测试工具,能模拟各种IO负载。我一般用它来做三件事:测极限吞吐、验证优化效果、复现线上问题。

先看一个典型的测试用例:

# 4K随机写,队列深度32,直接IO
fio --name=randwrite --ioengine=libaio --iodepth=32 \
    --rw=randwrite --bs=4k --direct=1 \
    --size=1G --numjobs=1 --runtime=60 \
    --filename=/data/test.fio

参数解释一下:

  • --direct=1:绕过页缓存,直接测块设备
  • --iodepth:队列深度,这个很关键。深度太低,硬件跑不满;太高,延迟会飙升
  • --rw:读写模式,randwrite/randread/read/write/rw等
关键指标:
  • IOPS:每秒IO次数,随机读写主要看这个
  • 带宽:每秒吞吐量,顺序读写主要看这个
  • 延迟:99分位延迟比平均延迟更有参考价值

我遇到过最典型的一个案例:某款手机UFS规格很高,但实际体验就是卡。用fio一测,发现4K随机读IOPS只有标称值的60%。后来定位到是IO调度器的参数没调好,队列深度被限制死了。调整之后,IOPS直接翻倍。

fio还能输出延迟分布图,这个对分析尾延迟特别有用:

fio --name=test --output-format=json ...

输出JSON格式,然后用脚本解析,能看到各个百分位的延迟。我一般重点关注99.9分位——如果这个值很高,说明有长尾延迟问题。

Systrace/Perfetto:系统级IO trace

最后说一下Systrace和Perfetto。这两个工具大家可能更熟悉,常用于分析UI卡顿。但其实它们也能抓IO trace,关键是要打开对应的标签。

Systrace时代,我一般加这些标签:

systrace.py -t 10 -o trace.html \
    sched freq idle load am wm gfx view \
    binder_driver hal dalvik camera input res \
    **f2fs** **ext4** **block** **mmc**

加粗的那几个就是IO相关的。f2fs/ext4是文件系统层,block是块层,mmc是存储驱动层。三层一起看,能完整还原一个IO请求的路径。

到了Perfetto时代,就更强大了。它支持SQL查询,能精确分析IO事件。比如我想看某个进程的IO延迟分布:

SELECT
  process.name,
  COUNT(*) as io_count,
  AVG(dur) as avg_dur_us,
  MAX(dur) as max_dur_us
FROM
  ftrace_event
WHERE
  name = 'block_rq_complete'
  AND process.name = 'com.android.systemui'
GROUP BY
  process.name
注意: Perfetto抓IO trace时,数据量可能很大。我建议先抓短时间(5-10秒),确认问题能复现再延长。不然一个trace文件几百兆,分析起来也费劲。

用Perfetto看IO trace,我一般关注这几个点:

  • IO提交间隔:如果间隔不均匀,说明上层有抖动
  • IO完成延迟:看有没有异常的尖峰
  • 队列深度变化:深度波动大,说明调度策略有问题

举个例子,有一次我用Perfetto看到,某个App在启动时发起了大量4K随机读,但每个读请求之间间隔了2-3ms。这说明App的IO模型有问题——没有做预读或者批量提交。后来让开发改了代码,启动速度提升了30%。

小结一下

这一讲我们聊了三个工具:

  • blktrace:块层全链路追踪,适合深度分析IO路径
  • block_dump:轻量级监控,适合快速定位问题进程
  • fio:基准测试,适合量化评估和验证优化效果
  • Systrace/Perfetto:系统级trace,适合结合UI性能一起分析

这些工具各有侧重,实际工作中我经常组合使用。先用fio压测看极限性能,再用blktrace分析瓶颈在哪,最后用Perfetto结合上层行为一起看。这样一套组合拳下来,大部分IO性能问题都能定位到根因。

下一讲,咱们聊聊IO性能优化的具体策略。到时候我会分享一些实战案例,包括我踩过的坑和总结的经验。