162306a36Sopenharmony_ciUsing gcov with the Linux kernel
262306a36Sopenharmony_ci================================
362306a36Sopenharmony_ci
462306a36Sopenharmony_cigcov profiling kernel support enables the use of GCC's coverage testing
562306a36Sopenharmony_citool gcov_ with the Linux kernel. Coverage data of a running kernel
662306a36Sopenharmony_ciis exported in gcov-compatible format via the "gcov" debugfs directory.
762306a36Sopenharmony_ciTo get coverage data for a specific file, change to the kernel build
862306a36Sopenharmony_cidirectory and use gcov with the ``-o`` option as follows (requires root)::
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci    # cd /tmp/linux-out
1162306a36Sopenharmony_ci    # gcov -o /sys/kernel/debug/gcov/tmp/linux-out/kernel spinlock.c
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ciThis will create source code files annotated with execution counts
1462306a36Sopenharmony_ciin the current directory. In addition, graphical gcov front-ends such
1562306a36Sopenharmony_cias lcov_ can be used to automate the process of collecting data
1662306a36Sopenharmony_cifor the entire kernel and provide coverage overviews in HTML format.
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ciPossible uses:
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci* debugging (has this line been reached at all?)
2162306a36Sopenharmony_ci* test improvement (how do I change my test to cover these lines?)
2262306a36Sopenharmony_ci* minimizing kernel configurations (do I need this option if the
2362306a36Sopenharmony_ci  associated code is never run?)
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci.. _gcov: https://gcc.gnu.org/onlinedocs/gcc/Gcov.html
2662306a36Sopenharmony_ci.. _lcov: http://ltp.sourceforge.net/coverage/lcov.php
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ciPreparation
3062306a36Sopenharmony_ci-----------
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ciConfigure the kernel with::
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci        CONFIG_DEBUG_FS=y
3562306a36Sopenharmony_ci        CONFIG_GCOV_KERNEL=y
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ciand to get coverage data for the entire kernel::
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci        CONFIG_GCOV_PROFILE_ALL=y
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ciNote that kernels compiled with profiling flags will be significantly
4262306a36Sopenharmony_cilarger and run slower. Also CONFIG_GCOV_PROFILE_ALL may not be supported
4362306a36Sopenharmony_cion all architectures.
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ciProfiling data will only become accessible once debugfs has been
4662306a36Sopenharmony_cimounted::
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci        mount -t debugfs none /sys/kernel/debug
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ciCustomization
5262306a36Sopenharmony_ci-------------
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ciTo enable profiling for specific files or directories, add a line
5562306a36Sopenharmony_cisimilar to the following to the respective kernel Makefile:
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci- For a single file (e.g. main.o)::
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	GCOV_PROFILE_main.o := y
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci- For all files in one directory::
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	GCOV_PROFILE := y
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ciTo exclude files from being profiled even when CONFIG_GCOV_PROFILE_ALL
6662306a36Sopenharmony_ciis specified, use::
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	GCOV_PROFILE_main.o := n
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ciand::
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	GCOV_PROFILE := n
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ciOnly files which are linked to the main kernel image or are compiled as
7562306a36Sopenharmony_cikernel modules are supported by this mechanism.
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ciFiles
7962306a36Sopenharmony_ci-----
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ciThe gcov kernel support creates the following files in debugfs:
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci``/sys/kernel/debug/gcov``
8462306a36Sopenharmony_ci	Parent directory for all gcov-related files.
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci``/sys/kernel/debug/gcov/reset``
8762306a36Sopenharmony_ci	Global reset file: resets all coverage data to zero when
8862306a36Sopenharmony_ci        written to.
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci``/sys/kernel/debug/gcov/path/to/compile/dir/file.gcda``
9162306a36Sopenharmony_ci	The actual gcov data file as understood by the gcov
9262306a36Sopenharmony_ci        tool. Resets file coverage data to zero when written to.
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci``/sys/kernel/debug/gcov/path/to/compile/dir/file.gcno``
9562306a36Sopenharmony_ci	Symbolic link to a static data file required by the gcov
9662306a36Sopenharmony_ci        tool. This file is generated by gcc when compiling with
9762306a36Sopenharmony_ci        option ``-ftest-coverage``.
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ciModules
10162306a36Sopenharmony_ci-------
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ciKernel modules may contain cleanup code which is only run during
10462306a36Sopenharmony_cimodule unload time. The gcov mechanism provides a means to collect
10562306a36Sopenharmony_cicoverage data for such code by keeping a copy of the data associated
10662306a36Sopenharmony_ciwith the unloaded module. This data remains available through debugfs.
10762306a36Sopenharmony_ciOnce the module is loaded again, the associated coverage counters are
10862306a36Sopenharmony_ciinitialized with the data from its previous instantiation.
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ciThis behavior can be deactivated by specifying the gcov_persist kernel
11162306a36Sopenharmony_ciparameter::
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci        gcov_persist=0
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ciAt run-time, a user can also choose to discard data for an unloaded
11662306a36Sopenharmony_cimodule by writing to its data file or the global reset file.
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ciSeparated build and test machines
12062306a36Sopenharmony_ci---------------------------------
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ciThe gcov kernel profiling infrastructure is designed to work out-of-the
12362306a36Sopenharmony_cibox for setups where kernels are built and run on the same machine. In
12462306a36Sopenharmony_cicases where the kernel runs on a separate machine, special preparations
12562306a36Sopenharmony_cimust be made, depending on where the gcov tool is used:
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci.. _gcov-test:
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_cia) gcov is run on the TEST machine
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci    The gcov tool version on the test machine must be compatible with the
13262306a36Sopenharmony_ci    gcc version used for kernel build. Also the following files need to be
13362306a36Sopenharmony_ci    copied from build to test machine:
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci    from the source tree:
13662306a36Sopenharmony_ci      - all C source files + headers
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci    from the build tree:
13962306a36Sopenharmony_ci      - all C source files + headers
14062306a36Sopenharmony_ci      - all .gcda and .gcno files
14162306a36Sopenharmony_ci      - all links to directories
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci    It is important to note that these files need to be placed into the
14462306a36Sopenharmony_ci    exact same file system location on the test machine as on the build
14562306a36Sopenharmony_ci    machine. If any of the path components is symbolic link, the actual
14662306a36Sopenharmony_ci    directory needs to be used instead (due to make's CURDIR handling).
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci.. _gcov-build:
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cib) gcov is run on the BUILD machine
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci    The following files need to be copied after each test case from test
15362306a36Sopenharmony_ci    to build machine:
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci    from the gcov directory in sysfs:
15662306a36Sopenharmony_ci      - all .gcda files
15762306a36Sopenharmony_ci      - all links to .gcno files
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci    These files can be copied to any location on the build machine. gcov
16062306a36Sopenharmony_ci    must then be called with the -o option pointing to that directory.
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci    Example directory setup on the build machine::
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci      /tmp/linux:    kernel source tree
16562306a36Sopenharmony_ci      /tmp/out:      kernel build directory as specified by make O=
16662306a36Sopenharmony_ci      /tmp/coverage: location of the files copied from the test machine
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci      [user@build] cd /tmp/out
16962306a36Sopenharmony_ci      [user@build] gcov -o /tmp/coverage/tmp/out/init main.c
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ciNote on compilers
17362306a36Sopenharmony_ci-----------------
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ciGCC and LLVM gcov tools are not necessarily compatible. Use gcov_ to work with
17662306a36Sopenharmony_ciGCC-generated .gcno and .gcda files, and use llvm-cov_ for Clang.
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci.. _gcov: https://gcc.gnu.org/onlinedocs/gcc/Gcov.html
17962306a36Sopenharmony_ci.. _llvm-cov: https://llvm.org/docs/CommandGuide/llvm-cov.html
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ciBuild differences between GCC and Clang gcov are handled by Kconfig. It
18262306a36Sopenharmony_ciautomatically selects the appropriate gcov format depending on the detected
18362306a36Sopenharmony_citoolchain.
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ciTroubleshooting
18762306a36Sopenharmony_ci---------------
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ciProblem
19062306a36Sopenharmony_ci    Compilation aborts during linker step.
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ciCause
19362306a36Sopenharmony_ci    Profiling flags are specified for source files which are not
19462306a36Sopenharmony_ci    linked to the main kernel or which are linked by a custom
19562306a36Sopenharmony_ci    linker procedure.
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ciSolution
19862306a36Sopenharmony_ci    Exclude affected source files from profiling by specifying
19962306a36Sopenharmony_ci    ``GCOV_PROFILE := n`` or ``GCOV_PROFILE_basename.o := n`` in the
20062306a36Sopenharmony_ci    corresponding Makefile.
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ciProblem
20362306a36Sopenharmony_ci    Files copied from sysfs appear empty or incomplete.
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ciCause
20662306a36Sopenharmony_ci    Due to the way seq_file works, some tools such as cp or tar
20762306a36Sopenharmony_ci    may not correctly copy files from sysfs.
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ciSolution
21062306a36Sopenharmony_ci    Use ``cat`` to read ``.gcda`` files and ``cp -d`` to copy links.
21162306a36Sopenharmony_ci    Alternatively use the mechanism shown in Appendix B.
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ciAppendix A: gather_on_build.sh
21562306a36Sopenharmony_ci------------------------------
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ciSample script to gather coverage meta files on the build machine
21862306a36Sopenharmony_ci(see :ref:`Separated build and test machines a. <gcov-test>`):
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci.. code-block:: sh
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci    #!/bin/bash
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci    KSRC=$1
22562306a36Sopenharmony_ci    KOBJ=$2
22662306a36Sopenharmony_ci    DEST=$3
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci    if [ -z "$KSRC" ] || [ -z "$KOBJ" ] || [ -z "$DEST" ]; then
22962306a36Sopenharmony_ci      echo "Usage: $0 <ksrc directory> <kobj directory> <output.tar.gz>" >&2
23062306a36Sopenharmony_ci      exit 1
23162306a36Sopenharmony_ci    fi
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci    KSRC=$(cd $KSRC; printf "all:\n\t@echo \${CURDIR}\n" | make -f -)
23462306a36Sopenharmony_ci    KOBJ=$(cd $KOBJ; printf "all:\n\t@echo \${CURDIR}\n" | make -f -)
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci    find $KSRC $KOBJ \( -name '*.gcno' -o -name '*.[ch]' -o -type l \) -a \
23762306a36Sopenharmony_ci                     -perm /u+r,g+r | tar cfz $DEST -P -T -
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci    if [ $? -eq 0 ] ; then
24062306a36Sopenharmony_ci      echo "$DEST successfully created, copy to test system and unpack with:"
24162306a36Sopenharmony_ci      echo "  tar xfz $DEST -P"
24262306a36Sopenharmony_ci    else
24362306a36Sopenharmony_ci      echo "Could not create file $DEST"
24462306a36Sopenharmony_ci    fi
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ciAppendix B: gather_on_test.sh
24862306a36Sopenharmony_ci-----------------------------
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ciSample script to gather coverage data files on the test machine
25162306a36Sopenharmony_ci(see :ref:`Separated build and test machines b. <gcov-build>`):
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci.. code-block:: sh
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci    #!/bin/bash -e
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci    DEST=$1
25862306a36Sopenharmony_ci    GCDA=/sys/kernel/debug/gcov
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci    if [ -z "$DEST" ] ; then
26162306a36Sopenharmony_ci      echo "Usage: $0 <output.tar.gz>" >&2
26262306a36Sopenharmony_ci      exit 1
26362306a36Sopenharmony_ci    fi
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci    TEMPDIR=$(mktemp -d)
26662306a36Sopenharmony_ci    echo Collecting data..
26762306a36Sopenharmony_ci    find $GCDA -type d -exec mkdir -p $TEMPDIR/\{\} \;
26862306a36Sopenharmony_ci    find $GCDA -name '*.gcda' -exec sh -c 'cat < $0 > '$TEMPDIR'/$0' {} \;
26962306a36Sopenharmony_ci    find $GCDA -name '*.gcno' -exec sh -c 'cp -d $0 '$TEMPDIR'/$0' {} \;
27062306a36Sopenharmony_ci    tar czf $DEST -C $TEMPDIR sys
27162306a36Sopenharmony_ci    rm -rf $TEMPDIR
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci    echo "$DEST successfully created, copy to build system and unpack with:"
27462306a36Sopenharmony_ci    echo "  tar xfz $DEST"
275