编译链接实战(22)C/C++代码覆盖率统计报告生成

Gcov 查看代码覆盖率

文章目录

    • GCOV 工具简介
    • gcov 使用
    • lcov
    • 相关编译选项

GCOV 工具简介

gcov是一个测试代码覆盖率的工具,它是 gcc 自带的查看代码覆盖率的工具。

与GCC结合使用,可以分析您的程序以帮助创建更高效、运行更快的代码,并发现程序中未经测试的部分。您可以将gcov作为性能分析工具使用,以帮助发现优化工作对代码产生最佳效果的位置。您还可以将gcov与另一种性能分析工具gprof一起使用,以评估代码的哪些部分使用了最多的计算时间。

性能分析工具可以帮助您分析代码的性能。使用像gcov或gprof这样的分析器,您可以找出一些基本的性能统计数据,例如:

  • 每行代码执行了多少次
  • 实际执行了哪些代码行
  • 每个代码段使用了多少计算时间

一旦您了解了编译后的代码如何工作,就可以查看每个模块,看看哪些模块应该进行优化。gcov可以帮助您确定在哪里进行优化工作。

软件开发人员还结合测试套件使用覆盖率测试,以确保软件实际上足够好,可以发布。测试套件可以验证程序按预期工作;覆盖率程序测试测试套件执行了程序的多少部分。然后,开发人员可以确定需要向测试套件中添加哪些类型的测试用例,以创建更好的测试和更好的最终产品。

如果您计划使用gcov,应该在不优化的情况下编译代码,因为通过将一些代码行组合成一个函数的优化,可能无法为您提供寻找“热点”所需的信息,即代码使用大量计算时间的地方。同样,因为gcov按行(最低分辨率)累积统计数据,它最适合一种编程风格,即每行只放置一个语句。如果您使用复杂的宏,这些宏展开为循环或其他控制结构,统计数据就不那么有用——它们只报告宏调用出现的行。如果您的复杂宏表现得像函数,您可以用内联函数替换它们来解决这个问题。

gcov创建一个名为sourcefile.gcov的日志文件,指示源文件sourcefile.c的每一行执行了多少次。您可以将这些日志文件与gprof一起使用,以帮助微调程序的性能。gprof提供您可以与从gcov获得的信息一起使用的计时信息。

gcov仅适用于用GCC编译的代码。它与任何其他性能分析或测试覆盖机制不兼容。

使用效果如下图所示:

img

程序运行完成后,可以查看每个文件的代码覆盖率情况,上面报告中展示了每个文件的行覆盖率,函数覆盖率和分支覆盖率。

打开一个文件的覆盖率报告,页面对开始有文件的基本信息描述,以 FreeRTOS 的 task.c 为例,它的有效代码行数为 921 行,共 24 个函数(几千行的文件其实也没多少嘛~)

img

img

在覆盖率的正文,有该文件的完整代码,并用不同颜色进行高亮标注了:

  • 蓝色表示运行被覆盖的代码,前面的数字表示代码执行次数。
  • 红色表示未执行代码。
  • 白色表示无效代码,包括注释,空行和未编译代码。

gcov 使用

使用 gcov 的流程非常简单,只需要三步即可。 下面以 hello world 为例,展示生成覆盖率报告。

代码如下:

//main.c

#include <stdio.h>

int main(int argc, char **argv) {
    printf("hello world\n");
    return 0;
}

第一步: 添加编译参数 -fprofile-arcs -ftest-coverage

在所需要的生产覆盖率的文件中,添加编译参数,编译代码生成目标文件,同时会生成 *.gcno 文件,其中包含文件的行号等信息。
GCC C/C++代码覆盖率统计生成

gcc main.c -c -fprofile-arcs -ftest-coverage -o main.o
ls # 输出文件列表:
# main.c  main.gcno  main.o
gcc main.o -lgcov -o main

第二步: 添加链接参数 -lgcov ,运行程序

运行程序后,会生成一个 *.gcda 文件,里面包含代码执行次数等数据。

