1*4882a593SmuzhiyunUsing gcov with the Linux kernel 2*4882a593Smuzhiyun================================ 3*4882a593Smuzhiyun 4*4882a593Smuzhiyungcov profiling kernel support enables the use of GCC's coverage testing 5*4882a593Smuzhiyuntool gcov_ with the Linux kernel. Coverage data of a running kernel 6*4882a593Smuzhiyunis exported in gcov-compatible format via the "gcov" debugfs directory. 7*4882a593SmuzhiyunTo get coverage data for a specific file, change to the kernel build 8*4882a593Smuzhiyundirectory and use gcov with the ``-o`` option as follows (requires root):: 9*4882a593Smuzhiyun 10*4882a593Smuzhiyun # cd /tmp/linux-out 11*4882a593Smuzhiyun # gcov -o /sys/kernel/debug/gcov/tmp/linux-out/kernel spinlock.c 12*4882a593Smuzhiyun 13*4882a593SmuzhiyunThis will create source code files annotated with execution counts 14*4882a593Smuzhiyunin the current directory. In addition, graphical gcov front-ends such 15*4882a593Smuzhiyunas lcov_ can be used to automate the process of collecting data 16*4882a593Smuzhiyunfor the entire kernel and provide coverage overviews in HTML format. 17*4882a593Smuzhiyun 18*4882a593SmuzhiyunPossible uses: 19*4882a593Smuzhiyun 20*4882a593Smuzhiyun* debugging (has this line been reached at all?) 21*4882a593Smuzhiyun* test improvement (how do I change my test to cover these lines?) 22*4882a593Smuzhiyun* minimizing kernel configurations (do I need this option if the 23*4882a593Smuzhiyun associated code is never run?) 24*4882a593Smuzhiyun 25*4882a593Smuzhiyun.. _gcov: https://gcc.gnu.org/onlinedocs/gcc/Gcov.html 26*4882a593Smuzhiyun.. _lcov: http://ltp.sourceforge.net/coverage/lcov.php 27*4882a593Smuzhiyun 28*4882a593Smuzhiyun 29*4882a593SmuzhiyunPreparation 30*4882a593Smuzhiyun----------- 31*4882a593Smuzhiyun 32*4882a593SmuzhiyunConfigure the kernel with:: 33*4882a593Smuzhiyun 34*4882a593Smuzhiyun CONFIG_DEBUG_FS=y 35*4882a593Smuzhiyun CONFIG_GCOV_KERNEL=y 36*4882a593Smuzhiyun 37*4882a593Smuzhiyunand to get coverage data for the entire kernel:: 38*4882a593Smuzhiyun 39*4882a593Smuzhiyun CONFIG_GCOV_PROFILE_ALL=y 40*4882a593Smuzhiyun 41*4882a593SmuzhiyunNote that kernels compiled with profiling flags will be significantly 42*4882a593Smuzhiyunlarger and run slower. Also CONFIG_GCOV_PROFILE_ALL may not be supported 43*4882a593Smuzhiyunon all architectures. 44*4882a593Smuzhiyun 45*4882a593SmuzhiyunProfiling data will only become accessible once debugfs has been 46*4882a593Smuzhiyunmounted:: 47*4882a593Smuzhiyun 48*4882a593Smuzhiyun mount -t debugfs none /sys/kernel/debug 49*4882a593Smuzhiyun 50*4882a593Smuzhiyun 51*4882a593SmuzhiyunCustomization 52*4882a593Smuzhiyun------------- 53*4882a593Smuzhiyun 54*4882a593SmuzhiyunTo enable profiling for specific files or directories, add a line 55*4882a593Smuzhiyunsimilar to the following to the respective kernel Makefile: 56*4882a593Smuzhiyun 57*4882a593Smuzhiyun- For a single file (e.g. main.o):: 58*4882a593Smuzhiyun 59*4882a593Smuzhiyun GCOV_PROFILE_main.o := y 60*4882a593Smuzhiyun 61*4882a593Smuzhiyun- For all files in one directory:: 62*4882a593Smuzhiyun 63*4882a593Smuzhiyun GCOV_PROFILE := y 64*4882a593Smuzhiyun 65*4882a593SmuzhiyunTo exclude files from being profiled even when CONFIG_GCOV_PROFILE_ALL 66*4882a593Smuzhiyunis specified, use:: 67*4882a593Smuzhiyun 68*4882a593Smuzhiyun GCOV_PROFILE_main.o := n 69*4882a593Smuzhiyun 70*4882a593Smuzhiyunand:: 71*4882a593Smuzhiyun 72*4882a593Smuzhiyun GCOV_PROFILE := n 73*4882a593Smuzhiyun 74*4882a593SmuzhiyunOnly files which are linked to the main kernel image or are compiled as 75*4882a593Smuzhiyunkernel modules are supported by this mechanism. 76*4882a593Smuzhiyun 77*4882a593Smuzhiyun 78*4882a593SmuzhiyunFiles 79*4882a593Smuzhiyun----- 80*4882a593Smuzhiyun 81*4882a593SmuzhiyunThe gcov kernel support creates the following files in debugfs: 82*4882a593Smuzhiyun 83*4882a593Smuzhiyun``/sys/kernel/debug/gcov`` 84*4882a593Smuzhiyun Parent directory for all gcov-related files. 85*4882a593Smuzhiyun 86*4882a593Smuzhiyun``/sys/kernel/debug/gcov/reset`` 87*4882a593Smuzhiyun Global reset file: resets all coverage data to zero when 88*4882a593Smuzhiyun written to. 89*4882a593Smuzhiyun 90*4882a593Smuzhiyun``/sys/kernel/debug/gcov/path/to/compile/dir/file.gcda`` 91*4882a593Smuzhiyun The actual gcov data file as understood by the gcov 92*4882a593Smuzhiyun tool. Resets file coverage data to zero when written to. 93*4882a593Smuzhiyun 94*4882a593Smuzhiyun``/sys/kernel/debug/gcov/path/to/compile/dir/file.gcno`` 95*4882a593Smuzhiyun Symbolic link to a static data file required by the gcov 96*4882a593Smuzhiyun tool. This file is generated by gcc when compiling with 97*4882a593Smuzhiyun option ``-ftest-coverage``. 98*4882a593Smuzhiyun 99*4882a593Smuzhiyun 100*4882a593SmuzhiyunModules 101*4882a593Smuzhiyun------- 102*4882a593Smuzhiyun 103*4882a593SmuzhiyunKernel modules may contain cleanup code which is only run during 104*4882a593Smuzhiyunmodule unload time. The gcov mechanism provides a means to collect 105*4882a593Smuzhiyuncoverage data for such code by keeping a copy of the data associated 106*4882a593Smuzhiyunwith the unloaded module. This data remains available through debugfs. 107*4882a593SmuzhiyunOnce the module is loaded again, the associated coverage counters are 108*4882a593Smuzhiyuninitialized with the data from its previous instantiation. 109*4882a593Smuzhiyun 110*4882a593SmuzhiyunThis behavior can be deactivated by specifying the gcov_persist kernel 111*4882a593Smuzhiyunparameter:: 112*4882a593Smuzhiyun 113*4882a593Smuzhiyun gcov_persist=0 114*4882a593Smuzhiyun 115*4882a593SmuzhiyunAt run-time, a user can also choose to discard data for an unloaded 116*4882a593Smuzhiyunmodule by writing to its data file or the global reset file. 117*4882a593Smuzhiyun 118*4882a593Smuzhiyun 119*4882a593SmuzhiyunSeparated build and test machines 120*4882a593Smuzhiyun--------------------------------- 121*4882a593Smuzhiyun 122*4882a593SmuzhiyunThe gcov kernel profiling infrastructure is designed to work out-of-the 123*4882a593Smuzhiyunbox for setups where kernels are built and run on the same machine. In 124*4882a593Smuzhiyuncases where the kernel runs on a separate machine, special preparations 125*4882a593Smuzhiyunmust be made, depending on where the gcov tool is used: 126*4882a593Smuzhiyun 127*4882a593Smuzhiyuna) gcov is run on the TEST machine 128*4882a593Smuzhiyun 129*4882a593Smuzhiyun The gcov tool version on the test machine must be compatible with the 130*4882a593Smuzhiyun gcc version used for kernel build. Also the following files need to be 131*4882a593Smuzhiyun copied from build to test machine: 132*4882a593Smuzhiyun 133*4882a593Smuzhiyun from the source tree: 134*4882a593Smuzhiyun - all C source files + headers 135*4882a593Smuzhiyun 136*4882a593Smuzhiyun from the build tree: 137*4882a593Smuzhiyun - all C source files + headers 138*4882a593Smuzhiyun - all .gcda and .gcno files 139*4882a593Smuzhiyun - all links to directories 140*4882a593Smuzhiyun 141*4882a593Smuzhiyun It is important to note that these files need to be placed into the 142*4882a593Smuzhiyun exact same file system location on the test machine as on the build 143*4882a593Smuzhiyun machine. If any of the path components is symbolic link, the actual 144*4882a593Smuzhiyun directory needs to be used instead (due to make's CURDIR handling). 145*4882a593Smuzhiyun 146*4882a593Smuzhiyunb) gcov is run on the BUILD machine 147*4882a593Smuzhiyun 148*4882a593Smuzhiyun The following files need to be copied after each test case from test 149*4882a593Smuzhiyun to build machine: 150*4882a593Smuzhiyun 151*4882a593Smuzhiyun from the gcov directory in sysfs: 152*4882a593Smuzhiyun - all .gcda files 153*4882a593Smuzhiyun - all links to .gcno files 154*4882a593Smuzhiyun 155*4882a593Smuzhiyun These files can be copied to any location on the build machine. gcov 156*4882a593Smuzhiyun must then be called with the -o option pointing to that directory. 157*4882a593Smuzhiyun 158*4882a593Smuzhiyun Example directory setup on the build machine:: 159*4882a593Smuzhiyun 160*4882a593Smuzhiyun /tmp/linux: kernel source tree 161*4882a593Smuzhiyun /tmp/out: kernel build directory as specified by make O= 162*4882a593Smuzhiyun /tmp/coverage: location of the files copied from the test machine 163*4882a593Smuzhiyun 164*4882a593Smuzhiyun [user@build] cd /tmp/out 165*4882a593Smuzhiyun [user@build] gcov -o /tmp/coverage/tmp/out/init main.c 166*4882a593Smuzhiyun 167*4882a593Smuzhiyun 168*4882a593SmuzhiyunNote on compilers 169*4882a593Smuzhiyun----------------- 170*4882a593Smuzhiyun 171*4882a593SmuzhiyunGCC and LLVM gcov tools are not necessarily compatible. Use gcov_ to work with 172*4882a593SmuzhiyunGCC-generated .gcno and .gcda files, and use llvm-cov_ for Clang. 173*4882a593Smuzhiyun 174*4882a593Smuzhiyun.. _gcov: https://gcc.gnu.org/onlinedocs/gcc/Gcov.html 175*4882a593Smuzhiyun.. _llvm-cov: https://llvm.org/docs/CommandGuide/llvm-cov.html 176*4882a593Smuzhiyun 177*4882a593SmuzhiyunBuild differences between GCC and Clang gcov are handled by Kconfig. It 178*4882a593Smuzhiyunautomatically selects the appropriate gcov format depending on the detected 179*4882a593Smuzhiyuntoolchain. 180*4882a593Smuzhiyun 181*4882a593Smuzhiyun 182*4882a593SmuzhiyunTroubleshooting 183*4882a593Smuzhiyun--------------- 184*4882a593Smuzhiyun 185*4882a593SmuzhiyunProblem 186*4882a593Smuzhiyun Compilation aborts during linker step. 187*4882a593Smuzhiyun 188*4882a593SmuzhiyunCause 189*4882a593Smuzhiyun Profiling flags are specified for source files which are not 190*4882a593Smuzhiyun linked to the main kernel or which are linked by a custom 191*4882a593Smuzhiyun linker procedure. 192*4882a593Smuzhiyun 193*4882a593SmuzhiyunSolution 194*4882a593Smuzhiyun Exclude affected source files from profiling by specifying 195*4882a593Smuzhiyun ``GCOV_PROFILE := n`` or ``GCOV_PROFILE_basename.o := n`` in the 196*4882a593Smuzhiyun corresponding Makefile. 197*4882a593Smuzhiyun 198*4882a593SmuzhiyunProblem 199*4882a593Smuzhiyun Files copied from sysfs appear empty or incomplete. 200*4882a593Smuzhiyun 201*4882a593SmuzhiyunCause 202*4882a593Smuzhiyun Due to the way seq_file works, some tools such as cp or tar 203*4882a593Smuzhiyun may not correctly copy files from sysfs. 204*4882a593Smuzhiyun 205*4882a593SmuzhiyunSolution 206*4882a593Smuzhiyun Use ``cat`` to read ``.gcda`` files and ``cp -d`` to copy links. 207*4882a593Smuzhiyun Alternatively use the mechanism shown in Appendix B. 208*4882a593Smuzhiyun 209*4882a593Smuzhiyun 210*4882a593SmuzhiyunAppendix A: gather_on_build.sh 211*4882a593Smuzhiyun------------------------------ 212*4882a593Smuzhiyun 213*4882a593SmuzhiyunSample script to gather coverage meta files on the build machine 214*4882a593Smuzhiyun(see 6a): 215*4882a593Smuzhiyun 216*4882a593Smuzhiyun.. code-block:: sh 217*4882a593Smuzhiyun 218*4882a593Smuzhiyun #!/bin/bash 219*4882a593Smuzhiyun 220*4882a593Smuzhiyun KSRC=$1 221*4882a593Smuzhiyun KOBJ=$2 222*4882a593Smuzhiyun DEST=$3 223*4882a593Smuzhiyun 224*4882a593Smuzhiyun if [ -z "$KSRC" ] || [ -z "$KOBJ" ] || [ -z "$DEST" ]; then 225*4882a593Smuzhiyun echo "Usage: $0 <ksrc directory> <kobj directory> <output.tar.gz>" >&2 226*4882a593Smuzhiyun exit 1 227*4882a593Smuzhiyun fi 228*4882a593Smuzhiyun 229*4882a593Smuzhiyun KSRC=$(cd $KSRC; printf "all:\n\t@echo \${CURDIR}\n" | make -f -) 230*4882a593Smuzhiyun KOBJ=$(cd $KOBJ; printf "all:\n\t@echo \${CURDIR}\n" | make -f -) 231*4882a593Smuzhiyun 232*4882a593Smuzhiyun find $KSRC $KOBJ \( -name '*.gcno' -o -name '*.[ch]' -o -type l \) -a \ 233*4882a593Smuzhiyun -perm /u+r,g+r | tar cfz $DEST -P -T - 234*4882a593Smuzhiyun 235*4882a593Smuzhiyun if [ $? -eq 0 ] ; then 236*4882a593Smuzhiyun echo "$DEST successfully created, copy to test system and unpack with:" 237*4882a593Smuzhiyun echo " tar xfz $DEST -P" 238*4882a593Smuzhiyun else 239*4882a593Smuzhiyun echo "Could not create file $DEST" 240*4882a593Smuzhiyun fi 241*4882a593Smuzhiyun 242*4882a593Smuzhiyun 243*4882a593SmuzhiyunAppendix B: gather_on_test.sh 244*4882a593Smuzhiyun----------------------------- 245*4882a593Smuzhiyun 246*4882a593SmuzhiyunSample script to gather coverage data files on the test machine 247*4882a593Smuzhiyun(see 6b): 248*4882a593Smuzhiyun 249*4882a593Smuzhiyun.. code-block:: sh 250*4882a593Smuzhiyun 251*4882a593Smuzhiyun #!/bin/bash -e 252*4882a593Smuzhiyun 253*4882a593Smuzhiyun DEST=$1 254*4882a593Smuzhiyun GCDA=/sys/kernel/debug/gcov 255*4882a593Smuzhiyun 256*4882a593Smuzhiyun if [ -z "$DEST" ] ; then 257*4882a593Smuzhiyun echo "Usage: $0 <output.tar.gz>" >&2 258*4882a593Smuzhiyun exit 1 259*4882a593Smuzhiyun fi 260*4882a593Smuzhiyun 261*4882a593Smuzhiyun TEMPDIR=$(mktemp -d) 262*4882a593Smuzhiyun echo Collecting data.. 263*4882a593Smuzhiyun find $GCDA -type d -exec mkdir -p $TEMPDIR/\{\} \; 264*4882a593Smuzhiyun find $GCDA -name '*.gcda' -exec sh -c 'cat < $0 > '$TEMPDIR'/$0' {} \; 265*4882a593Smuzhiyun find $GCDA -name '*.gcno' -exec sh -c 'cp -d $0 '$TEMPDIR'/$0' {} \; 266*4882a593Smuzhiyun tar czf $DEST -C $TEMPDIR sys 267*4882a593Smuzhiyun rm -rf $TEMPDIR 268*4882a593Smuzhiyun 269*4882a593Smuzhiyun echo "$DEST successfully created, copy to build system and unpack with:" 270*4882a593Smuzhiyun echo " tar xfz $DEST" 271