调试的时候有几个技巧,分享和记录下,方便自己后面可以熟练的用到。
看所有的编译命令,但是不执行
-###
,这个就是 clang 的第一个参数。
https://clang.llvm.org/docs/CommandGuide/clang.html
用 clang 编译的时候,会从打印(但不运行)为此编译运行的命令。
然后打印出出错的命令,然后一步一步的执行,就知道是哪里的问题了。
比如:优化或者是定位哪一步的编译时间过长,是词法解析,还是编译器后端,还是 lld 导致的,用这个方法分别执行每一步的命令,然后统计下,就知道是哪里耗费的时间长。
llvm_debug 用法
将对应的实例以字符串的形式输入到 errs() 流中,但是类似这种调试信息,我们通常并不想在正式发布的时候打印,而且有时候 Pass 的代码一多,就会造成打印的信息过多,干扰我们调试。
https://zhqli.com/post/1667466024
借助 LLVM 的 LLVM_DEBUG
对调试信息进行分类,使用之前需要导入对应的头文件并定义 DEBUG_TYPE
, 如下所示
在 llvm 代码里面可以看到 LLVM_DEBUG()
的用法,这个用法是什么喃?
用的时候需要在 cpp 顶部定义各一个#incldue DEBUG_TYPE "pass_name"
举个例子
https://github.com/llvm/llvm-project/blob/main/llvm/lib/Target/AMDGPU/AMDGPUCallLowering.cpp
AMDGPU 的 calllowering 里面。
#define DEBUG_TYPE "amdgpu-call-lowering"
定义一个 debug_type 的,后面是 pass 的名字。如何使用,
LLVM_DEBUG(dbgs())
// Make sure that they can fit on the caller's stack.
const SIMachineFunctionInfo *FuncInfo = MF.getInfo<SIMachineFunctionInfo>();
if (OutInfo.getStackSize() > FuncInfo->getBytesInStackArgArea()) {
LLVM_DEBUG(dbgs() << "... Cannot fit call operands on caller's stack.\n");
return false;
}
这样 debug 的时候,只需要跟上这个 pass 的名字,就只打印出这个 pass 的相关的 log 信息了。定位就方便多了。
opt xxx --debug-only=amdgpu-call-lowering
统计运行时间
上面提到如何用###
来查看命令,那么还有如何通过执行直接获取每一个的执行时间?
可以用这个命令通过 opt -time-trace
选项告诉 opt 导出所有由 TimeTraceaScope 收集的信息,并将 trace 文件保存到 -time-trace-file 指定的 json 文件中,这个 json 文件怎么查看呢?可以在 chrome 地址栏输入 chrome://tracing
, 然后打开这个 json 文件即可可视化查看,是不是有点惊喜?
点击图片中第三个图标,就可以放大和缩小这个图片了,能看到具体是哪一个出了问题。
chrome 的 trace 查看功能实际上是集成了项目 perfetto, 这个项目可以在线使用,地址是 https://ui.perfetto.dev/.
那么 clang 里面用 -ftime-trace
也是可以用的`。
方便么?do you get it?
顺便推荐一本书,就是短时间内学习有用的 LLVM 技能,并使您能够快速构建原型和项目。编程语言爱好者还会发现本书对于在 LLVM 的帮助下构建新的编程语言很有用。 https://github.com/PacktPublishing/LLVM-Techniques-Tips-and-Best-Practices-Clang-and-Middle-End-Libraries
还有大佬翻译为中文了,https://github.com/xiaoweiChen/LLVM-Techniques-Tips-and-Best-Practies