summaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@kernel.org>2023-07-25 18:56:51 -0700
committerZorro Lang <zlang@kernel.org>2023-08-05 02:06:34 +0800
commitd39fb9a81d76305ab1b3c0c3a042e767a7c1bf89 (patch)
tree5759a315f68c824da387c276b95663d17aed61d0 /common
parent24cfe625794ea0c807d0739291f0a9ce7ddd5a2b (diff)
check: generate gcov code coverage reports at the end of each section
Support collecting kernel code coverage information as reported in debugfs. At the start of each section, we reset the gcov counters; during the section wrapup, we'll collect the kernel gcov data. If lcov is installed and the kernel source code is available, it will also generate a nice html report. If a CLI web browser is available, it will also format the html report into text for easy grepping. This requires the test runner to set REPORT_GCOV=1 explicitly and gcov to be enabled in the kernel. Cc: tytso@mit.edu Cc: kent.overstreet@linux.dev Signed-off-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Zorro Lang <zlang@redhat.com> Signed-off-by: Zorro Lang <zlang@kernel.org>
Diffstat (limited to 'common')
-rw-r--r--common/gcov87
1 files changed, 87 insertions, 0 deletions
diff --git a/common/gcov b/common/gcov
new file mode 100644
index 00000000..b7e3ed5a
--- /dev/null
+++ b/common/gcov
@@ -0,0 +1,87 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2023 Oracle. All Rights Reserved.
+#
+# Routines for capturing kernel code coverage reports
+
+GCOV_DIR=/sys/kernel/debug/gcov
+
+# Find the topmost directories of the .gcno directory hierarchy
+__gcov_find_topdirs() {
+ find "${GCOV_DIR}/" -name '*.gcno' -printf '%d|%h\n' | \
+ sort -g -k 1 | \
+ uniq | \
+ $AWK_PROG -F '|' 'BEGIN { x = -1 } { if (x < 0) x = $1; if ($1 == x) printf("%s\n", $2);}'
+}
+
+# Generate lcov html report from kernel gcov data if configured
+_gcov_generate_report() {
+ local output_dir="$1"
+ test -n "${output_dir}" || return
+
+ # Kernel support built in?
+ test -d "$GCOV_DIR" || return
+
+ readarray -t gcno_dirs < <(__gcov_find_topdirs)
+ test "${#gcno_dirs[@]}" -gt 0 || return
+
+ mkdir -p "${output_dir}/raw/"
+
+ # Collect raw coverage data from the kernel
+ readarray -t source_dirs < <(find "${GCOV_DIR}/" -mindepth 1 -maxdepth 1 -type d)
+ for dir in "${source_dirs[@]}"; do
+ cp -p -R -d -u "${dir}" "${output_dir}/raw/"
+ done
+
+ # If lcov is installed, use it to summarize the gcda data.
+ # If it is not installed, there's no point in going forward
+ command -v lcov > /dev/null || return
+ local lcov=(lcov --exclude 'include*' --capture)
+ lcov+=(--output-file "${output_dir}/gcov.report")
+ for d in "${gcno_dirs[@]}"; do
+ lcov+=(--directory "${d}")
+ done
+
+ # Generate a detailed HTML report from the summary
+ local gcov_start_time="$(date --date="${fstests_start_time:-now}")"
+ local genhtml=()
+ if command -v genhtml > /dev/null; then
+ genhtml+=(genhtml -o "${output_dir}/" "${output_dir}/gcov.report")
+ genhtml+=(--title "fstests on $(hostname -s) @ ${gcov_start_time}" --legend)
+ fi
+
+ # Try to convert the HTML report summary as text for easier grepping if
+ # there's an HTML renderer present
+ local totext=()
+ test "${#totext[@]}" -eq 0 && \
+ command -v lynx &>/dev/null && \
+ totext=(lynx -dump "${output_dir}/index.html" -width 120 -nonumbers -nolist)
+ test "${#totext[@]}" -eq 0 && \
+ command -v links &>/dev/null && \
+ totext=(links -dump "${output_dir}/index.html" -width 120)
+ test "${#totext[@]}" -eq 0 && \
+ command -v elinks &>/dev/null && \
+ totext=(elinks -dump "${output_dir}/index.html" --dump-width 120 --no-numbering --no-references)
+
+ # Analyze kernel data
+ "${lcov[@]}" > "${output_dir}/gcov.stdout" 2> "${output_dir}/gcov.stderr"
+ test "${#genhtml[@]}" -ne 0 && \
+ "${genhtml[@]}" >> "${output_dir}/gcov.stdout" 2>> "${output_dir}/gcov.stderr"
+ test "${#totext[@]}" -ne 0 && \
+ "${totext[@]}" > "${output_dir}/index.txt" 2>> "${output_dir}/gcov.stderr"
+}
+
+# Reset gcov usage data
+_gcov_reset() {
+ echo 1 > "${GCOV_DIR}/reset"
+}
+
+# If the caller wanted us to capture gcov reports but the kernel doesn't
+# support it, turn it off.
+_gcov_check_report_gcov() {
+ test -z "$REPORT_GCOV" && return 0
+ test -w "${GCOV_DIR}/reset" && return 0
+
+ unset REPORT_GCOV
+ return 1
+}