C之(14)gcov覆盖率

C之(14)gcov覆盖率


Author: Once Day Date: 2024年12月30日

一位热衷于Linux学习和开发的菜鸟,试图谱写一场冒险之旅,也许终点只是一场白日梦…

漫漫长路,有人对你微笑过嘛…

全系列文章可参考专栏: C语言_Once-Day的博客-CSDN博客

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。人工智能学习网站 - 点击跳转。


参考文章:
  • gcov代码覆盖率测试-原理和实践总结-CSDN博客
  • 使用 Gcov 和 LCOV 度量 C/C++ 项目的代码覆盖率 - 知乎

C之(14)gcov覆盖率

Author: Once Day Date:2024年12月30日

漫漫长路,有人对你微笑过嘛…

参考引用文档:

  • gcov代码覆盖率测试-原理和实践总结-CSDN博客
  • 使用 Gcov 和 LCOV 度量 C/C++ 项目的代码覆盖率 - 知乎

文章目录

  • C之(14)gcov覆盖率
      • C之(14)gcov覆盖率
        • 1. 介绍
          • 1.1 背景
          • 1.2 gcov工作流程
          • 1.3 gcov工作原理
        • 2. 实践
          • 2.1 编译源码
          • 2.2 运行二进制文件
          • 2.3 生成覆盖率测试数据

1. 介绍
1.1 背景

在现代软件开发过程中,代码质量和可靠性至关重要。为了确保软件的正确性和稳定性,软件测试已成为开发流程中不可或缺的一部分。而在众多软件测试方法中,代码覆盖率测试因其客观、量化的特点而备受关注。

代码覆盖率测试是一种白盒测试方法,旨在衡量测试用例对代码的执行覆盖程度。通过插桩等技术手段,代码覆盖率测试工具可以记录并统计测试过程中每一条代码的执行情况,并以此计算出多种覆盖率指标,如语句覆盖率、分支覆盖率、条件覆盖率等。这些指标从不同维度反映了代码的测试充分性,为发现未被测试覆盖的代码片段提供了量化依据。

在代码覆盖率测试领域,Gcov是一款功能强大且被广泛使用的工具。Gcov由GNU Compiler Collection (GCC)提供,能够与GCC编译器无缝集成,支持C、C++等多种编程语言。通过在编译时添加特定参数,Gcov可以在程序执行过程中实时记录代码的执行频率,并在程序结束后生成详细的覆盖率报告。

Gcov的输出报告包含了每个源文件的执行概况,以及每一行代码的执行次数。同时,Gcov还提供了多种格式的输出,如HTML、XML等,便于用户查看和分析覆盖率数据。凭借其易用性和与GCC的紧密集成,Gcov已成为许多开发者进行代码覆盖率测试的首选工具。

除Gcov外,还有许多其他优秀的代码覆盖率测试工具,如:

  • LCOV,一款基于Gcov的图形化前端工具,能够生成更加直观和交互式的覆盖率报告。

  • Clover,一款适用于Java语言的代码覆盖率测试工具,提供了丰富的报告格式和与主流构建工具的集成。

  • Coverage.py,一款用于Python语言的代码覆盖率测试工具,支持分支覆盖率和HTML报告生成。

  • Istanbul,一款用于JavaScript语言的代码覆盖率测试工具,可以与主流的测试框架(如Mocha、Jasmine等)集成使用。

这些工具各有特色,为不同编程语言和开发环境下的代码覆盖率测试提供了便利。

1.2 gcov工作流程

在这里插入图片描述

图片来自文章:gcov代码覆盖率测试-原理和实践总结-CSDN博客

