了解 gcov 文件中的分支

发布于 2024-11-29 13:12:43 字数 842 浏览 0 评论 0原文

我试图了解 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 是什么或为什么/何时执行它。

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

I'm trying to understand the output of the gcov tool. Running it with no options makes sense, but I'm wanting to try and understand the branch coverage options. Unfortunately it's hard to make sense of what the branches do and why they aren't taken. Below is the output for a method (compile using the latest LLVM/Clang build).

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:}

I've run 5 test through this, passing in nil, an empty array, an array with 1 object, and array with 2 objects and an array with 4 objects. I can guess that in the first case, branch 1 means "go into the loop" but I haven't a clue what branch 0 is. In the second case branch 0 seems to be loop through again, branch 1 seems to be end the loop and branch 3 is continue/exit the loop, but I have no idea what branch 2 is or why/when it would be executed.

If anyone knows how to decipher the branch info, or knows of any detailed documentation on what it all means, I'd appreciate the help.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

潜移默化 2024-12-06 13:12:43

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

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

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

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

Gcov works by instrumenting (while compiling) every basic block of machine commands (you can think about assembler). Basic block means a linear section of code, which have no branches inside it and no lables inside it. So, If and only if you start running a basic block, you will reach end of basic block. Basic blocks are organized in CFG (Control flow graph, think about it as directed graph), which shows relations between basicblocks (edge from V1 to V2 is V1 calls V2; and V2 is called by V1). So, profile-arcs mode of compiler and gcov want to get execution count for every line and do this via counting basic block executions. Some of edges in CFG are instrumented and some are not, because there are algebraic relations between basic blocks in graph.

Your ObjC construction (for..in) is lowered (converted in early compilation) to several basic blocks. So, gcov sees 4 branches, because it sees only lowered BBs. It knows nothing about this lowering, but it knows which line corresponds to every assembler instruction (this is debug info). So, branches are edges of CFG.

If you want to see basic blocks, you should do an assembler dump of compiled program or disassemble a binary or dump CFG from compiler. You can do this both for profile-arcs and non-profile-arcs modes and compare them.

profile-arcs mode will have a lot calls and increments of something like "__llvm_gcov_ctr" or "__llvm_gcda_edge" - it is an actual instrumentation of basic blocks.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文