infer objective-C 如何实现增量分析

2021-12-03  本文已影响0人  令狐冲_

背景:

公司需要接入infer,但是技委会那边提供的脚本只支持全量,脚本代码如下:

infer run --keep-going --skip-analysis-in-path Pods --compilation-database $compile_commands_path &> $inferlog_path

单次infer执行的时长特别的长,非常影响构建机的其他工作效率,我们希望能够把全量改为增量,只分析当前分支最近一次提交修改的文件即可,不需要次次走全量。

infer工作流程

infer-run指令实际分为两步

  1. infer-capture
    这个指令相当于infer的编译操作,会把当前语言翻译成infer自己内部的中间语言,这个翻译过程类似于编译,并把中间文件存储在results目录中,该目录存储在这一步生成的infer-out文件夹,里面有全部的分析结果。
  2. infer-analysis
    分析阶段,这时候infer会分析infer-out文件夹中的文件,每个函数,每个方法,并把错误输出在infer-out/report.txt
    现在我们知道了infer-run具体的工作流程是以上两步,我们不难得出infer-analysis这一步是可以优化的想法,我们不需要每次都分析所有的文件,只需要分析有变化的文件即可。

优化思路

我的思路如下:

  1. 保存infer-out
    为什么要保存infer-out,因为我司使用gitlab CI/CD的runner来触发工作流的,导致每次都会重新初始化仓库,删除之前所有的无关变量,包括infer-out(这个文件夹包含了上一次的扫描结果),所以我们要想办法存储上一次的infer-out,并且在下一次分析的时候把它重新拉回来。
  2. infer分析步骤只分析差异性文件

需要注意的点

  1. 一台构建机上可能有多个runner;
  2. 每个runner可以执行多个项目;
  3. 每个项目可以有多个分支;

实现方式

  1. 在根目录下按照runner ID 建立多个目录,保证每个runner之间互不干涉;
  2. 在runner目录下按照项目建立新的目录,保证每个项目都可以保存自己的infer分析结果;
  3. 在项目目录下按照分支保存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这一步时长的想法,欢迎一起交流学习!

上一篇下一篇

猜你喜欢

热点阅读