gcc main.o -lgcov -o main
# 运行程序
./main
# hello world
ls # 输出文件列表:
#main  main.c  main.gcda  main.gcno  main.o

第三步: 输出覆盖率报告 使用下面命令输出覆盖率报告

# 第一次使用前安装工具
sudo apt install lcov

# 生成覆盖率文本报告
lcov -c -d . -o test.info --rc lcov_branch_coverage=1 
# 生成覆盖率网页报告
genhtml --branch-coverage -o result test.info 

输入上面两/三条命令后在,执行命令的文件路径可以看到一个 result 文件夹,在里面就是对应的网页覆盖率报告。

img

用浏览器打开 index.html 就可以看到最开始展示的覆盖率信息了。

lcov

lcov 是 GCC 覆盖率测试工具 gcov 的图形化前端,用于收集多个源文件的行、函数和分支覆盖率数据,并创建包含覆盖信息的 HTML 页面。它还添加了概览页面,以便在文件结构中进行方便的导航。

使用 lcov 收集覆盖率数据,并使用 genhtml 创建 HTML 页面。覆盖率数据可以从当前正在运行的 Linux 内核或用户空间应用程序中收集。要做到这一点,您需要完成以下准备步骤:

  1. 收集覆盖率数据:首先,使用 lcov 工具来收集代码的覆盖率数据。您可以通过在编译时添加 -ftest-coverage-fprofile-arcs 选项来生成覆盖率数据的中间文件。然后,通过运行应用程序或测试套件来执行代码路径,以便生成覆盖率数据。
  2. 生成 HTML 页面:接下来,使用 genhtml 工具将收集到的覆盖率数据转换为 HTML 页面。genhtml 将分析覆盖率数据,并生成带有覆盖信息注释的源代码的 HTML 页面,以及用于导航文件结构的概览页面。

这些工具的结合使用使得开发人员能够更直观地查看代码的覆盖情况,从而更好地理解测试覆盖范围和质量。通过分析生成的 HTML 页面,开发人员可以识别哪些部分的代码需要更多的测试覆盖,以及哪些部分已经得到了良好的覆盖。

总的来说,lcov 和 genhtml 工具的组合为开发人员提供了一种强大的方式来收集和可视化代码覆盖率数据,从而帮助他们更好地进行测试和代码质量管理。如果您需要进一步解释或有其他问题,请随时告诉我,我很乐意为您提供帮助。

关键选项:

   -r tracefile pattern
   --remove tracefile pattern
          Remove data from tracefile.

          Use this switch if you want to remove coverage data for a particular set of files from a tracefile. Additional command line parameters will be interpreted as  shell  wildcard  patterns  (note
          that they may need to be escaped accordingly to prevent the shell from expanding them first).  Every file entry in tracefile which matches at least one of those patterns will be removed.

          Note: The pattern must be specified to match the absolute path of each source file.

          The result of the remove operation will be written to stdout or the tracefile specified with -o.

          Only one of  -z, -c, -a, -e, -r, -l, --diff or --summary may be specified at a time.

   --exclude pattern
          Exclude source files matching pattern.

          Use this switch if you want to exclude coverage data for a particular set of source files matching any of the given patterns. Multiple patterns can be specified by  using  multiple  --exclude
          command line switches. The patterns will be interpreted as shell wildcard patterns (note that they may need to be escaped accordingly to prevent the shell from expanding them first).

          Note: The pattern must be specified to match the absolute path of each source file.

          Can be combined with the --include command line switch. If a given file matches both the include pattern and the exclude pattern, the exclude pattern will take precedence.
 --include pattern
              Include source files matching pattern.

              Use this switch if you want to include coverage data for only a particular set of source files matching any of the given patterns. Multiple patterns can be specified by using  multiple  --in‐
              clude command line switches. The patterns will be interpreted as shell wildcard patterns (note that they may need to be escaped accordingly to prevent the shell from expanding them first).

              Note: The pattern must be specified to match the absolute path of each source file.
       --rc keyword=value
              Override a configuration directive.

              Use  this option to specify a keyword=value statement which overrides the corresponding configuration statement in the lcovrc configuration file. You can specify this option more than once to
              override multiple configuration statements.  See lcovrc(5) for a list of available keywords and their meaning.