在使用Gcov进行代码覆盖率测试之前,首先需要对源代码进行特殊的编译处理。通常,这是通过在GCC编译器的编译选项中添加额外的参数来实现的。具体而言,需要在编译命令中加入"-fprofile-arcs"和"-ftest-coverage"两个选项。这两个选项的作用如下:

  • "-fprofile-arcs":该选项告知编译器在编译过程中插入必要的代码,用于记录程序执行流程和收集覆盖率数据。
  • "-ftest-coverage":该选项指示编译器生成专门用于覆盖率测试的辅助信息文件。

添加了这两个编译选项后,编译器会在编译过程中对源代码进行插桩,为后续的覆盖率数据收集做好准备。

在源码编译阶段,编译器会在目标代码中插入特殊的汇编指令,称为"插桩"。这些插桩代码的作用是在程序执行过程中记录代码的执行情况,并将相关数据写入辅助文件中。

插桩代码通常包括以下几个部分:

  • 在每个基本块的开头插入计数器,用于记录该基本块的执行次数。
  • 在每个函数的入口和出口处插入代码,用于记录函数的调用次数和返回情况。
  • 在程序的开始和结束位置插入代码,用于初始化和写入覆盖率数据文件。

通过插桩,Gcov可以精确地跟踪代码的执行流程,为后续的覆盖率分析提供必要的数据基础。

在编译过程中,编译器除了生成目标代码文件外,还会生成一个以".gcno"为后缀的辅助文件。这个文件包含了程序的静态结构信息,如函数定义、行号、基本块等。

.gcno文件的作用是为后续的覆盖率数据收集提供必要的上下文信息。当程序执行时,Gcov会根据.gcno文件中的信息,将收集到的覆盖率数据与源代码的结构进行关联,从而生成详细的覆盖率报告。

在编译并插桩后,程序就可以正常执行了。在执行过程中,之前插入的插桩代码会随着程序流程的进行而被触发,并将相关的执行数据写入到一个以".gcda"为后缀的文件中。

.gcda文件包含了程序运行过程中收集到的动态覆盖率数据,如每个基本块的执行次数、每个函数的调用次数等。这些数据是Gcov进行覆盖率分析的核心依据。

需要注意的是,.gcda文件是在程序执行结束时才会被写入磁盘。因此,为了获取完整的覆盖率数据,必须确保程序能够正常结束,并且对应的.gcda文件能够成功生成。

当程序执行完毕,并生成了.gcda文件后,就可以使用Gcov工具来分析覆盖率数据,并生成详细的覆盖率报告了。

通过运行"gcov"命令,并指定要分析的源代码文件,Gcov会自动读取对应的.gcno和.gcda文件,并将其中的信息进行综合分析。通常包括以下几个方面:

  • 每个源文件的总体执行情况,如执行的行数、未执行的行数、覆盖率等。
  • 每个函数的执行情况,包括函数的调用次数、行覆盖率等。
  • 每一行代码的执行次数,以及未被执行的代码行。

Gcov会将分析结果以文本格式输出,同时也支持生成HTML格式的报告,便于用户直观地查看和分析覆盖率信息。

通过对覆盖率报告的分析,开发者可以发现代码中的薄弱环节,如未被测试覆盖的代码块、执行频率较低的函数等,并据此改进测试用例和代码质量。

1.3 gcov工作原理

基本块(Basic Block, BB)是Gcov进行覆盖率分析的基本单位。一个基本块是指一组顺序执行的代码指令,它们只有一个入口和一个出口。换句话说,一个基本块中的指令要么全部执行,要么全部不执行。

在Gcov的工作过程中,编译器会将源代码划分为若干个基本块。每个基本块都会被赋予一个唯一的标识号,用于后续的覆盖率数据收集和分析。

跳转(ARC)是指在基本块之间的控制流转移。当程序执行完一个基本块后,根据条件判断或函数调用等因素,会选择下一个要执行的基本块,这个过程就称为跳转。

在Gcov中,跳转是连接基本块的重要概念。通过跟踪和记录跳转的执行情况,Gcov可以构建出程序的动态执行流程,并据此计算覆盖率指标。

