openGauss

开源数据库

openGauss社区官网

开源社区

如何跑增量代码覆盖率

彭炯2022-05-05覆盖率

全量代码覆盖率统计:

  1. 下载安装 lcov 工具(版本 >= 1.15)
shell
wget https://sourceforge.net/projects/ltp/files/Coverage%20Analysis/LCOV-1.15/lcov-1.15.tar.gz
tar -zxvf lcov-1.15.tar.gz
cd lcov-1.15/bin
./lcov -v
结果显示:
lcov: LCOV version 1.15

并将lcov路径增加在环境变量中

shell
export PATH=/xxx/lcov-1.15/bin:$PATH
  1. 增加插桩函数用于收集结果:在代码根目录下执行, 假设此代码根目录为 /home/test/openGauss-server
shell
sed -i '/NotifyProcessActive();/i __gcov_flush();'  src/gausskernel/process/postmaster/postmaster.cpp
sed -i '/extern void InitGlobalSeq();/i extern "C" void __gcov_flush();'   src/gausskernel/process/postmaster/postmaster.cpp

执行完可以 git diff src/gausskernel/process/postmaster/postmaster.cpp 查看插桩是否成功。

shell
[pengjiong@localhost openGauss-server]$ git diff src/gausskernel/process/postmaster/postmaster.cpp
diff --git a/src/gausskernel/process/postmaster/postmaster.cpp b/src/gausskernel/process/postmaster/postmaster.cpp
index d7b939fed..e8f5cdc0f 100644
--- a/src/gausskernel/process/postmaster/postmaster.cpp
+++ b/src/gausskernel/process/postmaster/postmaster.cpp
@@ -293,6 +293,7 @@

 #include "utils/postinit.h"

+extern "C" void __gcov_flush();
 extern void InitGlobalSeq();
 extern void auto_explain_init(void);
 extern int S3_init();
@@ -6687,6 +6688,7 @@ static void pmdie(SIGNAL_ARGS)
             break;
     }

+__gcov_flush();
     NotifyProcessActive();

     gs_signal_setmask(&t_thrd.libpq_cxt.UnBlockSig, NULL);

  1. configure 时增加编译选项:"-fprofile-arcs -ftest-coverage" 和 "LDFLAGS='-lgcov'"是必须要新增的选项(其他选项请根据实际情况调整)
shell
./configure --gcc-version=10.3.1 CC=g++ CFLAGS='-O0 -fprofile-arcs -ftest-coverage' --prefix=$GAUSSHOME --3rd=$BINARYLIBS --enable-debug --enable-cassert --enable-thread-safety --with-readline --without-zlib LDFLAGS='-lgcov'
  1. 正常执行 make && make install
  2. 然后正常执行 fastcheck 或者其他 LLT 用例即可
  3. 用例运行完后,执行 gs_ctl stop -D xxx 停止 gaussdb,开始准备收集覆盖率信息
  4. 在代码根目录下执行:
shell
lcov --capture --directory . --output-file coverage.info

然后会在根目录生成 coverage.info 文件

shell
[pengjiong@localhost openGauss-server]$ ll coverage.info
-rw-------. 1 pengjiong pengjiong 20M Apr 26 16:31 coverage.info
  1. 执行下面命令,修改 coverage.info 文件,将shark相关的四个文件路径修改正确
sed -i 's|contrib/shark/gram\.y|contrib/shark/src/backend_parser/gram-tsql-rule.y|g' coverage.info
sed -i 's|contrib/shark/scan-tsql-rule\.l|contrib/shark/src/backend_parser/scan-tsql-rule.l|g' coverage.info
sed -i 's|contrib/shark/scan\.l|contrib/shark/src/backend_parser/scan-tsql-rule.l|g' coverage.info
sed -i 's|contrib/shark/scan-tsql-epilogue\.l\.cpp|contrib/shark/src/backend_parser/scan-tsql-epilogue.l.cpp|g' coverage.info
  1. 接下来,使用生成的 info 文件转换为可视化的 html 文件,在代码根目录执行:
shell
genhtml --no-prefix --no-sort coverage.info -o results
  1. 执行成功显示覆盖率如下:
Writing directory view page.
Overall coverage rate:
  lines......: 15.1% (144084 of 957019 lines)
  functions..: 18.9% (12059 of 63944 functions)
  1. 同时在根目录下生成 results 文件夹,将 results 文件夹下载到 windows 上,用浏览器打开 results 目录下的 index.html 文件,即可看到此次覆盖率的全部情况。也可以点击文件夹或者文件查看到具体文件,具体函数的覆盖率。

增量代码覆盖率统计: 在全量代码覆盖率结果的基础上,通过增量代码的 diff 文件,生成增量代码覆盖率。

  1. 得到基线代码和修改后的新代码的 diff 文件,注意拉取两份完全干净的代码进行比较获取 diff 结果,以免其他文件影响最终结果。同时注意两份代码的路径深度要一致,如下面的例子所示,基线代码和修改后的新代码,都在 /home/workspace/xx/ 路径下,深度一致。
diff -r  -N -x ".git" -x "*.gcov" -u /home/workspace/base/openGauss-server /home/workspace/increment/openGauss-server>> diff.txt

-r 表示递归,子目录也产生输出

-N 文件不存在当做空文件,比如新版本增加了一个文件,此选项会将每一行都输出

-x 表示排除,比如.git 不需要

-u 是 lcov 需要的格式

  1. 由全量覆盖率结果(coverage.info)和 diff 文件,生成增量覆盖率结果。addlcov 工具下载地址:https://github.com/Dragonliu2018/addlcov
addlcov --rc lcov_branch_coverage=1 --diff coverage.info  diff.txt -o increment.info --strip $dep --path $new_Addr

coverage.info:前面得到的全量覆盖率文件路径

increment.info:输出的增量覆盖率文件路径

$new_Addr: 原始代码路径

$dep:diff 文件中的代码路径深度,即分隔符”/”的个数(包括结尾的)

以前面的代码路径为例,原始代码路径为 /home/test/openGauss-server。

用来生成 diff.txt 文件的干净基线代码路径为 /home/workspace/base/openGauss-server。

用来生成 diff.txt 文件的干净增量代码路径为 /home/workspace/increment/openGauss-server。

那么 $new_Addr 应该为原始代码路径即 /home/test/openGauss-server。

$dep 应该为 5,即 /home/workspace/base/openGauss-server 的路径深度,这也是为何生成 diff.txt 时,要求基线代码和修改后的新代码保持深度一致。

同时命令中所有文件路径全部使用绝对路径,如果 coverage.info 文件中部分文件在增量修改后被删除了,在 coverage.info 里面把那一行删除

可以得出命令为:

addlcov --rc lcov_branch_coverage=1 --diff /home/test/openGauss-server/coverage.info  /home/test/openGauss-server/diff.txt -o /home/test/openGauss-server/increment.info --strip 5 --path /home/test/openGauss-server
  1. 收集增量覆盖率结果,同全量的操作一样:
shell
genhtml --rc lcov_branch_coverage=1 --no-prefix --no-sort increment.info -o incremen_results