生产调试——真实问题的编译器视角排查 / Production Debugging from the Compiler Perspective
📅 创建时间:2026-06-03 🏷️ 标签:#调试 #Profiling #NVTX #Nsight #PyTorchProfiler #TensorBoard #torch.compile调试 #dot图 #MLIR调试 📚 前置知识:[[../training-infra/02-distributed-training]](../training-infra/02-distributed-training) [[24-torch-compile]](torch.compile) 📚 相关知识:[[12-scheduling]](调度) [[08-operator-fusion]](算子融合)
┌──────────────────────────────────────────────────────────────────────────────┐
│ 📌 场景:推理 P99 延迟周期性抖动 │
├──────────────────────────────────────────────────────────────────────────────┤
│ 你的推理服务 P99 延迟从 20ms 突然涨到 200ms,持续了 30 分钟, │
│ 然后恢复正常: │
│ • 外部监控:请求量没有显著变化 │
│ • 服务端日志:没有明显错误 │
│ • GPU 利用率:从 70% 掉到 30% │
│ • 你开始怀疑 JIT 编译缓存失效了,但不知道如何确认 │
└──────────────────────────────────────────────────────────────────────────────┘第1节:性能分析工具全家桶
1.1 PyTorch Profiler
PyTorch Profiler 是 PyTorch 官方的性能分析工具,可以分析 CPU 和 GPU 上的执行时间。
python
import torch
from torch.profiler import profile, ProfilerActivity, schedule, tensorboard_trace_handler
# ============================================================
# 基础用法
# ============================================================
with profile(
activities=[
ProfilerActivity.CPU, # 分析 CPU 时间
ProfilerActivity.CUDA, # 分析 GPU 时间
],
schedule=schedule(
wait=1, # 跳过前 1 个 step
warmup=1, # 预热 1 个 step
active=3, # 分析 3 个 step
repeat=2 # 重复 2 次
),
on_trace_ready=tensorboard_trace_handler('./profiler_logs'), # 输出到 TensorBoard
record_shapes=True, # 记录 tensor shape
profile_memory=True, # 分析显存使用
with_stack=True, # 记录调用栈
) as prof:
for step, batch in enumerate(dataloader):
# 训练步骤
output = model(batch)
loss = criterion(output, target)
loss.backward()
optimizer.step()
optimizer.zero_grad()
prof.step() # 进入下一个 step
# ============================================================
# 分析输出
# ============================================================
# 打印 CPU 时间最长的操作
print(prof.key_averages().table(
sort_by="cpu_time_total",
row_limit=20
))
# 打印 GPU 时间最长的操作
print(prof.key_averages().table(
sort_by="cuda_time_total",
row_limit=20
))
# 打印显存使用
print(prof.key_averages().table(
sort_by="self_cuda_memory_usage",
row_limit=20
))
# ============================================================
# 导出到 TensorBoard
# ============================================================
# 在终端运行:
# tensorboard --logdir=./profiler_logs
# 然后打开 http://localhost:60061.2 NVTX(NVIDIA Tools Extensions)
NVTX 允许你在 CUDA 代码中插入标记,用于标识代码的不同区域。
python
import torch.cuda.nvtx as nvtx
# ============================================================
# 基本标记
# ============================================================
def train_step(batch):
nvtx.range_push("data_transfer") # 开始一个区间
batch = batch.to('cuda')
nvtx.range_pop()
nvtx.range_push("forward")
output = model(batch)
nvtx.range_pop()
nvtx.range_push("backward")
loss = criterion(output, target)
loss.backward()
nvtx.range_pop()
nvtx.range_push("optimizer")
optimizer.step()
optimizer.zero_grad()
nvtx.range_pop()
# ============================================================
# 带颜色的命名区间
# ============================================================
# nvtx.range_push 支持颜色字符串
nvtx.range_push("forward", "green")
nvtx.range_push("backward", "red")
# ============================================================
# 在 torch.compile 中使用 NVTX
# ============================================================
# PyTorch 2.0+ 支持自动插入 NVTX 标记
with profile(
activities=[ProfilerActivity.CUDA],
with_stack=True,
) as prof:
# 运行推理
output = torch.compile(model)(batch)
prof.step()
# 在 Nsight Systems 中可以看到编译后的 kernel1.3 Nsight Compute 与 Nsight Systems
Nsight Compute:CUDA kernel 级分析,精确到每个 SM 的执行情况。
bash
# ============================================================
# Nsight Compute 命令行使用
# ============================================================
# 基本 kernel 分析
ncu --set full \
--target-processes all \
--output ./kernel_report \
python inference.py
# 分析特定的 kernel
ncu --kernel-name "gemm" \
--output ./gemm_report \
python inference.py
# 分析 GPU 利用率
ncu --metrics sm__throughput.avg.pct_of_peak_sustained \
python inference.pyNsight Systems:系统级分析,包括 CPU、GPU、内存、I/O 等。
bash
# ============================================================
# Nsight Systems 命令行使用
# ============================================================
# 基本分析
nsys profile --output ./profile \
--trace=cuda,nvtx,osrt,pytorch \
python training.py
# 导出为 JSON 格式(便于程序分析)
nsys profile --output ./profile \
--type cuda \
--format json \
python inference.py
# 分析特定时间段
nsys profile --output ./profile \
--cuda-memory-usage true \
--duration 10 \ # 10 秒
python inference.py1.4 TensorBoard Profiler 插件
bash
# ============================================================
# TensorBoard Profiler 使用
# ============================================================
# 1. 安装
pip install tensorboard tensorboard_plugin_profile
# 2. 启动 TensorBoard
tensorboard --logdir=./logs --port=6006
# 3. 在浏览器打开
# http://localhost:6006/#profilepython
# ============================================================
# TensorBoard 日志格式
# ============================================================
from torch.profiler import tensorboard_trace_handler
# 输出到 TensorBoard 兼容格式
with profile(
activities=[ProfilerActivity.CPU, ProfilerActivity.CUDA],
on_trace_ready=tensorboard_trace_handler('./tb_logs'),
...
) as prof:
for step in range(100):
train_step(batch)
prof.step()
# TensorBoard 会生成以下分析视图:
# - Overview Page: 性能概览和优化建议
# - Trace View: 时间线视图
# - GPU Kernel Stats: GPU kernel 统计
# - Memory View: 显存使用分析
# - CPU GPU Ops: CPU 和 GPU 操作对应关系1.5 工具对比表
| 工具 | 粒度 | 主要用途 | 使用场景 | 学习曲线 |
|---|---|---|---|---|
| PyTorch Profiler | Op 级别 | PyTorch 训练/推理分析 | 日常性能分析 | 低 |
| NVTX | 区间标记 | 代码区域标记 | 自定义代码分析 | 低 |
| Nsight Compute | Kernel 级别 | CUDA kernel 细节 | GPU kernel 优化 | 高 |
| Nsight Systems | 系统级 | 全系统分析 | 定位瓶颈来源 | 中 |
| TensorBoard | Op 级别 | 可视化分析 | 结果展示 | 低 |
第2节:torch.compile 调试
2.1 开启 debug 模式
python
import torch
# ============================================================
# 基本 debug 配置
# ============================================================
# 开启 dynamo debug(查看 graph break)
torch._dynamo.config.debug = True
torch._dynamo.config.verbose = True
# 编译模型
compiled_model = torch.compile(
model,
backend="inductor",
mode="reduce-overhead",
)
# ============================================================
# 捕获 Graph Break
# ============================================================
# 运行后,Dynamo 会输出每个 graph break 的原因
# 例如:
# Graph break: call_function max_pool2d ... not supported
# Graph break: call_method items() ... not a tensor
# ============================================================
# 导出编译后的代码
# ============================================================
torch._inductor.config.debug = True
torch._inductor.config.trace.enabled = True
compiled_model = torch.compile(
model,
backend="inductor",
)
# 运行一次以生成代码
output = compiled_model(sample_input)
# 导出的代码位置:
# torch._inductor.config.trace.output = "./inductor_output"
# 或在环境变量设置:
# TORCHINDUCTOR_TRACE_OUTPUT=./logspython
# ============================================================
# 查看生成的 Inductor 代码
# ============================================================
import torch._inductor
# 设置输出目录
torch._inductor.config.trace.output = "./inductor_logs"
# 编译
compiled = torch.compile(model)
# 运行(会自动生成代码)
output = compiled(input)
# 在 ./inductor_logs 目录下会有:
# - *.py: 生成的 CUDA kernel 代码
# - *.cpp: 生成的 cpp wrapper 代码2.2 XLA HLO 可视化
python
# ============================================================
# XLA HLO 调试
# ============================================================
import torch_xla.core.xla_model as xm
import torch_xla
# 设置 XLA 调试选项
xla_env = os.environ
xla_env["XLA_IR_DEBUG"] = "1" # 输出 IR
xla_env["XLA_HLO_DEBUG"] = "1" # 输出 HLO
xla_env["XLA_SAVE_TENSORS_FILE"] = "./xla_debug" # 保存 tensor
# 运行 XLA 编译
model_xla = torch_xla.compile(model)
# 生成的 HLO 文件可以用 XLA inspector 查看
# https://github.com/jreiffers/XLAInspector2.3 编译调试代码示例
python
# ============================================================
# torch.compile 调试完整示例
# ============================================================
import torch
import torch._dynamo as dynamo
import torch._inductor as inductor
def debug_torch_compile():
# 1. 设置 debug 配置
dynamo.config.debug = True
dynamo.config.verbose = True
dynamo.config.replay = True # 允许重放
inductor.config.debug = True
inductor.config.trace.enabled = True
inductor.config.trace.output = "./debug_output"
# 2. 编译模型
print("=" * 60)
print("开始编译")
print("=" * 60)
compiled = torch.compile(
model,
backend="inductor",
options={
"trace.enabled": True,
"trace.output": "./debug_output",
}
)
# 3. 运行编译
print("\n" + "=" * 60)
print("运行第一次推理(编译阶段)")
print("=" * 60)
# Warmup
torch.cuda.synchronize()
output = compiled(sample_input)
torch.cuda.synchronize()
# 4. 分析生成的代码
print("\n" + "=" * 60)
print("分析生成的代码")
print("=" * 60)
# 读取生成的 kernel
import os
for f in os.listdir("./debug_output"):
if f.endswith(".py"):
print(f"\n--- {f} ---")
with open(os.path.join("./debug_output", f)) as fp:
print(fp.read()[:2000]) # 打印前 2000 字符
# 5. 检查是否有 graph break
print("\n" + "=" * 60)
print("检查 Graph Break")
print("=" * 60)
# dynamo 会输出类似:
# TorchDynamo skipped 1 graphs with 2 graph breaks
return compiled
# 运行调试
compiled_model = debug_torch_compile()第3节:MLIR 调试
3.1 MLIR Pass 调试
bash
# ============================================================
# MLIR 调试选项
# ============================================================
# 打印每个 pass 后的 IR
mlir-opt --mlir-print-ir-after-all input.mlir
# 打印每个 pass 前的 IR
mlir-opt --mlir-print-ir-before-all input.mlir
# 只打印感兴趣的 pass
mlir-opt \
--mlir-print-ir-after-change \
--mlir-pass-pipeline="builtin.module(cse,canonicalize)" \
input.mlir
# 打印展平的 SSA 形式
mlir-opt --mlir-print-flat-root-scope input.mlir
# 打印 operation 的类型
mlir-opt --mlir-print-op-generic input.mlir3.2 MLIR 工具链
python
# ============================================================
# 在 Python 中使用 MLIR 工具链
# ============================================================
import subprocess
import os
def run_mlir_pass(mlir_file, passes, output_file=None):
"""
运行 MLIR pass
"""
cmd = ["mlir-opt"]
# 添加 pass
cmd.extend(["--pass-pipeline", passes])
# 输入文件
cmd.append(mlir_file)
# 输出文件
if output_file:
cmd.extend(["-o", output_file])
result = subprocess.run(cmd, capture_output=True, text=True)
return result.stdout, result.stderr
def visualize_mlir(mlir_code, title="MLIR"):
"""
可视化 MLIR(需要在支持的环境中运行)
"""
# 打印 IR
print(f"\n{'=' * 60}")
print(f"{title}")
print(f"{'=' * 60}")
print(mlir_code)
# 可以导出为 dot 图
# 使用 mlir-tblgen 生成 .td 定义,然后用 mlir-opt --mlir-print-dot第4节:常见性能问题根源分析
4.1 GPU 利用率低
python
# ============================================================
# GPU 利用率分析
# ============================================================
# 问题分类
class GPUUtilizationAnalyzer:
"""
分析 GPU 利用率低的根本原因
"""
def analyze_low_utilization(self, profiler_result):
"""
分析低利用率的根本原因
"""
cpu_time = self.get_cpu_time(profiler_result)
gpu_time = self.get_gpu_time(profiler_result)
if cpu_time > gpu_time * 1.5:
return "CPU_BOUND"
elif gpu_time < self.theoretical_min_time:
return "MEMORY_BOUND"
else:
return "COMPUTE_BOUND"
def diagnose_kernel_launch_overhead(self, profiler_result):
"""
诊断 kernel launch 开销
"""
# 太多小的 kernel 会导致 launch overhead
small_kernels = []
for kernel in profiler_result.kernels():
if kernel.duration < 1: # 小于 1 微秒
small_kernels.append(kernel)
if len(small_kernels) > 100:
return "TOO_MANY_SMALL_KERNELS"
return "OK"
def diagnose_memory_bound(self, profiler_result):
"""
诊断是否是显存带宽瓶颈
"""
memory_ops = self.get_memory_ops(profiler_result)
compute_ops = self.get_compute_ops(profiler_result)
memory_time = sum(op.duration for op in memory_ops)
compute_time = sum(op.duration for op in compute_ops)
if memory_time > compute_time * 2:
return "MEMORY_BOUND"
return "COMPUTE_BOUND"GPU 利用率低的原因和解决方案:
| 原因 | 诊断方法 | 解决方案 |
|---|---|---|
| CPU 瓶颈 | CPU time >> GPU time | 优化数据加载、减少 Python 开销 |
| Kernel 太小 | 大量 < 1μs 的 kernel | 使用 torch.compile 融合 kernel |
| 显存带宽瓶颈 | memory_time > compute_time | 使用更高效的数据格式、融合操作 |
| 内存不足导致 swap | GIL + CPU wait | 减小 batch size、使用梯度检查点 |
| 通信瓶颈 | 训练时 GPU 空闲 | 使用 NCCL、优化通信 schedule |
4.2 P99 延迟抖动
python
# ============================================================
# P99 抖动分析
# ============================================================
class LatencyJitterAnalyzer:
"""
分析 P99 延迟抖动的原因
"""
def check_gc_pauses(self):
"""
检查 GC 暂停
"""
import gc
import time
gc_waits = []
# 在关键路径上插入 GC 检查
for _ in range(1000):
start = time.perf_counter()
gc.collect() # 手动触发检查
elapsed = time.perf_counter() - start
gc_waits.append(elapsed)
max_gc_time = max(gc_waits)
if max_gc_time > 0.01: # 超过 10ms
return f"GC_PAUSE: {max_gc_time * 1000:.1f}ms"
return "OK"
def check_jit_warmup(self, model):
"""
检查 JIT 热身延迟
"""
import time
# 检查是否是第一次编译
start = time.perf_counter()
output = model(sample_input)
torch.cuda.synchronize()
first_time = time.perf_counter() - start
# 后续调用应该更快
warm_times = []
for _ in range(10):
start = time.perf_counter()
output = model(sample_input)
torch.cuda.synchronize()
warm_times.append(time.perf_counter() - start)
avg_warm = sum(warm_times) / len(warm_times)
if first_time > avg_warm * 10:
return f"JIT_WARMUP: first={first_time*1000:.1f}ms, warm={avg_warm*1000:.1f}ms"
return "OK"
def check_memory_fragmentation(self):
"""
检查内存碎片化
"""
# 反复分配和释放不同大小的 tensor
import torch
allocations = []
for size in range(100, 10000, 100):
t = torch.randn(size)
allocations.append(t)
# 释放部分
for i in range(0, len(allocations), 2):
del allocations[i]
# 再分配
start = time.perf_counter()
torch.randn(5000)
allocate_time = time.perf_counter() - start
if allocate_time > 0.001: # 超过 1ms 说明有碎片
return f"MEMORY_FRAGMENTATION: {allocate_time*1000:.1f}ms"
return "OK"P99 抖动常见原因:
| 原因 | 典型延迟 | 诊断方法 | 解决方案 |
|---|---|---|---|
| GC 暂停 | 10-100ms | gc.collect() 耗时 | 减少对象创建、使用对象池 |
| JIT 编译 | 1-10s | 首次调用慢 | 预热、缓存编译结果 |
| 内存碎片 | 1-10ms | 分配延迟 | 使用内存池、避免频繁分配释放 |
| 锁竞争 | 变化大 | 多线程 profiling | 减少锁、使用无锁数据结构 |
| 系统调度 | 0.1-1ms | 系统工具 | 绑核、优先级设置 |
4.3 CPU Bound 诊断
python
# ============================================================
# CPU Bound 分析
# ============================================================
class CPUBoundAnalyzer:
"""
分析 CPU bound 的原因
"""
def diagnose_gil_contention(self):
"""
诊断 GIL 争用
"""
import threading
import time
results = []
def cpu_work():
start = time.perf_counter()
for _ in range(1000000):
pass
results.append(time.perf_counter() - start)
# 单线程
t1 = threading.Thread(target=cpu_work)
t1.start()
t1.join()
single_thread_time = results[0]
# 双线程
results.clear()
t1 = threading.Thread(target=cpu_work)
t2 = threading.Thread(target=cpu_work)
t1.start(); t2.start()
t1.join(); t2.join()
dual_thread_time = max(results)
# 如果双线程没有加速,说明是 GIL 瓶颈
speedup = single_thread_time / dual_thread_time
if speedup < 1.3: # 理论应该接近 2
return f"GIL_CONTENTION: speedup={speedup:.2f}x"
return f"OK: speedup={speedup:.2f}x"
def diagnose_data_loading(self):
"""
诊断数据加载瓶颈
"""
import time
import torch.utils.data as data
# 测量 DataLoader 的 throughput
loader = data.DataLoader(dataset, batch_size=32, num_workers=4)
times = []
for batch in loader:
start = time.perf_counter()
# 模拟处理
_ = batch.to('cuda')
torch.cuda.synchronize()
times.append(time.perf_counter() - start)
avg_time = sum(times) / len(times)
p99_time = sorted(times)[int(len(times) * 0.99)]
# 如果 p99 >> avg,说明有长尾
if p99_time > avg_time * 3:
return f"DATA_LOADING_SLOW: avg={avg_time*1000:.1f}ms, p99={p99_time*1000:.1f}ms"
return f"OK: avg={avg_time*1000:.1f}ms"第5节:JIT 编译缓存
5.1 torch.compile 缓存机制
python
# ============================================================
# torch.compile 缓存机制
# ============================================================
import torch._dynamo as dynamo
# 查看缓存统计
print(f"缓存统计: {dynamo.eval_frame.cached_frames_stats()}")
# 清理缓存
dynamo.reset()
# ============================================================
# 缓存配置
# ============================================================
# 设置 FX graph 缓存大小(默认 64)
torch._inductor.config.fx_graph_cache = True
torch._inductor.config.fx_graph_cache_size = 128
# 环境变量方式
# TORCHINDUCTOR_FX_CACHE_SIZE=128
# TORCHINDUCTOR_CACHE=1
# ============================================================
# 缓存失效原因
# ============================================================
"""
缓存失效的常见原因:
1. 输入 shape 变化 -> 生成新的编译结果
2. 输入 dtype 变化
3. 设备变化(cuda:0 vs cuda:1)
4. 模型参数变化(微调后)
5. 全局配置变化(精度设置等)
6. 环境变量变化
"""
def check_cache_hit_rate():
"""
检查缓存命中率
"""
# 方法 1:查看日志
# torch.compile 会输出类似:
# "torch.compile cache stats: 10 cache hits, 5 cache misses"
# 方法 2:使用环境变量
import os
os.environ["TORCH_SHOW_CPP_STACKS"] = "1"
# 方法 3:查看 counters
from torch._inductor import compile_fx
print(compile_fx.COUNTERS)5.2 缓存调试
python
# ============================================================
# 缓存调试示例
# ============================================================
import torch
import torch._inductor as inductor
# 开启缓存调试
inductor.config.debug = True
inductor.config.trace.cache = True
# 第一次编译
print("=" * 60)
print("第一次推理")
print("=" * 60)
model1 = torch.nn.Linear(128, 128).cuda()
compiled1 = torch.compile(model1)
output1 = compiled1(torch.randn(32, 128).cuda())
torch.cuda.synchronize()
# 检查缓存
print(f"缓存键: {compiled1._cache_key}")
print(f"编译缓存目录: {inductor.config.trace.output}")
# 第二次推理(相同 shape)
print("\n" + "=" * 60)
print("第二次推理(相同 shape)")
print("=" * 60)
output2 = compiled1(torch.randn(32, 128).cuda())
torch.cuda.synchronize()
# 不同 shape 的推理
print("\n" + "=" * 60)
print("不同 shape 推理")
print("=" * 60)
output3 = compiled1(torch.randn(64, 128).cuda()) # batch_size 变化
torch.cuda.synchronize()
# 这会导致缓存失效,生成新的编译结果第6节:编译正确性验证
6.1 数值误差分析
python
# ============================================================
# 编译正确性验证
# ============================================================
import torch
import torch.testing as testing
def verify_compiled_correctness(model, input_data):
"""
验证编译模型与 eager 模型的数值一致性
"""
model.eval()
# Eager 模式输出
with torch.no_grad():
eager_output = model(input_data)
# Compiled 模式输出
compiled_model = torch.compile(model)
with torch.no_grad():
compiled_output = compiled_model(input_data)
# 比较输出
print("=" * 60)
print("数值一致性检查")
print("=" * 60)
# 方法 1:使用 torch.testing.assert_close
try:
testing.assert_close(
eager_output,
compiled_output,
rtol=1e-3, # 相对误差容限
atol=1e-3, # 绝对误差容限
)
print("✅ 数值一致")
except AssertionError as e:
print(f"❌ 数值不一致:\n{e}")
# 方法 2:手动计算误差
abs_diff = (eager_output - compiled_output).abs()
rel_diff = abs_diff / eager_output.abs()
print(f"\n绝对误差 - max: {abs_diff.max():.6f}, mean: {abs_diff.mean():.6f}")
print(f"相对误差 - max: {rel_diff.max():.6f}, mean: {rel_diff.mean():.6f}")
return eager_output, compiled_output
def diagnose_numerical_errors(eager, compiled, tolerance=1e-3):
"""
诊断数值误差的来源
"""
diff = (eager - compiled).abs()
# 找出误差最大的位置
flat_diff = diff.flatten()
flat_eager = eager.flatten()
# 按相对误差排序
rel_error = flat_diff / (flat_eager.abs() + 1e-8)
_, indices = rel_error.topk(10)
print("\n误差最大的 10 个位置:")
for idx in indices:
print(f" 位置 {idx}: eager={flat_eager[idx]:.4f}, "
f"compiled={compiled.flatten()[idx]:.4f}, "
f"diff={flat_diff[idx]:.6f}")6.2 常见数值误差来源
python
# ============================================================
# 数值误差来源分析
# ============================================================
class NumericalErrorAnalyzer:
"""
分析编译引入的数值误差
"""
def check_float_precision(self, eager, compiled):
"""
检查浮点精度问题
"""
# 不同硬件上的浮点运算顺序可能不同
# 这可能导致微小差异
# 检查是否在合理范围内
diff = (eager - compiled).abs()
rel_diff = diff / eager.abs()
# FP32 的精度限制约为 1e-6
if rel_diff.max() > 1e-5:
return "FLOAT_PRECISION_ISSUE"
return "OK"
def check_operation_order(self, graph):
"""
检查算子执行顺序
"""
# 某些情况下,编译器可能改变算子的融合顺序
# 这可能导致数值差异
# 检查是否有顺序敏感的算子
sensitive_ops = ['sort', 'topk', 'argmax']
for op in sensitive_ops:
if op in graph:
print(f"⚠️ 顺序敏感算子: {op}")
return
def check_reduction_order(self):
"""
检查归约操作的顺序
"""
# AllReduce 等操作的结果顺序可能不确定
# 这可能导致数值差异
return "OK"升华
┌──────────────────────────────────────────────────────────────────────────────┐
│ 生产调试实践原则 │
├──────────────────────────────────────────────────────────────────────────────┤
│ 1. 先定位后优化:用 profiler 确定瓶颈,不要猜测 │
│ 2. 分层排查:GPU 利用率低 → 可能是 CPU bound / memory bound / compute bound │
│ 3. 抖动先查 GC 和 JIT:P99 延迟抖动最常见的原因是垃圾回收和 JIT 编译 │
│ 4. 缓存状态要监控:torch.compile 的缓存命中率直接影响推理延迟 │
│ 5. 数值安全第一:优化前先验证正确性,数值误差会累积 │
└──────────────────────────────────────────────────────────────────────────────┘"AI 可查 vs 必须理解"清单
必须理解(不理解就等于不会):
- 🔴 PyTorch Profiler 的使用方法和输出解读
- 🔴 GPU 利用率低的三个原因:CPU bound / memory bound / compute bound
- 🔴 P99 延迟抖动的常见原因:GC / JIT warmup / memory fragmentation
- 🔴 torch.compile 缓存失效的原因
- 🔴 数值误差的来源和验证方法
AI 可查(知道去哪查就行):
- ✅ Nsight Compute/Systems 的具体使用参数
- ✅ MLIR 调试选项的具体语法
- ✅ 特定 kernel 的性能数据
- ✅ 各硬件平台的性能基准
- ✅ XLA HLO 的具体格式
学习状态:🟡 开始学习