相关编译选项

  • -fprofile-arcs

该选项用于在程序执行时对程序流程弧进行插装,记录每个分支和调用被执行的次数以及它们被取或返回的次数。对于支持具有优先级支持的构造函数的目标,剖析能够正确处理构造函数、析构函数以及用作全局变量类型的类的C++构造函数(和析构函数)。

当编译后的程序退出时,会将这些数据保存到名为 auxname.gcda 的文件中,每个源文件都会生成一个相应的 .gcda 文件。这些数据可以用于基于profile-directed 的优化(例如 -fbranch-probabilities),或者用于测试覆盖率分析(例如 -ftest-coverage)。每个目标文件的 auxname 是从输出文件的名称生成的,如果显式指定了输出文件并且它不是最终可执行文件,则 auxname 会采用源文件的基本名称。在这两种情况下,任何后缀都会被移除(例如对于输入文件 dir/foo.cauxnamefoo.gcda;对于指定为 -o dir/foo.o 的输出文件,auxnamedir/foo.gcda)。

简而言之,通过使用 -fprofile-arcs 编译选项,您可以收集程序在执行过程中的代码覆盖率和执行路径信息,从而可以进行优化或测试覆盖率分析。

  • –coverage

这个选项是 -fprofile-arcs -ftest-coverage(编译时)和 -lgcov(链接时)的同义词。主要做了以下工作:

  1. 使用 -fprofile-arcs 和优化、代码生成选项来编译源文件。对于测试覆盖率分析,还需额外加上 -ftest-coverage 选项。并不需要对程序中的每个源文件都进行剖析。
  2. 另外使用 -fprofile-abs-path 选项来编译源文件,以在 .gcno 文件中创建绝对路径名。这样可以让 gcov 在项目中的编译发生在不同工作目录的情况下正确找到源文件。
  3. 使用 -lgcov-fprofile-arcs(后者暗含了前者)来链接您的目标文件。
  4. 运行程序以生成弧剖析信息。可以多次重复这个过程。您可以同时运行多个程序实例,只要文件系统支持锁定,数据文件就会被正确地更新。除非启用了严格的 ISO C 方言选项,否则 “fork” 调用会被检测并正确处理,而不会重复计数。
  5. 对于基于profile-directed的优化,需要使用相同的优化和代码生成选项再次编译源文件,并加上 -fbranch-probabilities
  6. 对于测试覆盖率分析,使用 gcov 从 .gcno.gcda 文件中生成人类可读的信息。请参考 gcov 文档以获取更多信息。
    特殊环境使用注意点:

在正常使用 gcov 是非常简单的,但是在特殊项目中使用 gcov 需要注意一些坑,否则就会跟我一样掉进去出不来。。。

  • 链接时,会在 .init_array 段插入 __gcov_init() 函数,该函数在 main 运行之前初始化 gcov 运行环境。
  • 如果修改过链接脚本,注意 .init_array 的全局构造函数是否执行成功。
  • 和上面一样,链接时,会在全局析构函数中插入 __gcov_exit() 函数,在 main 执行结束后,输出 *.gcda 文件。
  • 如果程序为异常退出,则不会生成 *.gcda 文件,此时需要在代码适当位置插入 __gcov_flush() 函数,将文件进行保存。
  • 默认状态 *.gcda 文件和 *.gcno 文件所在文件夹相同,如果需要修改输出文件夹,可通过添加环境变量:GCOV_PREFIX 和 GCOV_PREFIX_STRIP
  • GCOV_PREFIX_STRIP=16 , 为将原有路径裁剪16个文件夹。 GCOV_PREFIX=/home/tester/build , 为将裁剪后的路径添加前缀 例如:上文中默认 main.gcda 所在的文件 /home/tester/main.gcda,裁剪后添加前缀后变为/home/tester/build/main.gcda

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/421618.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

决定西弗吉尼亚州地区版图的关键历史事件