**程序流图(Control Flow Graph, CFG)**是一种表示程序控制流的有向图。在程序流图中,每个节点表示一个基本块,而有向边则表示基本块之间的跳转关系。

通过构建程序流图,Gcov可以直观地表示程序的静态结构和动态执行路径。在进行覆盖率分析时,Gcov会根据程序流图和收集到的执行数据,计算出各个基本块和跳转的执行次数,并生成相应的覆盖率报告。

为了实现覆盖率数据的收集,Gcov在编译阶段会对源代码进行插桩。插桩是一种代码插入技术,它在不影响程序原有逻辑的前提下,在特定位置插入额外的代码,用于记录程序的执行情况。

在Gcov中,插桩主要分为以下两类:

  • 基本块计数器:在每个基本块的开头,Gcov会插入一个计数器,用于记录该基本块的执行次数。当程序执行到该基本块时,计数器就会自动加1。

  • 跳转计数器:对于每个跳转(ARC),Gcov会插入一个计数器,用于记录该跳转的执行次数。当程序执行到相应的跳转语句时,计数器就会自动加1。

通过插桩,Gcov可以在程序运行过程中动态地更新基本块和跳转的执行计数。这些计数信息会被写入到.gcda文件中,供后续的覆盖率分析使用。

在收集到程序的执行计数数据后,Gcov就可以计算各种覆盖率指标了。常见的覆盖率指标包括:

  • 语句覆盖率:表示被执行过的代码行数占总代码行数的比例。

  • 分支覆盖率:表示被执行过的条件分支数占总条件分支数的比例。

  • 路径覆盖率:表示被执行过的路径数占总可能路径数的比例。

Gcov会根据基本块和跳转的执行计数,结合程序流图的结构信息,自动计算出这些覆盖率指标。通过分析覆盖率指标,开发者可以全面了解测试用例对代码的覆盖情况,发现未被充分测试的代码区域,并有针对性地改进测试策略。

2. 实践
2.1 编译源码

下面以cmake脚本为例,makefile之类脚本都是类似的,因为只需要在CFLAGS加上--coverage即可。

当在编译命令中添加--coverage选项时,GCC编译器会自动启用生成覆盖率数据所需的插桩代码和辅助文件。

  • -fprofile-arcs:该选项指示编译器在编译过程中插入必要的代码,用于记录程序执行流程和收集覆盖率数据。它会在每个基本块的开头插入计数器,并在函数的入口和出口处插入代码,以跟踪函数的调用次数和返回情况。
  • -ftest-coverage:该选项告知编译器生成专门用于覆盖率测试的辅助信息文件,如.gcno文件。这些文件包含了程序的静态结构信息,如函数定义、行号、基本块等,为后续的覆盖率数据收集和分析提供必要的上下文。
# 启用覆盖率测试
option(COVERAGE "Enable coverage reporting" OFF)
if(COVERAGE)list(APPEND CXX_FLAGS "--coverage")list(APPEND CXX_FLAGS -fprofile-dir=${CMAKE_CURRENT_SOURCE_DIR}/output/coverage)list(APPEND C_FLAGS "--coverage")
endif()

-fprofile-dir参数用于指定Gcov生成的覆盖率数据文件(.gcda)和辅助信息文件(.gcno)的存储目录。默认情况下,这些文件会被存储在与源代码文件相同的目录下。但是,通过使用-fprofile-dir参数,我们可以将这些文件存储到一个单独的目录中,以便更好地组织和管理覆盖率数据。

-fprofile-dir参数的语法如下:

-fprofile-dir=<directory>

其中,<directory>表示要存储覆盖率数据文件和辅助信息文件的目录路径。该路径可以是绝对路径或相对路径。

举个例子,如果我们想将覆盖率数据文件存储到当前目录下的"coverage_data"子目录中,可以使用以下编译选项:

-fprofile-dir=./coverage_data

