想要对vllm进行profile,但vllm用了torch Dynamo去compile cuda graph,在里面插nvtx的标会让dynamo的编译出问题然后直接报错。
但不能打标,对着一堆无关的内容profile有一种难绷的感觉,比如说实际上只希望profile模型推理的阶段,但看到nsys输出的东西包含了一堆vllm加载模型,构建计算图之类的过程。生成的profile文件很大,而且找到目标很麻烦。而当用ncu去profile kernel的时候更是没法用,因为没法只选定一个范围的话ncu查的东西实在是太多了。
每次profile vllm就头大。最近七七八八地研究了一下nsys和ncu还有nvtx。
先看看NVTX是不是真的能用。nsys profile -t nvtx python -c "import nvtx, time; nvtx.push_range('A'); time.sleep(1); nvtx.pop_range()"这里提供一个极简的测试,在生成的report里用nsys的GUI打开应该能看到有个A。如果没有这个A,那说明NVTX本身的工作就有问题,那是死活也看不到NVTX的标的。
注意ldconfig -p | grep libnvToolsExt看看能不能找到这个链接库,理论上是应该有的。如果没有的话,那前面一步将确实看不到A。
找一下$CUDA_HOME/lib64下面是否有libnvToolsExt.so,有的话就行,用下面这个测试来看看是不是能看到A。
|
|
用nsys profile -t nvtx python test.py来profile上面这个文件,应该是能看到A了。这至少说明NVTX的链接库是好的。
解决方案是要么研究一下NVTX和nsys的版本问题,update一下说不定就能用。(在我的测试里nvtx0.2.13+nsys2024.4没法看到标,更新nsys2025.5就正常工作了。)
要么就用这个链接库当python的nvtx库用,比如下面:
|
|
具体的API可见英伟达文档。注意如果用C打的话,传message的时候得确保这个message不是一个临时创建的字符串,否则一旦python gc直接把这个字符串回收了,C去读到的指针就是一个不知道什么了。需要在类里面存下来这些字符串,比如:
|
|
对于范围限定问题,nsys提供了--capture-range。
--capture-range=nvtx:使用nvtx.push_range()和nvtx.pop_range()标记开始和结束。
--capture-range=cudaProfilerApi:使用torch.cuda.cudart().cudaProfilerStart() 和torch.cuda.cudart().cudaProfilerStop() 来标记开始和结束。
cudart这个也可以直接拉链接库。CUDA runtime API文档,找Profiler Control的部分。
|
|
注意vllm的旧一些的版本,在里外各放了一个benchmarks文件夹,在执行vllm bench的时候实际上在跑的是vllm/benchmarks下的那些,在benchmarks/里改半天也是发现什么效果都没有。我的教训是下次插profile相关的内容的时候,先插一个raise Error,看看是不是程序真的会经过这行代码。
但还是没法解决nvtx和dynamo冲突的问题。
尝试了一下,下面这三种方法都没法让nvtx和torch Dynamo共存:
|
|
注意@support_torch_compile在哪个类上,这个类以及其触发的类都没法打NVTX了,我觉得这是很糟糕的。
那就只能打在外面,比如qwen3moe只能打在token层面,打不到layer层面。
ncu相关的问题:
Failed to open/create lock file /tmp/nsight-compute-lock.
那是因为另一个用户用过了,导致这个tmp没有写权限,sudo删掉就行
测之前可以锁一下卡的频率,让速率上的可复现性好一点
sudo nvidia-smi -i 0 -pm 1
sudo nvidia-smi -i 0 -ac 1215,1410
# 以下为恢复
sudo nvidia-smi -i 0 -pm 0
sudo nvidia-smi -i 0 -rac