决定西弗吉尼亚州地区版图的关键历史事件&#xff1a; 1. 内部分裂与美国内战&#xff1a; - 在1861年美国内战爆发时&#xff0c;弗吉尼亚州作为南方邦联的一员宣布退出美利坚合众国。然而&#xff0c;弗吉尼亚州西部的一些县由于经济结构&#xff08;主要是农业非依赖奴隶制…

Python3零基础教程之字符串专题进阶

大家好&#xff0c;我是千与编程&#xff0c;上一期我们讲解了Python3编程语言中的数组与列表专题。这一期我们讲解了字符串专题初阶。 在 Python3 的字符串专题进阶教程中&#xff0c;我们将深入探讨更高级的字符串操作技巧&#xff0c;包括字符串切片、替换、去除空白、分割与…

3.1日学习打卡----初学FastDFS(一)

3.1日学习打卡 目录: 3.1日学习打卡一. 为什么要使用分布式文件系统二. FastDFS简介核心概念上传机制下载机制FastDFS环境搭建_LinuxFastDFS指令 一. 为什么要使用分布式文件系统 单机时代 初创时期由于时间紧迫&#xff0c;在各种资源有限的情况下&#xff0c;通常就直接在项…

Acwing周赛记录

很难得参加一次周赛hhhhh这次参加的是第144场周赛&#xff0c;一共有三道题 AcWing 5473. 简单数对推理 给定两个整数数对&#xff0c;每个数对都包含两个 1∼9 之间的不同整数。 这两个数对恰好包含一个公共数&#xff0c;即恰好有一个整数同时包含于这两个数对。 给定这两…

政安晨【示例演绎虚拟世界开发】(三):TypeScript编程语言——实现游戏脚本开发

TypeScript是一种开源的编程语言&#xff0c;由微软开发和维护。它是JavaScript的一个超集&#xff0c;意味着任何合法的JavaScript代码也是合法的TypeScript代码。TypeScript通过添加静态类型检查和一些新特性来增强JavaScript的功能。 它在JavaScript的基础上添加了类型系统…

if语句用法

if语句是单条件分支语句 定义&#xff1a;根据一个条件来控制程序执行流程(如图3.2)。 语法格式&#xff1a; if&#xff08;表达式&#xff09;{ 若干语句 } ★注意★&#xff1a; ① 表达式的值必须是boolean 型&#xff1b; ② 不能用0代表false&#xff1b;用1代表 true&am…

Linux 之压缩与解压相关命令的基础用法

目录 1、zip 与 unzip 2、gzip 命令 3、tar 命令 1、zip 与 unzip 在桌面新建一个文件和文件夹用于测试 在 test 目录下有一个 1.txt 文件 我们使用 zip 命令对其压缩 用法&#xff1a; zip 自定义压缩包名 被压缩文件路径位置 zip myon.zip 1.txt 因为我们这里就是在 …

『运维备忘录』之 RegEx 正则表达式实例汇总

运维人员不仅要熟悉操作系统、服务器、网络等知识&#xff0c;甚至对于开发相关的也要有所了解。很多运维工作者可能一时半会记不住那么多命令、代码、方法、原理或者用法等等。这里我将结合自身工作&#xff0c;持续给大家更新运维工作所需要接触到的知识点&#xff0c;希望大…

抽象类与抽象方法

文章目录 抽象类抽象类的特点 抽象方法抽象方法的特点 模板设计模式模板设计模式能解决的问题示例 #抽象类与抽象方法 抽象类 用abstract关键字来修饰一个类时&#xff0c;这个类就叫抽象类。 public abstract 类名{... }抽象类的特点 1&#xff09;抽象类不能被实例化。 2&…

javaScript 深浅拷贝

javaScript深浅拷贝 浅拷贝 自己创建一个新的对象&#xff0c;来接受你要重新复制或引用的对象值。如果对象属性是基本的数据类型&#xff0c;复制的就是基本类型的值给新对象&#xff0c;但如果属性是引用数据类型&#xff0c;复制的就是内存中的地址&#xff0c;如果其中一个…

pip降级在pycharm中

