18c2ecf20Sopenharmony_ciUsing gcov with the Linux kernel
28c2ecf20Sopenharmony_ci================================
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_cigcov profiling kernel support enables the use of GCC's coverage testing
58c2ecf20Sopenharmony_citool gcov_ with the Linux kernel. Coverage data of a running kernel
68c2ecf20Sopenharmony_ciis exported in gcov-compatible format via the "gcov" debugfs directory.
78c2ecf20Sopenharmony_ciTo get coverage data for a specific file, change to the kernel build
88c2ecf20Sopenharmony_cidirectory and use gcov with the ``-o`` option as follows (requires root)::
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci    # cd /tmp/linux-out
118c2ecf20Sopenharmony_ci    # gcov -o /sys/kernel/debug/gcov/tmp/linux-out/kernel spinlock.c
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ciThis will create source code files annotated with execution counts
148c2ecf20Sopenharmony_ciin the current directory. In addition, graphical gcov front-ends such
158c2ecf20Sopenharmony_cias lcov_ can be used to automate the process of collecting data
168c2ecf20Sopenharmony_cifor the entire kernel and provide coverage overviews in HTML format.
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ciPossible uses:
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci* debugging (has this line been reached at all?)
218c2ecf20Sopenharmony_ci* test improvement (how do I change my test to cover these lines?)
228c2ecf20Sopenharmony_ci* minimizing kernel configurations (do I need this option if the
238c2ecf20Sopenharmony_ci  associated code is never run?)
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci.. _gcov: https://gcc.gnu.org/onlinedocs/gcc/Gcov.html
268c2ecf20Sopenharmony_ci.. _lcov: http://ltp.sourceforge.net/coverage/lcov.php
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ciPreparation
308c2ecf20Sopenharmony_ci-----------
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ciConfigure the kernel with::
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci        CONFIG_DEBUG_FS=y
358c2ecf20Sopenharmony_ci        CONFIG_GCOV_KERNEL=y
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ciand to get coverage data for the entire kernel::
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci        CONFIG_GCOV_PROFILE_ALL=y
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ciNote that kernels compiled with profiling flags will be significantly
428c2ecf20Sopenharmony_cilarger and run slower. Also CONFIG_GCOV_PROFILE_ALL may not be supported
438c2ecf20Sopenharmony_cion all architectures.
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ciProfiling data will only become accessible once debugfs has been
468c2ecf20Sopenharmony_cimounted::
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci        mount -t debugfs none /sys/kernel/debug
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ciCustomization
528c2ecf20Sopenharmony_ci-------------
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ciTo enable profiling for specific files or directories, add a line
558c2ecf20Sopenharmony_cisimilar to the following to the respective kernel Makefile:
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci- For a single file (e.g. main.o)::
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	GCOV_PROFILE_main.o := y
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci- For all files in one directory::
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	GCOV_PROFILE := y
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ciTo exclude files from being profiled even when CONFIG_GCOV_PROFILE_ALL
668c2ecf20Sopenharmony_ciis specified, use::
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	GCOV_PROFILE_main.o := n
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ciand::
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	GCOV_PROFILE := n
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ciOnly files which are linked to the main kernel image or are compiled as
758c2ecf20Sopenharmony_cikernel modules are supported by this mechanism.
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ciFiles
798c2ecf20Sopenharmony_ci-----
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ciThe gcov kernel support creates the following files in debugfs:
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci``/sys/kernel/debug/gcov``
848c2ecf20Sopenharmony_ci	Parent directory for all gcov-related files.
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci``/sys/kernel/debug/gcov/reset``
878c2ecf20Sopenharmony_ci	Global reset file: resets all coverage data to zero when
888c2ecf20Sopenharmony_ci        written to.
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci``/sys/kernel/debug/gcov/path/to/compile/dir/file.gcda``
918c2ecf20Sopenharmony_ci	The actual gcov data file as understood by the gcov
928c2ecf20Sopenharmony_ci        tool. Resets file coverage data to zero when written to.
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci``/sys/kernel/debug/gcov/path/to/compile/dir/file.gcno``
958c2ecf20Sopenharmony_ci	Symbolic link to a static data file required by the gcov
968c2ecf20Sopenharmony_ci        tool. This file is generated by gcc when compiling with
978c2ecf20Sopenharmony_ci        option ``-ftest-coverage``.
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ciModules
1018c2ecf20Sopenharmony_ci-------
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ciKernel modules may contain cleanup code which is only run during
1048c2ecf20Sopenharmony_cimodule unload time. The gcov mechanism provides a means to collect
1058c2ecf20Sopenharmony_cicoverage data for such code by keeping a copy of the data associated
1068c2ecf20Sopenharmony_ciwith the unloaded module. This data remains available through debugfs.
1078c2ecf20Sopenharmony_ciOnce the module is loaded again, the associated coverage counters are
1088c2ecf20Sopenharmony_ciinitialized with the data from its previous instantiation.
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ciThis behavior can be deactivated by specifying the gcov_persist kernel
1118c2ecf20Sopenharmony_ciparameter::
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci        gcov_persist=0
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ciAt run-time, a user can also choose to discard data for an unloaded
1168c2ecf20Sopenharmony_cimodule by writing to its data file or the global reset file.
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ciSeparated build and test machines
1208c2ecf20Sopenharmony_ci---------------------------------
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ciThe gcov kernel profiling infrastructure is designed to work out-of-the
1238c2ecf20Sopenharmony_cibox for setups where kernels are built and run on the same machine. In
1248c2ecf20Sopenharmony_cicases where the kernel runs on a separate machine, special preparations
1258c2ecf20Sopenharmony_cimust be made, depending on where the gcov tool is used:
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_cia) gcov is run on the TEST machine
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci    The gcov tool version on the test machine must be compatible with the
1308c2ecf20Sopenharmony_ci    gcc version used for kernel build. Also the following files need to be
1318c2ecf20Sopenharmony_ci    copied from build to test machine:
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci    from the source tree:
1348c2ecf20Sopenharmony_ci      - all C source files + headers
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci    from the build tree:
1378c2ecf20Sopenharmony_ci      - all C source files + headers
1388c2ecf20Sopenharmony_ci      - all .gcda and .gcno files
1398c2ecf20Sopenharmony_ci      - all links to directories
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci    It is important to note that these files need to be placed into the
1428c2ecf20Sopenharmony_ci    exact same file system location on the test machine as on the build
1438c2ecf20Sopenharmony_ci    machine. If any of the path components is symbolic link, the actual
1448c2ecf20Sopenharmony_ci    directory needs to be used instead (due to make's CURDIR handling).
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_cib) gcov is run on the BUILD machine
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci    The following files need to be copied after each test case from test
1498c2ecf20Sopenharmony_ci    to build machine:
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci    from the gcov directory in sysfs:
1528c2ecf20Sopenharmony_ci      - all .gcda files
1538c2ecf20Sopenharmony_ci      - all links to .gcno files
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci    These files can be copied to any location on the build machine. gcov
1568c2ecf20Sopenharmony_ci    must then be called with the -o option pointing to that directory.
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci    Example directory setup on the build machine::
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci      /tmp/linux:    kernel source tree
1618c2ecf20Sopenharmony_ci      /tmp/out:      kernel build directory as specified by make O=
1628c2ecf20Sopenharmony_ci      /tmp/coverage: location of the files copied from the test machine
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci      [user@build] cd /tmp/out
1658c2ecf20Sopenharmony_ci      [user@build] gcov -o /tmp/coverage/tmp/out/init main.c
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ciNote on compilers
1698c2ecf20Sopenharmony_ci-----------------
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ciGCC and LLVM gcov tools are not necessarily compatible. Use gcov_ to work with
1728c2ecf20Sopenharmony_ciGCC-generated .gcno and .gcda files, and use llvm-cov_ for Clang.
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci.. _gcov: https://gcc.gnu.org/onlinedocs/gcc/Gcov.html
1758c2ecf20Sopenharmony_ci.. _llvm-cov: https://llvm.org/docs/CommandGuide/llvm-cov.html
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ciBuild differences between GCC and Clang gcov are handled by Kconfig. It
1788c2ecf20Sopenharmony_ciautomatically selects the appropriate gcov format depending on the detected
1798c2ecf20Sopenharmony_citoolchain.
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ciTroubleshooting
1838c2ecf20Sopenharmony_ci---------------
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ciProblem
1868c2ecf20Sopenharmony_ci    Compilation aborts during linker step.
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ciCause
1898c2ecf20Sopenharmony_ci    Profiling flags are specified for source files which are not
1908c2ecf20Sopenharmony_ci    linked to the main kernel or which are linked by a custom
1918c2ecf20Sopenharmony_ci    linker procedure.
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ciSolution
1948c2ecf20Sopenharmony_ci    Exclude affected source files from profiling by specifying
1958c2ecf20Sopenharmony_ci    ``GCOV_PROFILE := n`` or ``GCOV_PROFILE_basename.o := n`` in the
1968c2ecf20Sopenharmony_ci    corresponding Makefile.
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ciProblem
1998c2ecf20Sopenharmony_ci    Files copied from sysfs appear empty or incomplete.
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ciCause
2028c2ecf20Sopenharmony_ci    Due to the way seq_file works, some tools such as cp or tar
2038c2ecf20Sopenharmony_ci    may not correctly copy files from sysfs.
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ciSolution
2068c2ecf20Sopenharmony_ci    Use ``cat`` to read ``.gcda`` files and ``cp -d`` to copy links.
2078c2ecf20Sopenharmony_ci    Alternatively use the mechanism shown in Appendix B.
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ciAppendix A: gather_on_build.sh
2118c2ecf20Sopenharmony_ci------------------------------
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ciSample script to gather coverage meta files on the build machine
2148c2ecf20Sopenharmony_ci(see 6a):
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci.. code-block:: sh
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci    #!/bin/bash
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci    KSRC=$1
2218c2ecf20Sopenharmony_ci    KOBJ=$2
2228c2ecf20Sopenharmony_ci    DEST=$3
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci    if [ -z "$KSRC" ] || [ -z "$KOBJ" ] || [ -z "$DEST" ]; then
2258c2ecf20Sopenharmony_ci      echo "Usage: $0 <ksrc directory> <kobj directory> <output.tar.gz>" >&2
2268c2ecf20Sopenharmony_ci      exit 1
2278c2ecf20Sopenharmony_ci    fi
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci    KSRC=$(cd $KSRC; printf "all:\n\t@echo \${CURDIR}\n" | make -f -)
2308c2ecf20Sopenharmony_ci    KOBJ=$(cd $KOBJ; printf "all:\n\t@echo \${CURDIR}\n" | make -f -)
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci    find $KSRC $KOBJ \( -name '*.gcno' -o -name '*.[ch]' -o -type l \) -a \
2338c2ecf20Sopenharmony_ci                     -perm /u+r,g+r | tar cfz $DEST -P -T -
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci    if [ $? -eq 0 ] ; then
2368c2ecf20Sopenharmony_ci      echo "$DEST successfully created, copy to test system and unpack with:"
2378c2ecf20Sopenharmony_ci      echo "  tar xfz $DEST -P"
2388c2ecf20Sopenharmony_ci    else
2398c2ecf20Sopenharmony_ci      echo "Could not create file $DEST"
2408c2ecf20Sopenharmony_ci    fi
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ciAppendix B: gather_on_test.sh
2448c2ecf20Sopenharmony_ci-----------------------------
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ciSample script to gather coverage data files on the test machine
2478c2ecf20Sopenharmony_ci(see 6b):
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci.. code-block:: sh
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci    #!/bin/bash -e
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci    DEST=$1
2548c2ecf20Sopenharmony_ci    GCDA=/sys/kernel/debug/gcov
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci    if [ -z "$DEST" ] ; then
2578c2ecf20Sopenharmony_ci      echo "Usage: $0 <output.tar.gz>" >&2
2588c2ecf20Sopenharmony_ci      exit 1
2598c2ecf20Sopenharmony_ci    fi
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci    TEMPDIR=$(mktemp -d)
2628c2ecf20Sopenharmony_ci    echo Collecting data..
2638c2ecf20Sopenharmony_ci    find $GCDA -type d -exec mkdir -p $TEMPDIR/\{\} \;
2648c2ecf20Sopenharmony_ci    find $GCDA -name '*.gcda' -exec sh -c 'cat < $0 > '$TEMPDIR'/$0' {} \;
2658c2ecf20Sopenharmony_ci    find $GCDA -name '*.gcno' -exec sh -c 'cp -d $0 '$TEMPDIR'/$0' {} \;
2668c2ecf20Sopenharmony_ci    tar czf $DEST -C $TEMPDIR sys
2678c2ecf20Sopenharmony_ci    rm -rf $TEMPDIR
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci    echo "$DEST successfully created, copy to build system and unpack with:"
2708c2ecf20Sopenharmony_ci    echo "  tar xfz $DEST"
271