一次WSL上使用clangd编写cuda的踩坑
起因
最近在WSL上学习CUDA,不假思索地选择了clangd作为lsp,使用的软件如下:
- Arch WSL2
- CMake 3.28.1
- Cuda compilation tools, release 12.3, V12.3.103
- LLVM 16.0.6
- VSCode 1.85.1
但是使用的过程中,遇到了一个非常神秘的问题,对于C++的源代码*.h
和*.cpp
等,clangd的代码补全一切正常,但是一遇到.cu
文件,completion的延迟会长达几秒钟:
可以看到连copilot都已经给我写好了,但是clangd还在犹豫,这是为什么呢?我看了一眼compile_commands.json
,发现并没有异样。遂在互联网上搜索了一番,最终在某群中,一个群友给出建议:
先在sudo模式下把 /etc/wsl.conf 文件权限+w,然后在该文件下新建节 [interop] enabled = false appendWindowsPath = false 最后重启wsl
看来果然是WSL的锅,经过一番控制变量,发现问题出在了$PATH
的环境变量上,WSL的$PATH
环境变量会自动添加Windows的环境变量,众所周知垮WSL的Host IO非常拉胯,在一堆/mnt
路径中搜来搜去肯定是很慢的。
But How?
但是很明显,这是不应该出现的情况,而且我也不想把interop直接禁用掉。
再次检查compile_commands.json
,一切正常:
1 | { |
根本没有任何/mnt
路径出现,不见棺材不掉泪,我把LLVM的源码拉了下来,对着$PATH
一顿搜索,毫无头绪,用到了$PATH
的地方根本就没有被触发。幸运的是,发现vscode-clangd
有一个trace的配置,可以保存trace到一个可以被Chrome trace viewer打开的文件中,very well,对比有无清理$PATH
的trace结果:
瓶颈在CreatePreamblePatch
:
一开始以为是clangd的include search问题,但是经过二分排查法,瓶颈调用链竟然出现在clangd对于nvcc
的调用上,但是我的compile_commands.json
中的nvcc
就是在WSL中的。由于后续debug涉及到了LLVM
核心模块,因此不再深究。但是综合上述的情况,答案很明显了:
瓶颈并非clangd
,而是nvcc
,nvcc
会在被调用时对于$PATH
进行搜索,而$PATH
中包含了/mnt
路径,导致了严重的IO延迟(这也是为什么只有.cu
文件会有问题)。
So **** u, NVIDIA.
解决方案
真麻烦,我们肯定不能指望哪一天NVIDIA大发慈悲来修修这个问题,而我目前也还没有找到能限制nvcc
搜索路径的方法,因此只能从vscode-clangd
插件入手。解决办法也很直接:在其启动clangd
language server时清理一下$PATH
即可:
在vscode-clangd
的src/clangd-context.ts
中:
1 | diff --git a/src/clangd-context.ts b/src/clangd-context.ts |
总而言之,虽然最终没能完美解决这个问题,但是能发现问题的根源然后用一个比较tricky的方法解决掉,也是一件值得庆幸的事情。
以及,again,**** u, NVIDIA.
一次WSL上使用clangd编写cuda的踩坑
https://hyiker.github.io/2023/12/17/一次WSL上使用clangd编写cuda的踩坑/