PyCharm依赖于"–build-dir"参数安装第三方库&#xff0c;但该参数在最新的23.0版pip中已删除 解决办法就是降级pip&#xff0c;PyCharm中选择File&#xff0c;找到编译器&#xff0c;点击pip&#xff0c;勾选对应版本即可 或者在cmd中执行运行python -m pip install…

swift 长按桌面图标弹出快捷选项

文章目录 一、3D Touch二、主屏交互1. 静态添加2. 动态添加三、监听主屏交互按钮的点击事件四、预览和跳转1. 注册3D touch2. 实现协议3. 在目标控制器复写previewActionItems4. 使用UIContextMenuConfiguration一、3D Touch 3D Touch通过屏幕下方的压力感应器来感知不同的压力…

蓝桥杯Java B组历年真题(2013年-2019年)

一、2013年真题 1、世纪末的星期 使用日期类判断就行&#xff0c;这里使用LocalDate&#xff0c;也可以使用Calendar类 答案 2099 使用LocalDate import java.time.LocalDate; import java.time.format.DateTimeFormatter; // 1:无需package // 2: 类名必须Main, 不可修改p…

【AIGC】微笑的秘密花园:红玫瑰与少女的美好相遇

在这个迷人的画面中&#xff0c;我们目睹了一个迷人的时刻&#xff0c;女子则拥有一头柔顺亮丽的秀发&#xff0c;明亮的眼睛如同星河般璀璨&#xff0c;优雅而灵动&#xff0c;她的微笑如春日暖阳&#xff0c;温暖而又迷人。站在红玫瑰花瓣的惊人洪水中。 在一片湛蓝无云的晴…

YOLOv9有效提点|加入BAM、CloFormer、Reversible Column Networks、Lskblock等几十种注意力机制(二)

专栏介绍&#xff1a;YOLOv9改进系列 | 包含深度学习最新创新&#xff0c;主力高效涨点&#xff01;&#xff01;&#xff01; 一、本文介绍 本文只有代码及注意力模块简介&#xff0c;YOLOv9中的添加教程&#xff1a;可以看这篇文章。 YOLOv9有效提点|加入SE、CBAM、ECA、SimA…

【机器学习300问】25、常见的模型评估指标有哪些?

模型除了从数据划分的角度来评估&#xff0c;我上一篇文章介绍了数据集划分的角度&#xff1a; 【机器学习300问】24、模型评估的常见方法有哪些&#xff1f;http://t.csdnimg.cn/LRyEt 还可以从一些指标的角度来评估&#xff0c;这篇文章就带大家从两个最经典的任务场景介绍…

天津公租房租金怎么算?附计算方式

天津公共租赁住房租金如何计算&#xff1f;附计算方法 天津市公共租赁住房租金租金标准建筑面积&#xff08;100分-减分&#xff09;。 公共租赁住房租金按照建筑面积计算。 应收租金以人民币计算&#xff0c;低于人民币的部分四舍五入。 具体内容见正文。 申请天津公共租赁住…

Go 与 Rust:导航编程语言景观

在当今构建软件时&#xff0c;开发者在编程语言上有着丰富的选择。两种脱颖而出的语言是 Go 和 Rust - 都很强大但却截然不同。本文将从各种因素比较这两种语言&#xff0c;以帮助您确定哪种更适合您的需求。 我们将权衡它们在并发、安全性、速度、互操作性等方面的方法。我们将…

软件系统开发流程规范

目的&#xff1a;规范系统开发流程&#xff0c;提高系统开发效率。 立项申请需求分析方案设计方案评审开发调整测试阶段系统培训试运行测试验收投入使用 所有文档过去进主页获取。

基于 STM32U5 片内温度传感器正确测算温度

目录预览 1、引言 2、问题 3、小结 01 引言 STM32 在内部都集成了一个温度传感器&#xff0c;STM32U5 也不例外。这个位于晶圆上的温度传感器虽然不太适合用来测量外部环境的温度&#xff0c;但是用于监控晶圆上的温度还是挺好的&#xff0c;以防止芯片过温运行。 02 问题…