123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257 |
- Using gcov with the Linux kernel
- ================================
- 1. Introduction
- 2. Preparation
- 3. Customization
- 4. Files
- 5. Modules
- 6. Separated build and test machines
- 7. Troubleshooting
- Appendix A: sample script: gather_on_build.sh
- Appendix B: sample script: gather_on_test.sh
- 1. Introduction
- ===============
- gcov profiling kernel support enables the use of GCC's coverage testing
- tool gcov [1] with the Linux kernel. Coverage data of a running kernel
- is exported in gcov-compatible format via the "gcov" debugfs directory.
- To get coverage data for a specific file, change to the kernel build
- directory and use gcov with the -o option as follows (requires root):
- # cd /tmp/linux-out
- # gcov -o /sys/kernel/debug/gcov/tmp/linux-out/kernel spinlock.c
- This will create source code files annotated with execution counts
- in the current directory. In addition, graphical gcov front-ends such
- as lcov [2] can be used to automate the process of collecting data
- for the entire kernel and provide coverage overviews in HTML format.
- Possible uses:
- * debugging (has this line been reached at all?)
- * test improvement (how do I change my test to cover these lines?)
- * minimizing kernel configurations (do I need this option if the
- associated code is never run?)
- --
- [1] http://gcc.gnu.org/onlinedocs/gcc/Gcov.html
- [2] http://ltp.sourceforge.net/coverage/lcov.php
- 2. Preparation
- ==============
- Configure the kernel with:
- CONFIG_DEBUG_FS=y
- CONFIG_GCOV_KERNEL=y
- select the gcc's gcov format, default is autodetect based on gcc version:
- CONFIG_GCOV_FORMAT_AUTODETECT=y
- and to get coverage data for the entire kernel:
- CONFIG_GCOV_PROFILE_ALL=y
- Note that kernels compiled with profiling flags will be significantly
- larger and run slower. Also CONFIG_GCOV_PROFILE_ALL may not be supported
- on all architectures.
- Profiling data will only become accessible once debugfs has been
- mounted:
- mount -t debugfs none /sys/kernel/debug
- 3. Customization
- ================
- To enable profiling for specific files or directories, add a line
- similar to the following to the respective kernel Makefile:
- For a single file (e.g. main.o):
- GCOV_PROFILE_main.o := y
- For all files in one directory:
- GCOV_PROFILE := y
- To exclude files from being profiled even when CONFIG_GCOV_PROFILE_ALL
- is specified, use:
- GCOV_PROFILE_main.o := n
- and:
- GCOV_PROFILE := n
- Only files which are linked to the main kernel image or are compiled as
- kernel modules are supported by this mechanism.
- 4. Files
- ========
- The gcov kernel support creates the following files in debugfs:
- /sys/kernel/debug/gcov
- Parent directory for all gcov-related files.
- /sys/kernel/debug/gcov/reset
- Global reset file: resets all coverage data to zero when
- written to.
- /sys/kernel/debug/gcov/path/to/compile/dir/file.gcda
- The actual gcov data file as understood by the gcov
- tool. Resets file coverage data to zero when written to.
- /sys/kernel/debug/gcov/path/to/compile/dir/file.gcno
- Symbolic link to a static data file required by the gcov
- tool. This file is generated by gcc when compiling with
- option -ftest-coverage.
- 5. Modules
- ==========
- Kernel modules may contain cleanup code which is only run during
- module unload time. The gcov mechanism provides a means to collect
- coverage data for such code by keeping a copy of the data associated
- with the unloaded module. This data remains available through debugfs.
- Once the module is loaded again, the associated coverage counters are
- initialized with the data from its previous instantiation.
- This behavior can be deactivated by specifying the gcov_persist kernel
- parameter:
- gcov_persist=0
- At run-time, a user can also choose to discard data for an unloaded
- module by writing to its data file or the global reset file.
- 6. Separated build and test machines
- ====================================
- The gcov kernel profiling infrastructure is designed to work out-of-the
- box for setups where kernels are built and run on the same machine. In
- cases where the kernel runs on a separate machine, special preparations
- must be made, depending on where the gcov tool is used:
- a) gcov is run on the TEST machine
- The gcov tool version on the test machine must be compatible with the
- gcc version used for kernel build. Also the following files need to be
- copied from build to test machine:
- from the source tree:
- - all C source files + headers
- from the build tree:
- - all C source files + headers
- - all .gcda and .gcno files
- - all links to directories
- It is important to note that these files need to be placed into the
- exact same file system location on the test machine as on the build
- machine. If any of the path components is symbolic link, the actual
- directory needs to be used instead (due to make's CURDIR handling).
- b) gcov is run on the BUILD machine
- The following files need to be copied after each test case from test
- to build machine:
- from the gcov directory in sysfs:
- - all .gcda files
- - all links to .gcno files
- These files can be copied to any location on the build machine. gcov
- must then be called with the -o option pointing to that directory.
- Example directory setup on the build machine:
- /tmp/linux: kernel source tree
- /tmp/out: kernel build directory as specified by make O=
- /tmp/coverage: location of the files copied from the test machine
- [user@build] cd /tmp/out
- [user@build] gcov -o /tmp/coverage/tmp/out/init main.c
- 7. Troubleshooting
- ==================
- Problem: Compilation aborts during linker step.
- Cause: Profiling flags are specified for source files which are not
- linked to the main kernel or which are linked by a custom
- linker procedure.
- Solution: Exclude affected source files from profiling by specifying
- GCOV_PROFILE := n or GCOV_PROFILE_basename.o := n in the
- corresponding Makefile.
- Problem: Files copied from sysfs appear empty or incomplete.
- Cause: Due to the way seq_file works, some tools such as cp or tar
- may not correctly copy files from sysfs.
- Solution: Use 'cat' to read .gcda files and 'cp -d' to copy links.
- Alternatively use the mechanism shown in Appendix B.
- Appendix A: gather_on_build.sh
- ==============================
- Sample script to gather coverage meta files on the build machine
- (see 6a):
- #!/bin/bash
- KSRC=$1
- KOBJ=$2
- DEST=$3
- if [ -z "$KSRC" ] || [ -z "$KOBJ" ] || [ -z "$DEST" ]; then
- echo "Usage: $0 <ksrc directory> <kobj directory> <output.tar.gz>" >&2
- exit 1
- fi
- KSRC=$(cd $KSRC; printf "all:\n\t@echo \${CURDIR}\n" | make -f -)
- KOBJ=$(cd $KOBJ; printf "all:\n\t@echo \${CURDIR}\n" | make -f -)
- find $KSRC $KOBJ \( -name '*.gcno' -o -name '*.[ch]' -o -type l \) -a \
- -perm /u+r,g+r | tar cfz $DEST -P -T -
- if [ $? -eq 0 ] ; then
- echo "$DEST successfully created, copy to test system and unpack with:"
- echo " tar xfz $DEST -P"
- else
- echo "Could not create file $DEST"
- fi
- Appendix B: gather_on_test.sh
- =============================
- Sample script to gather coverage data files on the test machine
- (see 6b):
- #!/bin/bash -e
- DEST=$1
- GCDA=/sys/kernel/debug/gcov
- if [ -z "$DEST" ] ; then
- echo "Usage: $0 <output.tar.gz>" >&2
- exit 1
- fi
- TEMPDIR=$(mktemp -d)
- echo Collecting data..
- find $GCDA -type d -exec mkdir -p $TEMPDIR/\{\} \;
- find $GCDA -name '*.gcda' -exec sh -c 'cat < $0 > '$TEMPDIR'/$0' {} \;
- find $GCDA -name '*.gcno' -exec sh -c 'cp -d $0 '$TEMPDIR'/$0' {} \;
- tar czf $DEST -C $TEMPDIR sys
- rm -rf $TEMPDIR
- echo "$DEST successfully created, copy to build system and unpack with:"
- echo " tar xfz $DEST"
|