使用gcov进行代码覆盖率分析的并行运行

11

我已经为项目中的几个文件设置了C/C++代码覆盖率,使用gcov进行覆盖率测试。

可执行文件正在并行运行。这导致一些共享代码被并行运行。

我得到了损坏的.da文件或大小为零的.da文件。这是并行运行时的问题吗?

因为两个或多个可执行实例都试图在同一个.da文件上写入覆盖率计数,以记录每个执行语句的覆盖率计数?

如果是这样的话,是否有任何解决方法?

使用的Gcov版本为1.5。


2
你可以考虑更改运行覆盖测试的脚本,使得每次运行(无论是否并行)都使用不同的结果文件,这样怎么样? - Some programmer dude
但是为了运行不同的测试用例,希望获取累积计数器值以查看覆盖分析。共享代码部分恰好在并行运行,导致同时访问相同的.da文件。这可能会导致损坏。有什么帮助可以在并行情况下完成此操作而避免争用吗? - Dr. Debasish Jana
我知道的那些不是开源的。 - Ira Baxter
有人曾经成功实现过这个吗? - Arno Moonen
@ArnoMoonen 下面发布了三个解决方案。 - yugr
显示剩余2条评论
3个回答

6

我曾有类似的需求,通过设置GCOV_PREFIX环境变量来解决。

根据文档

GCOV_PREFIX 包含要添加到目标文件中绝对路径的前缀。前缀可以是绝对的或相对的。默认情况下没有前缀。

GCOV_PREFIX设置为每个可执行文件+执行唯一的自定义目录将强制运行时在指定目录中生成 ".gcda" ,而不是使用编译目录(其中 '.gcno' 位于)。

完成所有执行后,您将能够使用它们来生成合并运行报告。


1
谢谢!设置 GCOV_PREFIX_STRIPGCOV_PREFIX 使我能够将每个测试的 .gcda 文件放置在单独的目录中。现在我只需要想办法如何将它们组合起来。然后我就可以并行运行所有的测试了。 - thoni56
2
根据我的研究,您必须将.gcno和生成的.gcda放在一起。与其将.gcda复制到对象和.gcno所在的位置,我将.gcno复制到.gcda目录中。通过这种方式,我可以为每个测试单独创建覆盖信息。我还可以使用lcov -o total.coverage -a <coverage1> -a <coverage2> ...组合所有信息。 - thoni56

3

看起来您已经找到了问题的根本原因并正在寻找解决方法。
我已经成功地为一些使用gcov的项目配置了代码覆盖率。
以下是我想向您澄清的几点:

  • 每个被编译时使用--coverage选项插装的源文件都会生成一个.gcno文件。
  • 在执行时,我们会得到与每个gcno文件相对应的.gcda文件。

.gcno文件只是相关源代码文件的流程图结构。
.gcda文件是在执行时生成的实际覆盖数据。

因此,在您的情况下,当两个或多个执行尝试同时写入同一个.gcda文件时,就会产生冲突。
最简单的解决方法是串行运行测试(至少这是我所做的)。
您不需要担心丢失覆盖数据,因为.gcda文件会随着每次执行而追加,而不是覆盖。请记住,您不需要重新编译,因为这会改变.gcno文件,之前的.gcda文件将变得无用。


最简单的解决方法是串行运行测试 - 不幸的是,这对于递归程序(例如 clang)不起作用。 - yugr

2
然而,在更新的(9+)GCC版本中,另一种解决方案支持 -fprofile-dir 中的%p模式。
-fprofile-dir=coverage.%p

这样可以避免每次都需要显式地重新生成GCOV_PREFIX环境变量。它还可以实现更复杂的用例分析,例如递归运行相同的程序/库(如clanggcc)。

收集覆盖率后,您可以使用gcov-tool-many进行合并(它是gcov-tool的包装器,一次只能组合两个文件):
# Combine coverages
$ scripts/gcov-tool-many merge coverage.*
# Get rid of mangled names like #home#user#myproject#bin#main.gcda
for f in `find -name '#*.gc[dn][ao]'`; do
  mv $f $(basename $f | tr \# /)
done
# Generate the report
gcov *.gcno

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接