调试与性能分析
调试与日志
- 程序执行的是写下的代码,不是你的预期
- 最小可复现示例
- 二分注释代码与二分输入
- 在边界打印参数验证假设
print只输出中间状态- 日志级别
DEBUG、INFO、WARN、ERROR - 按级别过滤,运行时开关
- 日志分流到文件、stderr、syslog
- 结构化日志:JSON Lines
- 时间戳与
request_id - 惰性格式化
log.debug("%s", x) - 修完后把
print改成log.debug -v、-vv提高详细度/var/log与journalctl -u- 第三方库的调试环境变量
- LLM 解释报错与崩溃栈
调试器
- 调试器与
print的适用边界 - 不知道打印什么时用调试器
- 启动慢、状态难重建的程序
gdb与lldb调试原生二进制-g生成 DWARF 调试信息run、break、continuestep与nextfinish跑完当前函数print、info localsbt与frame N- 条件断点
break ... if watch观察变量写入gdb -tui与Ctrl-x a- core 文件与
coredumpctl -fno-omit-frame-pointerpdb、debugpy、jdb
记录回放调试
- Heisenbug:一观察就消失
- 加
print后不再复现 - 竞态与时序依赖
- 记录执行,确定性重放
rr record与rr replay- 重放直接进入 GDB
reverse-continue反向运行reverse-step与reverse-nextreverse-finish反向出栈- watchpoint 回追写入
- 仅支持 Linux
- 依赖硬件性能计数器
- 云主机与 GPU 的限制
- 线程调度被序列化
- 多次录制抓间歇失败
- macOS 上的 Warpspeed
系统调用与追踪
- 系统调用是程序与内核的边界
strace ./prog-e trace=file与trace=network-f跟随子进程-p PID附加到运行中进程-T显示单次调用耗时-c汇总次数与时间- 返回值与
errno - macOS 的
dtruss与 SIP - eBPF 与
bpftrace的tracepoint:syscalls:* @[probe] = count()聚合- 按
comm、pid、cpid过滤 bcc的opensnoop、biosnooptcpdump -i any port 80-w存 pcap 交给 Wireshark- HTTPS 用
mitmproxy或浏览器面板
内存错误
- 越界、use-after-free、泄漏
- 错误延迟到远处才崩溃
- Sanitizer 是编译期插桩
-fsanitize=address- ASan 抓堆、栈、全局越界
- ASan 的分配栈与释放栈
-fsanitize=thread抓数据竞争-fsanitize=memory抓未初始化读取-fsanitize=undefined抓未定义行为- ASan 与 TSan 不能同时开
- MSan 需要全量插桩
- Valgrind 无需重编译
--leak-check=fulldefinitely lost与still reachableASAN_OPTIONS=halt_on_error=1- sanitizer 构建进 CI
计时与资源监控
time的 real、user、sys- real 包含等待时间
- 多线程下 user + sys 可超过 real
- real 远大于 CPU 时间说明在等 I/O
/usr/bin/time -vhtop的F6、t、Hiotop看进程级磁盘 I/Ofree -h看availablelsof查打开的文件ss -tlnp查监听端口lsof -i :8080nethogs与iftop- 日志输出
timestamp,valueCSV gnuplot -e直接画线matplotlib与ggplot2分面- 周期性尖峰与 GC 停顿
CPU 性能分析
- 采样 profiler 与追踪 profiler
- 采样开销低,适合生产
- 追踪记录每次调用,精确但慢
perf stat总览硬件计数器insn per cycle与branch-missesperf record -g记录调用栈perf report与perf scriptstackcollapse-perf.pl生成火焰图- 火焰图 X 轴是样本占比
- 火焰图 Y 轴是调用深度
- 颜色无语义,左右不是时间
perf_event_paranoid权限valgrind --tool=callgrindcallgrind_annotate、kcachegrindcProfile、py-spy、pprofcargo flamegraph、taskset
内存分析与基准测试
- Massif 采样堆使用量
valgrind --tool=massifms_print看曲线与快照- 峰值不回落不等于泄漏
memory-profiler逐行分析@profile只在对应模块生效hyperfine多次测量--warmup预热缓存--prepare重置状态--runs与--export-json- 均值、标准差与极值
- 微基准不等于真实负载
- 后台噪声与 CPU 降频
- DevTools Performance 面板
- Firefox Profiler
- 优化后重跑基准
容易混淆的问题
print与 logging 该选哪个- 日志该写 stdout 还是 stderr
gdb断点为什么没停watch与条件断点有什么区别- rr 为什么录不出竞态
strace与bpftrace怎么选- ASan、Valgrind、Massif 分别查什么
user + sys超过real正常吗- 火焰图能看出调用先后顺序吗
- 采样 profiler 会漏掉什么