这个ccusage能分析C/C++源码的调用热点,定位性能瓶颈的利器!
今天这篇文章分享一个我最近发现的小工具 —— ccusage,别看项目不大,但功能确实牛逼!我试了下,**直接分析了一个项目上万行的C代码,结果秒出,性能直接爆了!**用它来排查代码结构复杂度、函数耦合度、甚至热路径调用图,太爽了。
这玩意儿太适合那种C项目动不动几万行、一堆宏、结构体套娃嵌套、头文件依赖地狱的场景了。
那下面来看看,我是怎么上手用这个工具的,顺便讲讲它背后的几个设计思路。
1)项目简介:ccusage是干啥的?
一句话:这是一个源码级别的静态分析工具,用来统计各种 C / C++ 语言元素在项目中的“使用频率”与“出现位置”。
具体支持:
统计函数的调用次数、被调用者是谁; 分析宏定义(define)的使用位置; 结构体成员出现的频率; 可选生成 DOT 格式的调用图(graphviz)。
是不是有点像轻量版的 clang-analyzer 或 cscope,但上手更简单,不用搞复杂的编译参数导入。
而且它基于 libclang,所以准确性比你自己正则匹配高太多,不会误报一堆关键字。
2)安装 & 依赖
我用的是 macOS,本地是 M1 芯片,装这个需要依赖以下几个东西:
Python 3.10+ libclang(mac上直接用brew install llvm)graphviz(可选:用来可视化调用图)
装法如下:
git clone https://github.com/ryoppippi/ccusage.git
cd ccusage
pip install -r requirements.txt
注意!这个工具依赖的 libclang 路径可能要你手动配置一遍,我在 M1 上这样设的:
export LIBCLANG_PATH="/opt/homebrew/opt/llvm/lib"
然后就可以跑了。
3)怎么用?我用它分析了一个老项目!
我找了我们公司一个老旧的嵌入式项目,纯C写的,大概3万多行。我想看看哪个函数是“最核心的调用点”。
直接命令:
python ccusage.py -r ./your_project_path -t function -o out/function_usage.json
然后你得到的就是一个 json 文件,内容大概长这样:
{
"funcA": {
"count": 12,
"locations": [...],
"called_by": [...],
"calls": [...]
},
...
}
我一眼就看出来几个函数被调用次数上百,结果代码质量堪忧!有个“util_parse_cmd”函数被 UI 层、底层硬件、网络协议全调……完全是一个耦合怪兽!
是不是有点像 Flamegraph 那种感觉?不过这个更底层,能直接看到代码级别的调用关系。
4)还能画图!调用图太直观了!
接下来我用它的图形功能,导出了 DOT 图文件:
python ccusage.py -r ./your_project_path -t function -g out/callgraph.dot
然后用 dot 转成 PNG:
dot -Tpng out/callgraph.dot -o callgraph.png
我放进 PPT 给我Leader看了下,我们一个模块里有个函数居然扮演“蜘蛛网核心”的角色,从它出发能拉出几十条边!
他说了一句:“难怪这模块一改就炸”……
5)使用场景总结:这玩意适合谁?
我觉得下面这几类人非常适合用这个工具:
1)老项目接手人 —— 想快速了解代码结构,不靠肉眼啃源码; 2)性能分析 —— 找热点函数,看哪里调用集中,优化优先级高; 3)重构前分析 —— 哪些函数被“滥用”,作为候选拆分点; 4)教学/阅读源码 —— 分析开源项目的函数结构,用来辅助学习; 5)生成文档 —— 调用图放到项目文档里,完美。
6)几个小坑分享
我用下来发现几个小坑,顺便分享下:
有些项目需要先用 compile_commands.json导入编译信息,不然会报缺头文件;如果结构体写得很乱,建议先 -t struct单独导出分析;有些头文件里有宏嵌套宏,会导致 libclang 识别不准,慎用; 不支持 template / 模板分析(目前),C++重度使用模板的项目不太适用;
不过整体准确率和分析速度确实不错,比你手写脚本+正则强太多了!
感兴趣的朋友可以试试,如果你也接手过几万行的屎山项目,用这个工具,或许能救你一命!
我们下篇再见!