当使用-fprofile-dir参数指定了存储目录后,Gcov生成的覆盖率数据文件(.gcda)和辅助信息文件(.gcno)的命名格式也会发生相应的变化。

对于.gcda文件,其命名格式为:

<source_file_name>.<extension>.gcda

其中,<source_file_name>表示对应的源代码文件名(不包括路径),<extension>表示源代码文件的扩展名。

例如,如果源代码文件为"main.cpp",则对应的.gcda文件名将是:

main.cpp.gcda
2.2 运行二进制文件

编译成功后,运行单元测试程序,gcda文件输出在指定的目录中,如下所示:

ubuntu->ANMK_netdog:$ ./output/bin/anmk-base-tests
......
ubuntu->ANMK_netdog:$ ll output/coverage
total 472
drwxrwxr-x 2 ubuntu ubuntu 12288 Dec 30 22:57  ./
drwxrwxr-x 6 ubuntu ubuntu  4096 Sep  5 14:46  ../
-rw-rw-r-- 1 ubuntu ubuntu    88 Dec 30 22:57 '#home#ubuntu#ANMK_netdog#unwind.cpp.gcda'
-rw-rw-r-- 1 ubuntu ubuntu    68 Dec 30 22:57 '#home#ubuntu#ANMK_netdog#alias.cpp.gcda'
-rw-rw-r-- 1 ubuntu ubuntu  5640 Dec 30 22:57 '#home#ubuntu#ANMK_netdog#alias_unittest.cpp.gcda'
......
2.3 生成覆盖率测试数据

LCOV(Linux Code Coverage)是一个基于Gcov的图形化前端工具,它可以收集和处理Gcov生成的覆盖率数据,并生成易于阅读和导航的HTML格式覆盖率报告。LCOV提供了一组命令行工具,用于执行各种覆盖率数据的操作,如数据捕获、过滤、合并和生成报告等。

在使用lcov工具之前,需要对gcda文件的名字进行转换,去掉前缀路径:

#!/usr/bin/env python3
# 将 xxx#xxx#file.gcda 文件名修改为 file.gcda
import os
import sysdef gcov_file_deal(path):for root, dirs, files in os.walk(path):for file in files:if file.endswith('.gcda'):new_file = file.split('#')[-1]os.rename(os.path.join(root, file), os.path.join(root, new_file))print(f'{file} -> {new_file}')if __name__ == '__main__':if len(sys.argv) < 2:print(f'Usage: {sys.argv[0]} <path>')sys.exit(1)gcov_file_deal(sys.argv[1])

执行改脚本后,gcda文件的名字都标准化了:

ubuntu->ANMK_netdog:$ ./gcov_file_deal.py output/coverage
#home#ubuntu#ANMK_netdog#unwind.cpp.gcda -> unwind.cpp.gcda
......

然后从源码编译输出里面收集gcno文件,如下所示:

ubuntu->ANMK_netdog:$ find build/debug-cpp11/ -name "*.gcno" -exec cp -v {} output/coverage \;
'build/strings/stringprintf_unittest.cpp.gcno' -> 'output/coverage/stringprintf_unittest.cpp.gcno'
'build/strings/string_util_constants.cpp.gcno' -> 'output/coverage/string_util_constants.cpp.gcno'

捕获覆盖率数据后,我们可以使用genhtml工具将.info文件转换为可视化的HTML报告,例如:

genhtml output/coverage/coverage.info --output-directory output/coverage/

其中,--output-directory选项指定了生成HTML报告的输出目录。

然后可以打包文件,放在网页服务器下进行查看,如下所示:

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

简易屏幕共享工具-基于WebSocket

前面写了两个简单的屏幕共享工具&#xff0c;不过那只是为了验证通过截屏的方式是否可行&#xff0c;因为通常手动截屏的频率很低&#xff0c;而对于视频来说它的帧率要求就很高了&#xff0c;至少要一秒30帧率左右。所以&#xff0c;经过实际的截屏工具验证&#xff0c;我了解…

