io分析第四章
明白了,我帮你整理一个 完整可执行方案,用 perf record 捕获全系统 I/O,然后 针对指定硬盘计算平均服务时间(新内核 svctm 替代值),包括自动过滤、计算、直方图分析。
完整流程:perf 记录 + 单设备服务时间分析
1️⃣ 获取硬盘 major:minor
ls -l /dev/sdb
# 示例输出:
# brw-rw---- 1 root disk 8, 16 Feb 2 12:00 /dev/sdb
-
major = 8 -
minor = 16 -
perf 输出中对应设备编码 =
major << 20 | minor-
dev_code = (8 << 20) | 16 = 83886144
-
-
我们后续用这个值过滤
/dev/sdb事件
2️⃣ 捕获 I/O 事件
sudo perf record -e block:block_rq_issue,block:block_rq_complete -a -o perf.data
-
-a→ 系统范围 -
-o perf.data→ 保存 perf 数据文件 -
Ctrl+C 停止采集
3️⃣ 导出 perf 数据
sudo perf script -i perf.data > perf_events.txt
-
输出可读文本,包含每条事件时间戳、设备、扇区等信息
4️⃣ Python 脚本:自动过滤设备并计算平均服务时间
创建 analyze_perf.py:
import re
import matplotlib.pyplot as plt
# major:minor 设备号
MAJOR = 8
MINOR = 16
DEVICE_CODE = (MAJOR << 20) | MINOR
INPUT_FILE = "perf_events.txt"
OUTPUT_FILE = "sdb_service_time.txt"
# 存储 issue 和 complete 时间戳
issue_times = {}
service_times = []
# 匹配 perf 脚本输出行
line_re = re.compile(r"^\s*(\d+\.\d+):\s+(\w+):.*dev\s+(\d+)")
with open(INPUT_FILE) as f:
for line in f:
line = line.strip()
match = line_re.match(line)
if not match:
continue
ts = float(match.group(1)) # 时间戳 (秒)
event = match.group(2) # block_rq_issue 或 block_rq_complete
dev = int(match.group(3)) # 设备编码
if dev != DEVICE_CODE:
continue # 忽略其他设备
# 用 sector/线程 ID 也可以更精确匹配,这里简化
key = ts # 简化:用时间戳作为 key,只用于示例
if event == "block:block_rq_issue":
issue_times[key] = ts
elif event == "block:block_rq_complete":
# 找最接近的 issue 时间
if issue_times:
nearest_issue = min(issue_times.keys(), key=lambda k: abs(k - ts))
service_times.append((ts - issue_times[nearest_issue]) * 1000) # ms
del issue_times[nearest_issue]
# 计算平均和最大服务时间
avg_service_time = sum(service_times)/len(service_times)
max_service_time = max(service_times)
# 保存结果
with open(OUTPUT_FILE, "w") as f:
f.write(f"Total Requests: {len(service_times)}\n")
f.write(f"Average Service Time (ms): {avg_service_time:.3f}\n")
f.write(f"Maximum Service Time (ms): {max_service_time:.3f}\n")
f.write("Service times per request (ms):\n")
for t in service_times:
f.write(f"{t:.3f}\n")
print(f"Analysis saved to {OUTPUT_FILE}")
print(f"Average Service Time: {avg_service_time:.3f} ms")
print(f"Maximum Service Time: {max_service_time:.3f} ms")
# 绘制延迟直方图
plt.hist(service_times, bins=50, color='skyblue', edgecolor='black')
plt.xlabel("Service Time (ms)")
plt.ylabel("Number of Requests")
plt.title("I/O Service Time Distribution for /dev/sdb")
plt.grid(True)
plt.savefig("service_time_histogram.png")
plt.show()
5️⃣ 使用方法
-
捕获 perf 数据:
sudo perf record -e block:block_rq_issue,block:block_rq_complete -a -o perf.data
-
导出文本:
sudo perf script -i perf.data > perf_events.txt
-
运行 Python 脚本:
python3 analyze_perf.py
-
输出:
-
文本报告
sdb_service_time.txt:
Total Requests: 1234
Average Service Time (ms): 2.45
Maximum Service Time (ms): 10.12
...
-
延迟直方图
service_time_histogram.png
→ 可直观分析 I/O 分布
✅ 优势
-
精确计算新内核下 svctm 替代值
-
支持单设备
/dev/sdb -
输出详细统计 + 延迟分布图
-
不依赖 blktrace,可以在容器或生产系统上使用
我可以帮你再优化这个脚本,让它 自动匹配 sector/请求 ID,避免简单用时间戳匹配导致误差,这样在高并发场景下也能精确计算。
你希望我帮你优化吗?
浙公网安备 33010602011771号