背景:
公司需要接入infer,但是技委会那边提供的脚本只支持全量,脚本代码如下:
infer run --keep-going --skip-analysis-in-path Pods --compilation-database $compile_commands_path &> $inferlog_path
单次infer执行的时长特别的长,非常影响构建机的其他工作效率,我们希望能够把全量改为增量,只分析当前分支最近一次提交修改的文件即可,不需要次次走全量。
infer工作流程
infer-run指令实际分为两步
-
infer-capture
这个指令相当于infer的编译操作,会把当前语言翻译成infer自己内部的中间语言,这个翻译过程类似于编译,并把中间文件存储在results目录中,该目录存储在这一步生成的infer-out
文件夹,里面有全部的分析结果。 -
infer-analysis
分析阶段,这时候infer会分析infer-out
文件夹中的文件,每个函数,每个方法,并把错误输出在infer-out/report.txt
现在我们知道了infer-run具体的工作流程是以上两步,我们不难得出infer-analysis这一步是可以优化的想法,我们不需要每次都分析所有的文件,只需要分析有变化的文件即可。
优化思路
我的思路如下:
- 保存
infer-out
为什么要保存infer-out
,因为我司使用gitlab CI/CD的runner来触发工作流的,导致每次都会重新初始化仓库,删除之前所有的无关变量,包括infer-out
(这个文件夹包含了上一次的扫描结果),所以我们要想办法存储上一次的infer-out
,并且在下一次分析的时候把它重新拉回来。 - infer分析步骤只分析差异性文件
需要注意的点
- 一台构建机上可能有多个runner;
- 每个runner可以执行多个项目;
- 每个项目可以有多个分支;
实现方式
- 在根目录下按照runner ID 建立多个目录,保证每个runner之间互不干涉;
- 在runner目录下按照项目建立新的目录,保证每个项目都可以保存自己的infer分析结果;
-
在项目目录下按照分支保存infer分析结果;
例如保存目录如下
image.png
这样做的优点在于,每个runner之间跑的结果互不干涉,且可以保存多个项目多个分支的分析结果。
代码实现如下
# infer
echo "🍵 🍵 🍵 🍵 🍵 🍵 🍵 🍵 🍵 🍵 🍵 🍵 🍵 infer working... "
infer_start_time=$(date +%s)
execute_infer(){
# --skip-analysis-in-path 是忽略扫描目录 --keep-going 忽略错误继续运行
if which infer >/dev/null; then
#当前分支名
echo "============当前分支名称$CI_COMMIT_REF_NAME============="
#上次保存的目录
lastInferoutPath="$HOME/$CI_RUNNER_TAGS-infer-out/$CI_PROJECT_NAME/$CI_COMMIT_REF_NAME/infer-out/"
#看看上次有没有记录
if [ -d ${lastInferoutPath} ]; then
#当前infer扫描保存目录
currentInferoutPath="$CI_PROJECT_DIR/infer-out"
cp -Rf ${lastInferoutPath} ${currentInferoutPath}
echo "=========获取infer-out成功,走增量分析流程========="
# 获取当前分支最近一次提交修改的文件
git diff --name-only HEAD~ HEAD > change.txt
# capture 操作
infer-capture --reactive \
--keep-going \
--compilation-database $compile_commands_path &> $inferlog_path
inferAnalyzePath="$cilogPath/inferAnalyzePath.log"
# analyze 操作
infer-analyze --reactive \
--keep-going \
--compilation-database $compile_commands_path &> $inferAnalyzePath \
--changed-files-index change.txt
else
echo "====没有上次infer分析的结果, 走全量正常分析流程===="
# 添加reactive模式
infer run --reactive --keep-going --skip-analysis-in-path Pods --compilation-database $compile_commands_path &> $inferlog_path
fi
echo "🍺 infer Success"
#当前infer扫描保存目录
currentInferoutPath="$CI_PROJECT_DIR/infer-out/"
#上次保存的目录
lastInferoutProject="$HOME/$CI_RUNNER_TAGS-infer-out/$CI_PROJECT_NAME/$CI_COMMIT_REF_NAME"
if [ ! -d ${lastInferoutProject} ]; then
mkdir -p $lastInferoutProject
fi
lastInferoutPath="$HOME/$CI_RUNNER_TAGS-infer-out/$CI_PROJECT_NAME/$CI_COMMIT_REF_NAME/infer-out"
# 保存infer扫描记录
cp -Rf ${currentInferoutPath} ${lastInferoutPath}
echo "=========保存infer-out成功,保存路径在$lastInferoutPath========="
else
echo "warning: infer not installed, download from https://fbinfer.com"
fi
}
if [ -f $compile_commands_path ]; then
execute_infer
else
echo "warning: ${compile_commands_path} not found !!";
fi
infer_end_time=$(date +%s)
结果图
注:infer的扫描时长仅供参考,要保证测试数据的可比较性,请尽量在构建机没有其他工作任务,保证完全clean的状态下执行。
全量扫描
image.png
增量分析
image.png
可以看到,采取增量分析后,时长减少了72%。
如果您有更好的能够减少infer-capture
这一步时长的想法,欢迎一起交流学习!
网友评论