pytorch无法直接获取底层算子(如cublas_gemm)的纯计算时间,torch.cuda.event测的是host同步耗时,含调度排队等干扰;唯一官方支持的kernel级profiling是torch.profiler(依赖nsys),需cuda设备运行并启用record_shapes等参数。

PyTorch 自身不暴露底层算子(如 cublas_gemm、cudaMemcpyAsync)的原始执行时长,直接用 Python 代码“查看”是做不到的——你看到的 torch.cuda.Event 或 torch.profiler 给出的是 kernel launch 到同步完成的耗时,中间夹着驱动调度、stream 排队、内存拷贝隐式开销,不是算子本身纯计算时间。
用 torch.profiler 抓 kernel 级别耗时(最接近“底层算子”的方式)
这是目前 PyTorch 官方唯一支持的、能落到 CUDA kernel 粒度的 profiling 方案。它依赖 nsys 后端(需安装 NVIDIA Nsight Systems),但 Python 接口可触发:
- 必须在 CUDA 设备上运行,且模型/数据已
.cuda();CPU 模式下 profiler 不会记录 kernel - 启用
record_shapes=True才能看到 tensor shape 和算子参数(如 matmul 的 m/n/k) -
with torch.profiler.profile(record_shapes=True, with_stack=True, profile_memory=True)是最小可用组合 - 输出中的
cudaLaunchKernel行不是算子名,要看紧随其后的at::native::或cublas_前缀行——那才是实际调用的底层函数
with torch.profiler.profile(
activities=[torch.profiler.ProfilerActivity.CPU, torch.profiler.ProfilerActivity.CUDA],
record_shapes=True,
with_stack=False
) as prof:
out = model(x)
print(prof.key_averages(group_by_stack_n=5).table(sort_by="cuda_time_total", row_limit=10))
为什么 torch.cuda.Event 测不准底层算子时间?
它测的是两个事件点之间 host 端同步等待的时间,无法剥离以下干扰:
- GPU stream 中该 kernel 前面还有没跑完的 kernel,
Event等的是整个 stream 到达该点,不是单个 kernel - 如果 kernel 启动后立刻被
torch.cuda.synchronize()强制等,测出来的是“启动+排队+执行+写回”的总延迟,不是执行本身 - 小 kernel(如
add)可能被 driver 合并或延迟提交,Event时间会异常短甚至为 0
典型误用:start.record(); y = x + 1; end.record(); end.elapsed_time(start) —— 这里 y = x + 1 是异步 launch,elapsed_time 实际测的是从 launch 到 host 端确认完成的时间,和 GPU 上真实计算时长无关。
Python 3.14.2是Python编程语言在2025年12月5日发布的稳定版本,属于3.14系列的第二个维护更新。该版本包含了18项修复,重点解决了多进程、数据类及正则表达式等模块的回归问题,并修复了CVE-2025-12084等安全漏洞。此版本标志着自由线程模式(移除GIL)正式获得官方支持,是Python发展的重要里程碑。
想看真正算子级 trace?只能靠 nsys CLI + Python 预处理
PyTorch 的 Python 层无法绕过 CUDA driver 直接读取硬件计数器,所以必须借助 NVIDIA 官方工具链:
- 先用命令行跑:
nsys profile -t cuda,nvtx --capture-range=cudaProfilerApi python train.py - 生成
report.nsys-rep,再用nsys export -f csv -o profile.csv report.nsys-rep导出 CSV - Python 里用
pandas读取,过滤Kernel Name列含cublas、cudnn、void at::native::的行,提取Duration (ns) - 注意:同一 kernel 名在不同 shape 下性能差异极大,CSV 里必须关联
Grid Size和Block Size列才能判断是否是同一个算子变体
没有 nsys 权限(比如在 Docker 或共享服务器上)?那就只能接受 torch.profiler 的抽象层级——它告诉你“这段 Python 代码触发了哪些 kernel”,但不会告诉你“这个 kernel 在 SM 上实际跑了几个 cycle”。
真正卡点往往不在算子执行时间,而在 kernel 启动开销、memory coalescing 是否良好、tensor layout 是否适配 cudnn —— 这些都藏在 nsys 的 memory tab 和 source view 里,Python 代码扫不到。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