Paperlib(论文管理工具)

Paperlib 是一个简单好用的论文管理工具。软件接入各学科数据库用于匹配论文元数据&#xff0c;逐步为每一个学科&#xff08;例如计算机科学&#xff0c;物理学等&#xff09;定制化数据库组合提高检索精度。尤其是精准的会议论文元数据检索能力。还可以管理你的论文&#xff…

c# 2024/12/27 周五

6《详解类型、变量与对象》36 详解类型、变量与对象 _1_哔哩哔哩_bilibili

Formality:匹配(match)是如何进行的?

相关阅读Formalityhttps://blog.csdn.net/weixin_45791458/category_12841971.html?spm1001.2014.3001.5482 匹配点、对比点和逻辑锥 匹配指的是Formality工具尝试将参考设计中的每个匹配点与实现设计中的相应匹配点进行配对&#xff0c;这里的匹配点包括对比点(Compare Point…

分布式算法(五):初识ZAB协议

文章目录 一、什么是Zookeeper二、ZAB与Zookeeper的关系为什么Zookeeper不直接使用Paxos 三、ZAB简介1.名词解释提案&#xff08;Proposal&#xff09;事务&#xff08;Transaction&#xff09;原子广播&#xff08;Atomic Broadcast&#xff09; 2.集群角色领导者&#xff08;…

Mybatis 01

JDBC回顾 select 语句 "select *from student" 演示&#xff1a; 驱动包 JDBC 的操作流程&#xff1a; 1. 创建数据库连接池 DataSource 2. 通过 DataSource 获取数据库连接 Connection 3. 编写要执⾏带 ? 占位符的 SQL 语句 4. 通过 Connection 及 SQL 创建…

tensorboard的界面参数与图像数据分析讲解

目录 1.基础概念&#xff1a; (a)精确率与召回率&#xff1a; (b)mAP: (c)边界框损失&#xff1a; (d)目标损失&#xff1a; (e)分类损失&#xff1a; (f):学习率&#xff1a; 2.设置部分&#xff08;最右边部分&#xff09;&#xff1a; GENERAL&#xff08;常规设置…

《计算机网络A》单选题-复习题库解析-2

目录 51、下列关于以太网网卡地址特点的说法中&#xff0c;不正确的是&#xff08; &#xff09;。 52、当一个Web Browser向一个使用标准服务器端口的Web Server提出请求时&#xff0c;那么在服务返回的响应包中&#xff0c;所使用的源端口是&#xff08; &#xff0…

Linux总结之CentOS Stream 9安装mysql8.0实操安装成功记录

Linux总结之CentOS Stream 9安装mysql8.0实操安装成功记录 由于网上很多的mysql8.0安装教程都是老版本或者安装过程记录有问题&#xff0c;导致经常安装到一半需要删除重新安装。所以将成功的实操安装过程记录一下&#xff0c;方面后面查阅&#xff0c;大家还有问题的可以在此讨…

高等数学学习笔记 ☞ 无穷小与无穷大

1. 无穷小 1. 定义&#xff1a;若函数当或时的极限为零&#xff0c;那么称函数是当或时的无穷小。 备注&#xff1a; ①&#xff1a;无穷小描述的是自变量的变化过程中&#xff0c;函数值的变化趋势&#xff0c;绝不能认为无穷小是一个很小很小的数。 ②&#xff1a;说无穷小时…

KMP 2024 年总结,Kotlin 崛起的一年

2024 Google I/O 上正式官宣了 KMP&#xff08;Kotlin Multiplatform&#xff09;项目&#xff0c;它是 Google Workspace 团队的一项长期「投资」项目&#xff0c;由 JetBrains 开发维护和开源的项目&#xff0c;简单来说&#xff0c;JetBrains 主导&#xff0c;Google Worksp…

【SpringBoot教程】搭建SpringBoot项目之编写pom.xml

