7

我试图了解 gcov 工具的输出。不带选项运行它是有道理的,但我想尝试了解分支覆盖选项。不幸的是,很难理解这些分支做了什么以及为什么不使用它们。下面是一个方法的输出(使用最新的 LLVM/Clang 构建编译)。

function -[TestCoverageAppDelegate loopThroughArray:] called 5 returned 100% blocks executed 88%
        5:   30:- (NSInteger)loopThroughArray:(NSArray *)array {
        5:   31:    NSInteger i = 0;
       22:   32:    for (NSString *string in array) {
branch  0 taken 0
branch  1 taken 7
        -:   33:        
       22:   34:    }
branch  0 taken 4
branch  1 taken 3
branch  2 taken 0
branch  3 taken 3
        5:   35:    return i;
        -:   36:}

我已经通过这个运行了 5 次测试,传入 nil、一个空数组、一个包含 1 个对象的数组、一个包含 2 个对象的数组和一个包含 4 个对象的数组。我可以猜到,在第一种情况下,分支 1 的意思是“进入循环”,但我不知道分支 0 是什么。在第二种情况下,分支 0 似乎再次循环,分支 1 似乎结束循环,分支 3 继续/退出循环,但我不知道分支 2 是什么或为什么/何时执行。

如果有人知道如何破译分支信息,或者知道任何有关这一切的详细文档,我将不胜感激。

4

1 回答 1

3

Gcov 通过检测(编译时)每个基本机器命令块(您可以考虑汇编程序)来工作。基本块是指代码的线性部分,其中没有分支,也没有标签。因此,当且仅当您开始运行基本块时,您才会到达基本块的末尾。基本块以CFG(控制流图,将其视为有向图)组织,它显示了基本块之间的关系(从V1到V2的边是V1调用V2;而V2被V1调用)。因此,profile-arcs编译器模式和 gcov 想要获取每一行的执行计数,并通过计算基本块执行来做到这一点。CFG 中的一些边被检测了,有些则没有,因为图中的基本块之间存在代数关系。

您的 ObjC 构造(for..in)被降低(在早期编译中转换)为几个基本块。所以,gcov 看到 4 个分支,因为它只看到降低的 BB。它对这种降低一无所知,但它知道哪一行对应于每条汇编指令(这是调试信息)。因此,分支是 CFG 的边缘。

如果您想查看基本块,您应该对已编译程序进行汇编程序转储或反汇编二进制文件或从编译器转储 CFG。您可以对模式profile-arcs和非profile-arcs模式执行此操作并进行比较。

profile-arcs模式将有很多调用和增量,例如“__llvm_gcov_ctr”或“__llvm_gcda_edge”——它是基本块的实际检测。

于 2011-08-15T12:19:43.023 回答