-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
cmake: Add Coverage
script
#191
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# Copyright (c) 2024-present The Bitcoin Core developers | ||
# Distributed under the MIT software license, see the accompanying | ||
# file COPYING or https://opensource.org/license/mit/. | ||
|
||
exec @COV_TOOL@ "$@" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
# Copyright (c) 2024-present The Bitcoin Core developers | ||
# Distributed under the MIT software license, see the accompanying | ||
# file COPYING or https://opensource.org/license/mit/. | ||
|
||
include(${CMAKE_CURRENT_LIST_DIR}/CoverageInclude.cmake) | ||
|
||
set(functional_test_runner test/functional/test_runner.py) | ||
if(EXTENDED_FUNCTIONAL_TESTS) | ||
list(APPEND functional_test_runner --extended) | ||
endif() | ||
if(DEFINED JOBS) | ||
list(APPEND CMAKE_CTEST_COMMAND -j ${JOBS}) | ||
list(APPEND functional_test_runner -j ${JOBS}) | ||
endif() | ||
|
||
execute_process( | ||
COMMAND ${CMAKE_CTEST_COMMAND} --build-config Coverage | ||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} | ||
COMMAND_ERROR_IS_FATAL ANY | ||
) | ||
execute_process( | ||
COMMAND ${LCOV_COMMAND} --capture --directory src --test-name test_bitcoin --output-file test_bitcoin.info | ||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} | ||
) | ||
execute_process( | ||
COMMAND ${LCOV_COMMAND} --zerocounters --directory src | ||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} | ||
) | ||
execute_process( | ||
COMMAND ${LCOV_FILTER_COMMAND} test_bitcoin.info test_bitcoin_filtered.info | ||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} | ||
) | ||
execute_process( | ||
COMMAND ${LCOV_COMMAND} --add-tracefile test_bitcoin_filtered.info --output-file test_bitcoin_filtered.info | ||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} | ||
) | ||
execute_process( | ||
COMMAND ${LCOV_COMMAND} --add-tracefile baseline_filtered.info --add-tracefile test_bitcoin_filtered.info --output-file test_bitcoin_coverage.info | ||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} | ||
) | ||
execute_process( | ||
COMMAND ${GENHTML_COMMAND} test_bitcoin_coverage.info --output-directory test_bitcoin.coverage | ||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} | ||
) | ||
|
||
execute_process( | ||
COMMAND ${functional_test_runner} | ||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} | ||
COMMAND_ERROR_IS_FATAL ANY | ||
) | ||
execute_process( | ||
COMMAND ${LCOV_COMMAND} --capture --directory src --test-name functional-tests --output-file functional_test.info | ||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} | ||
) | ||
execute_process( | ||
COMMAND ${LCOV_COMMAND} --zerocounters --directory src | ||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} | ||
) | ||
execute_process( | ||
COMMAND ${LCOV_FILTER_COMMAND} functional_test.info functional_test_filtered.info | ||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} | ||
) | ||
execute_process( | ||
COMMAND ${LCOV_COMMAND} --add-tracefile functional_test_filtered.info --output-file functional_test_filtered.info | ||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} | ||
) | ||
execute_process( | ||
COMMAND ${LCOV_COMMAND} --add-tracefile baseline_filtered.info --add-tracefile test_bitcoin_filtered.info --add-tracefile functional_test_filtered.info --output-file total_coverage.info | ||
COMMAND ${GREP_EXECUTABLE} "%" | ||
COMMAND ${AWK_EXECUTABLE} "{ print substr($3,2,50) \"/\" $5 }" | ||
OUTPUT_FILE coverage_percent.txt | ||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} | ||
) | ||
execute_process( | ||
COMMAND ${GENHTML_COMMAND} total_coverage.info --output-directory total.coverage | ||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
# Copyright (c) 2024-present The Bitcoin Core developers | ||
# Distributed under the MIT software license, see the accompanying | ||
# file COPYING or https://opensource.org/license/mit/. | ||
|
||
include(${CMAKE_CURRENT_LIST_DIR}/CoverageInclude.cmake) | ||
|
||
if(NOT DEFINED FUZZ_SEED_CORPUS_DIR) | ||
set(FUZZ_SEED_CORPUS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/qa-assets/fuzz_seed_corpus) | ||
endif() | ||
|
||
execute_process( | ||
COMMAND test/fuzz/test_runner.py ${FUZZ_SEED_CORPUS_DIR} --loglevel DEBUG | ||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} | ||
COMMAND_ERROR_IS_FATAL ANY | ||
) | ||
execute_process( | ||
COMMAND ${LCOV_COMMAND} --capture --directory src --test-name fuzz-tests --output-file fuzz.info | ||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} | ||
) | ||
execute_process( | ||
COMMAND ${LCOV_COMMAND} --zerocounters --directory src | ||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} | ||
) | ||
execute_process( | ||
COMMAND ${LCOV_FILTER_COMMAND} fuzz.info fuzz_filtered.info | ||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} | ||
) | ||
execute_process( | ||
COMMAND ${LCOV_COMMAND} --add-tracefile fuzz_filtered.info --output-file fuzz_filtered.info | ||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} | ||
) | ||
execute_process( | ||
COMMAND ${LCOV_COMMAND} --add-tracefile baseline_filtered.info --add-tracefile fuzz_filtered.info --output-file fuzz_coverage.info | ||
COMMAND ${GREP_EXECUTABLE} "%" | ||
COMMAND ${AWK_EXECUTABLE} "{ print substr($3,2,50) \"/\" $5 }" | ||
OUTPUT_FILE coverage_percent.txt | ||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} | ||
) | ||
execute_process( | ||
COMMAND ${GENHTML_COMMAND} fuzz_coverage.info --output-directory fuzz.coverage | ||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
# Copyright (c) 2024-present The Bitcoin Core developers | ||
# Distributed under the MIT software license, see the accompanying | ||
# file COPYING or https://opensource.org/license/mit/. | ||
|
||
if("@CMAKE_CXX_COMPILER_ID@" STREQUAL "Clang") | ||
find_program(LLVM_COV_EXECUTABLE llvm-cov REQUIRED) | ||
set(COV_TOOL "${LLVM_COV_EXECUTABLE} gcov") | ||
Comment on lines
+5
to
+7
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Clang has a different native workflow: https://clang.llvm.org/docs/SourceBasedCodeCoverage.html which I guess produces better results compared to its gcc compatibility layer. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right. But this PR aims to mirror the master branch behaviour. Further improvements can be done later, no? |
||
else() | ||
find_program(GCOV_EXECUTABLE gcov REQUIRED) | ||
set(COV_TOOL "${GCOV_EXECUTABLE}") | ||
endif() | ||
|
||
# COV_TOOL is used to replace a placeholder. | ||
configure_file( | ||
cmake/cov_tool_wrapper.sh.in ${CMAKE_CURRENT_LIST_DIR}/cov_tool_wrapper.sh | ||
FILE_PERMISSIONS OWNER_READ OWNER_EXECUTE | ||
GROUP_READ GROUP_EXECUTE | ||
WORLD_READ | ||
@ONLY | ||
) | ||
|
||
find_program(LCOV_EXECUTABLE lcov REQUIRED) | ||
separate_arguments(LCOV_OPTS) | ||
set(LCOV_COMMAND ${LCOV_EXECUTABLE} --gcov-tool ${CMAKE_CURRENT_LIST_DIR}/cov_tool_wrapper.sh ${LCOV_OPTS}) | ||
|
||
find_program(GENHTML_EXECUTABLE genhtml REQUIRED) | ||
set(GENHTML_COMMAND ${GENHTML_EXECUTABLE} --show-details ${LCOV_OPTS}) | ||
|
||
find_program(GREP_EXECUTABLE grep REQUIRED) | ||
find_program(AWK_EXECUTABLE awk REQUIRED) | ||
|
||
set(LCOV_FILTER_COMMAND ./filter-lcov.py) | ||
list(APPEND LCOV_FILTER_COMMAND -p "/usr/local/") | ||
list(APPEND LCOV_FILTER_COMMAND -p "/usr/include/") | ||
list(APPEND LCOV_FILTER_COMMAND -p "/usr/lib/") | ||
list(APPEND LCOV_FILTER_COMMAND -p "/usr/lib64/") | ||
list(APPEND LCOV_FILTER_COMMAND -p "src/leveldb/") | ||
list(APPEND LCOV_FILTER_COMMAND -p "src/crc32c/") | ||
list(APPEND LCOV_FILTER_COMMAND -p "src/bench/") | ||
list(APPEND LCOV_FILTER_COMMAND -p "src/crypto/ctaes") | ||
list(APPEND LCOV_FILTER_COMMAND -p "src/minisketch") | ||
list(APPEND LCOV_FILTER_COMMAND -p "src/secp256k1") | ||
list(APPEND LCOV_FILTER_COMMAND -p "depends") | ||
|
||
execute_process( | ||
COMMAND ${LCOV_COMMAND} --capture --initial --directory src --output-file baseline.info | ||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} | ||
) | ||
execute_process( | ||
COMMAND ${LCOV_FILTER_COMMAND} baseline.info baseline_filtered.info | ||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} | ||
) | ||
execute_process( | ||
COMMAND ${LCOV_COMMAND} --add-tracefile baseline_filtered.info --output-file baseline_filtered.info | ||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -481,25 +481,34 @@ $ ./test/functional/test_runner.py --valgrind | |
|
||
### Compiling for test coverage | ||
|
||
LCOV can be used to generate a test coverage report based upon `make check` | ||
LCOV can be used to generate a test coverage report based upon `ctest` | ||
execution. LCOV must be installed on your system (e.g. the `lcov` package | ||
on Debian/Ubuntu). | ||
|
||
To enable LCOV report generation during test runs: | ||
|
||
```shell | ||
./configure --enable-lcov | ||
make | ||
make cov | ||
cmake -B build -DCMAKE_BUILD_TYPE=Coverage | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think with/without coverage should be independent option from debug/release. For example one may want to gather coverage on debug builds or release builds? I do not think we need a dedicated build type "Coverage" in order to pass a few extra flags which is already supported by the build system with For clang, that would be extra I know this would be different from how autotools works, but I would propose to have a shell script in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Is this something that is commonly done? What would the purpose of this be?
Not sure about this. I prefer to work with the build system directly without having to understand a wrapper script first if I want to tweak something. |
||
cmake --build build | ||
cmake -P build/Coverage.cmake | ||
|
||
# A coverage report will now be accessible at `./test_bitcoin.coverage/index.html`, | ||
# which covers unit tests, and `./total.coverage/index.html`, which covers | ||
# A coverage report will now be accessible at `./build/test_bitcoin.coverage/index.html`, | ||
# which covers unit tests, and `./build/total.coverage/index.html`, which covers | ||
# unit and functional tests. | ||
``` | ||
|
||
Additional LCOV options can be specified using `LCOV_OPTS`, but may be dependant | ||
on the version of LCOV. For example, when using LCOV `2.x`, branch coverage can be | ||
enabled by setting `LCOV_OPTS="--rc branch_coverage=1"`, when configuring. | ||
enabled by setting `LCOV_OPTS="--rc branch_coverage=1"`: | ||
|
||
``` | ||
cmake -DLCOV_OPTS="--rc branch_coverage=1" -P build/Coverage.cmake | ||
``` | ||
|
||
To enable test parallelism: | ||
``` | ||
cmake -DJOBS=$(nproc) -P build/Coverage.cmake | ||
``` | ||
|
||
### Performance profiling with perf | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file consists mostly of such
execute_process()
calls. The most natural way to execute a bunch of commands is from a shell script. I would suggest to use a shell script for this. This 77 lines cmake file would be equivalent roughly to the following:There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From CMake's point of view, using a platform independent approach is more natural :)
However, I have to admit that it is not expected that the user will run coverage scripts on Windows.