&#x1f64b;大家好&#xff01;我是毛毛张! &#x1f308;个人首页&#xff1a; 神马都会亿点点的毛毛张 &#x1f44f;今天毛毛张分享的内容主要是Maven 中 pom 文件&#x1f195;&#xff0c;涵盖基本概念、标签属性、配置等内容 文章目录 1.前言&#x1f96d;2.项目基本…

【Java 学习】详讲代码块:控制流语句代码块、方法代码块、实例代码块(构造代码块)、静态代码块、同步代码块

&#x1f4ac; 欢迎讨论&#xff1a;如对文章内容有疑问或见解&#xff0c;欢迎在评论区留言&#xff0c;我需要您的帮助&#xff01; &#x1f44d; 点赞、收藏与分享&#xff1a;如果这篇文章对您有所帮助&#xff0c;请不吝点赞、收藏或分享&#xff0c;谢谢您的支持&#x…

【亚马逊云科技】基于Amazon EKS部署高可用的OceanBase的最佳实践

一、前言 随着企业业务的快速发展和数据量的不断增长&#xff0c;高性能、高可用的数据库解决方案成为了关键需求。OceanBase作为一款分布式关系型数据库&#xff0c;以其高扩展性、高可用性和高性能的特点&#xff0c;逐渐受到企业的广泛关注。然而&#xff0c;在复杂的分布式…

【工具】—— SpringBoot3.x整合swagger

Swagger 是一个规范和完整的框架&#xff0c;用于生成、描述、调用和可视化 RESTful 风格的 Web 服务的接口文档。Swagger简单说就是可以帮助生成接口说明文档&#xff0c;操作比较简单添加注解说明&#xff0c;可以自动生成格式化的文档。 项目环境 jdk17SpringBoot 3.4.0Sp…

从0入门自主空中机器人-2-1【无人机硬件框架】

关于本课程&#xff1a; 本次课程是一套面向对自主空中机器人感兴趣的学生、爱好者、相关从业人员的免费课程&#xff0c;包含了从硬件组装、机载电脑环境设置、代码部署、实机实验等全套详细流程&#xff0c;带你从0开始&#xff0c;组装属于自己的自主无人机&#xff0c;并让…

基于视觉语言模型(VLM)的CogAgent

前言 CogAgent 是由清华大学与智谱AI联合推出的一个多模态大模型&#xff0c;专注于图形用户界面&#xff08;GUI&#xff09;的理解和导航。它代表了在视觉语言模型&#xff08;VLM&#xff09;领域的一项重要进展&#xff0c;特别是在GUI Agent能力方面。相较于传统的基于文…

win10、win11-鼠标右键还原、暂停更新

系统优化 win 10jihuo win 11jihuo鼠标右键还原暂停更新 update 2024.12.28win 10 jihuo winx&#xff0c;打开powershell管理员&#xff0c;输入以下命令,选择1并等待 irm https://get.activated.win | iex参考&#xff1a;https://www.bilibili.com/video/BV1TN411M72J/?sp…

C# 找出给定三角形的所有角度(Find all angles of a given triangle)

给定三角形在二维平面上所有三个顶点的坐标&#xff0c;任务是找到所有三个角度。 示例&#xff1a; 输入&#xff1a;A (0, 0), B (0, 1), C (1, 0) 输出&#xff1a;90, 45, 45 为了解决这个问题&#xff0c;我们使用下面的余弦定律。 c^2 a^2 …

【数据结构】(Python)差分数组。差分数组与树状数组结合

差分数组&#xff1a; 基于原数组构造的辅助数组。用于区间修改、单点查询。区间修改的时间复杂度O(1)。单点查询的时间复杂度O(n)。差分数组的元素&#xff1a;第一个元素等于原数组第一个元素&#xff0c;从第二个元素开始是原数组对应下标的元素与前一个元素的差&#xff0…