MariaDB 中的 Gcov

Gcov 是一个覆盖率测试工具,用于创建更好的程序。它可以显示代码库中哪些部分未经测试。Gcov 与 *gcc* 位于同一软件包中。MariaDB 注重代码质量,并使用 Gcov 检查测试覆盖率。我们期待 Gcov 很快能作为 buildbot (MDBF-158) 的一部分使用。

如何使用 Gcov

我们来写一个演示示例,展示它是如何工作的。

— 源代码

$ cat -n test.c
     int f1()
     {
       return 0;
     }
     
     int f2(int a, int b)
     {
       return a+b;
     }
     int main()
     {
       f1();
    
     }

— 使用 *coverage* 标志编译源代码

$ gcc --coverage test.c -o test
# Result files:
test  test.c  test.gcno

— 运行可执行文件

$ ./test
# Result files
test  test.c  test.gcno test.gcda

请注意,会创建用于 Gcov 的额外文件。

— 运行 Gcov

$ gcov test.c 
File 'test.c'
Lines executed:66.67% of 6
Creating 'test.c.gcov
# Result files
test  test.c  test.gcno test.gcda test.c.gcov

— 检查结果(请注意,*main()* 和 *f1()* 函数只被调用了一次)

$ cat test.c.gcov 
        -:    0:Source:test.c
        -:    0:Graph:test.gcno
        -:    0:Data:test.gcda
        -:    0:Runs:1
        1:    1:       int f1()
        -:    2:       {
        1:    3:         return 0;
        -:    4:       }
        -:    5:     
    #####:    6:       int f2(int a, int b)
        -:    7:       {
    #####:    8:         return a+b;
        -:    9:      }
        1:   10:      int main()
        -:   11:      {
        1:   12:        f1();
        -:   13:    
        -:   14:    }
        -:   15:

如果您更改源代码,再次调用 *f1()* 函数(总共 2 次),然后重复编译和运行二进制文件的过程,结果将是

        2:    1:       int f1()
        -:    2:       {
        2:    3:         return 0;
        -:    4:       }
        1:   10:      int main()
        -:   11:      {
        1:   12:        f1();
        1:   13:        f1();

MariaDB 与 Gcov

MariaDB 支持 Gcov,可以使用 *mysql-test-run.pl* (*mtr*) 脚本运行它,主要由 MariaDB 开发者或 MariaDB 代码库贡献者使用。目前,Gcov 只适用于 in-source 构建。

以下是使用 Gcov 的步骤

  1. 编写补丁

Gcov 将应用于您的补丁并显示您补丁的性能,因此这一步很有益。为了本教程的目的,我将在 10.3 分支上向您展示一个简单案例,其中我们将更改来自 *get_check_constraints_record* 函数的检查约束记录名称。假设这是我们创建的补丁

--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -6601,7 +6601,7 @@ static int get_check_constraints_record(THD *thd, TABLE_LIST *tables,
       }
 #endif
       Virtual_column_info *check= tables->table->check_constraints[i];
-      table->field[0]->store(STRING_WITH_LEN("def"), system_charset_info);
+      table->field[0]->store(STRING_WITH_LEN("definition"), system_charset_info);

此更改应在测试中可见:*funcs_1.is_check_constraints.test*,其中 *funcs_1* 是套件名称,*is_check_constraints* 是测试名称。您可以在此处阅读有关 mysql-test-run 框架如何工作的更多信息。

  1. 使用特定参数编译和构建源代码

文档中,您可以找到如何从源代码编译。在编译期间,添加 cmake 标志 **ENABLE_GCOV**。命令如下所示

$ cmake . -DCMAKE_BUILD_TYPE=Debug -DENABLE_GCOV=ON

编译源代码后,使用以下命令验证设置:  

$ cmake . -LAH | grep ENABLE_GCOV 

您应该在末尾看到 *ENABLE_GCOV:BOOL=ON*。现在通过调用 make 来构建二进制文件。

  1. mysql-test 文件夹中,使用 gcov 标志在 mtr 中运行测试,并将结果保存到文件中,以查看补丁使用 record 标志的效果
$ ./mtr funcs_1.is_check_constraints --gcov --record
Logging: ./mtr  funcs_1.is_check_constraints --gcov --record
vardir: /home/anel/mariadb/10.2-gcov/mysql-test/var
Checking leftover processes...
Removing old var directory...
Creating var directory '/home/anel/mariadb/10.2-gcov/mysql-test/var'...
Checking supported features...
MariaDB Version 10.2.41-MariaDB-debug
 - SSL connections supported
 - binaries are debug compiled
 - binaries built with wsrep patch
Collecting tests...
Installing system database...

==============================================================================

TEST                                      RESULT   TIME (ms) or COMMENT
--------------------------------------------------------------------------

worker[1] Using MTR_BUILD_THREAD 300, with reserved ports 16000..16019
funcs_1.is_check_constraints 'innodb'    [ pass ]    327
--------------------------------------------------------------------------
The servers were restarted 0 times
Spent 0.327 of 5 seconds executing testcases

Completed: All 1 tests were successful.

Running dgcov
  1. 检查 Gcov 的结果。您应该看到您的更改被测试使用的权重。
$ cat var/last_changes.dgcov 
*********************
dgcov sql/sql_show.cc
*********************
@@ +6601,7 @@ static int get_check_constraints_record(THD *thd, TABLE_LIST *tables,
         : 6601:      }
         : 6602:#endif
         : 6603:      Virtual_column_info *check= tables->table->check_constraints[i];
       88: 6605:      table->field[0]->store(STRING_WITH_LEN("definition"), system_charset_info);
         : 6606:      table->field[3]->store(check->name.str, check->name.length,
         : 6607:                             system_charset_info);

正如您所见,我们修改的行被执行了 88 次,这是好的。如果它根本没有被执行,我们就无法知道它是否工作正常。您可以在此处阅读更多关于使用 dgcov 进行代码覆盖率的信息。

欢迎反馈

如果您在此功能预览、设计或未按预期工作的边缘案例中遇到任何问题,请在 MDEV 项目的 JIRA 中提交 bug/功能请求告知我们。欢迎您在 Zulip 上讨论此事。