了解gcov文件中的分支
我试图了解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是什么或者为什么/何时执行。
如果有人知道如何破译分支信息,或者知道任何详细的文档意味着什么,我会很感激帮助。
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” - 它是基本块的实际工具。