Gcov in MariaDB

Gcov is a coverage testing tool, used to create better programs. It can show which parts of the codebase are untested. Gcov is located in the same package as gcc. MariaDB takes care of code quality and checks test coverage with Gcov. We are looking forward to have Gcov used soon as a part of our buildbot (MDBF-158).

How to use Gcov

Let’s write a demo example to demonstrate how it works.

— Source code:

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

— Compile the source code using flag coverage

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

— Run the executable file

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

Note that additional files are created that will be used for the Gcov.

— Run 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

— Examine the results (note that the main() and f1() functions are called just once):

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

If you change the source code to call f1() once again (2 times in total) and repeat the procedure to compile and run the binary, the result will be:

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

MariaDB and Gcov

MariaDB supports Gcov which can be run with the mysql-test-run.pl (mtr) script and is mostly used by developers of MariaDB or contributors to the MariaDB codebase. Currently, Gcov works only for in-source builds.

Here are the steps in order to use Gcov:

  1. Write the patch

Gcov will be applied to your patch and show you the performance of your patch, so this step is beneficial. For the sake of this tutorial, I will show you a simple case on the 10.3 branch where we will change the name of the check constraints record from the get_check_constraints_record function. Let’s suppose this is the patch we have created:

--- 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);

This change should be visible in the test: funcs_1.is_check_constraints.test, where funcs_1 is the name of the suite and is_check_constraints is a name of the test. You can read more about how the mysql-test-run framework works here.

  1. Compile and build the source code with specific arguments

In the documentation you can find how to compile from source code. During compilation add the cmake flag ENABLE_GCOV. The command would look like this:

$ cmake . -DCMAKE_BUILD_TYPE=Debug -DENABLE_GCOV=ON

After compiling the source code, verify the settings with:  

$ cmake . -LAH | grep ENABLE_GCOV 

you should see at the end ENABLE_GCOV:BOOL=ON. Now build the binaries by invoking make.

  1. Run the test in mtr from the mysql-test folder with gcov flag and save the result to a file to see the effect of the patch with the record flag:
$ ./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. Inspect the results of Gcov. You should see the weights of your change that are used by test.
$ 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);

As you can see, the line we’ve modified was executed 88 times, which is good. If it weren’t executed at all, we couldn’t know if it works correctly. You can read more about code coverage with dgcov.

Feedback Welcome

If you come across any problems in this feature preview, with the design, or edge cases that don’t work as expected, please let us know with a JIRA bug/feature request in the MDEV project. You are welcome to chat about it on Zulip.