diff --git a/Dockerfile b/Dockerfile index 0ceed4a..82d6f63 100644 --- a/Dockerfile +++ b/Dockerfile @@ -23,7 +23,7 @@ RUN apt-get update && \ iptables ebtables nftables vim psmisc bash-completion less jq \ gettext-base libevent-dev libtraceevent-dev libnewt0.52 libslang2 libutempter0 python3-newt tmux \ libdwarf-dev libbfd-dev libnuma-dev libzstd-dev libunwind-dev libdw-dev libslang2-dev python3-dev python3-setuptools binutils-dev libiberty-dev libbabeltrace-dev systemtap-sdt-dev libperl-dev python3-docutils \ - libtap-formatter-junit-perl \ + libtap-formatter-junit-perl lcov libjson-xs-perl \ zstd \ wget xz-utils lftp cpio u-boot-tools \ cscope \ diff --git a/entrypoint.sh b/entrypoint.sh index 6ea55b7..f52bd7e 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -55,6 +55,7 @@ set_trace_on : "${INPUT_SELFTESTS_MPTCP_LIB_OVERRIDE_FLAKY:=0}" : "${INPUT_SELFTESTS_MPTCP_LIB_COLOR_FORCE:=1}" : "${INPUT_CPUS:=""}" +: "${INPUT_GCOV:=""}" : "${INPUT_CI_RESULTS_DIR:=""}" : "${INPUT_CI_PRINT_EXIT_CODE:=1}" : "${INPUT_CI_TIMEOUT_SEC:=7200}" @@ -150,6 +151,8 @@ OUTPUT_VIRTME= TESTS_SUMMARY= CONCLUSION= KMEMLEAK= +LCOV_FILE= +LCOV_HTML= EXIT_STATUS=0 EXIT_REASONS=() @@ -222,6 +225,7 @@ setup_env() { local mode net=() mkdir -p "${RESULTS_DIR}" : "${INPUT_CPUS:=$(nproc)}" # use all available resources + : "${INPUT_GCOV:=1}" EXIT_TITLE="${EXIT_TITLE}: ${mode}" # only one mode @@ -241,6 +245,7 @@ setup_env() { local mode net=() mkdir -p "${RESULTS_DIR}" : "${INPUT_CPUS:=2}" # limit to 2 cores for now + : "${INPUT_GCOV:=0}" # add net support, can be useful, but delay the start of the tests (~1 sec?) net=("--net") @@ -256,6 +261,8 @@ setup_env() { local mode net=() TESTS_SUMMARY="${RESULTS_DIR}/summary.txt" CONCLUSION="${RESULTS_DIR}/conclusion.txt" KMEMLEAK="${RESULTS_DIR}/kmemleak.txt" + LCOV_FILE="${RESULTS_DIR}/kernel.lcov" + LCOV_HTML="${RESULTS_DIR}/lcov" KVERSION=$(make -C "${KERNEL_SRC}" -s kernelversion) ## 5.17.0 or 5.17.0-rc8 KVER_MAJ=${KVERSION%%.*} ## 5 @@ -429,6 +436,11 @@ gen_kconfig() { local mode kconfig=() vck rc=0 kconfig+=(-e DEBUG_INFO_REDUCED -e DEBUG_INFO_SPLIT) fi + # GCov for the CI + if [ "${INPUT_GCOV}" = 1 ]; then + kconfig+=(-e GCOV_KERNEL -e GCOV_PROFILE_MPTCP) + fi + # Debug tools for developers kconfig+=( -e DYNAMIC_DEBUG --set-val CONSOLE_LOGLEVEL_DEFAULT 8 @@ -491,7 +503,11 @@ gen_kconfig() { local mode kconfig=() vck rc=0 build_kernel() { local rc=0 log_section_start "Build kernel" - _make_o || rc=${?} + if [ "${INPUT_GCOV}" = 1 ]; then + KCFLAGS="-fprofile-update=atomic" _make_o || rc=${?} + else + _make_o || rc=${?} + fi # virtme will mount a tmpfs there + symlink to .virtme_mods mkdir -p /lib/modules @@ -1027,12 +1043,20 @@ has_call_trace() { } kmemleak_scan() { - if [ "${mode}" = "debug" ]; then + if [ -e /sys/kernel/debug/kmemleak ]; then echo scan > /sys/kernel/debug/kmemleak cat /sys/kernel/debug/kmemleak > "${KMEMLEAK}" fi } +gcov_extract() { + if [ -d /sys/kernel/debug/gcov ]; then + lcov --capture --keep-going --rc geninfo_unexecuted_blocks=1 \ + --function-coverage --branch-coverage \ + -b "${VIRTME_BUILD_DIR}" -j "${INPUT_CPUS}" -o "${LCOV_FILE}" + fi +} + # \$1: max iterations (<1 means no limit) ; args: what needs to be executed run_loop_n() { local i tdir rc=0 n=\${1} @@ -1106,6 +1130,7 @@ fi cd "${KERNEL_SRC}" kmemleak_scan +gcov_extract # To run commands before executing the tests if [ -f "${VIRTME_EXEC_POST}" ]; then @@ -1278,6 +1303,10 @@ _print_line() { echo "==========================================" } +_get_ref() { + echo "${GITHUB_REF_NAME:-$(git describe --tags 2>/dev/null || git rev-parse --short HEAD 2>/dev/null || echo "Unknown")}" +} + decode_stacktrace() { ./scripts/decode_stacktrace.sh "${VIRTME_BUILD_DIR}/vmlinux" "${KERNEL_SRC}" "${VIRTME_BUILD_DIR}/.virtme_mods" } @@ -1334,6 +1363,13 @@ _print_kmemleak() { echo "KMemLeak detected" } +_lcov_to_html() { + mkdir -p "${LCOV_HTML}" + genhtml -j "$(nproc)" -t "$(_get_ref)" --dark-mode \ + --include '/net/mptcp/' \ + -o "${LCOV_HTML}" "${LCOV_FILE}" &> "${LCOV_HTML}/gen.log" +} + # $1: mode, rest: args for kconfig _print_summary_header() { local mode="${1}" @@ -1341,7 +1377,7 @@ _print_summary_header() { echo "== Summary ==" echo - echo "Ref: ${GITHUB_REF_NAME:-${CIRRUS_TAG:-$(git describe --tags 2>/dev/null || git rev-parse --short HEAD 2>/dev/null || echo "Unknown")}}${GITHUB_SHA:+ (${GITHUB_SHA})}" + echo "Ref: $(_get_ref)${GITHUB_SHA:+ (${GITHUB_SHA})}" echo "Mode: ${mode}" echo "Extra kconfig: ${*:-/}" echo @@ -1480,6 +1516,15 @@ analyze() { EXIT_STATUS=1 fi + if [ "${INPUT_GCOV}" = 1 ]; then + if ! _lcov_to_html; then + echo "Unable to generate HTML from LCOV data" | tee -a "${TESTS_SUMMARY}" + tee -a "${TESTS_SUMMARY}" < "${LCOV_HTML}/gen.log" + _register_issue "Critical" "${mode}" "LCOV" + EXIT_STATUS=1 + fi + fi + echo -ne "${COLOR_RESET}" if [ "${EXIT_STATUS}" = "1" ]; then diff --git a/run.sh b/run.sh index 0ff9234..1bc14c0 100755 --- a/run.sh +++ b/run.sh @@ -37,6 +37,8 @@ docker run \ -e "INPUT_PACKETDRILL_STABLE=${VIRTME_PACKETDRILL_STABLE:-0}" \ -e "INPUT_EXPECT_TIMEOUT" \ -e "INPUT_EXTRA_ENV" \ + -e "INPUT_CPUS" \ + -e "INPUT_GCOV" \ -e "VIRTME_ARCH" \ -e "COMPILER" \ --privileged \