Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Refactor this as a Makefile target
  • Loading branch information
mdboom committed Oct 31, 2022
commit 776e423ce7f63655c34f7e6fd5d0220e742992ea
19 changes: 5 additions & 14 deletions .github/workflows/c-coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,26 +40,17 @@ jobs:
uses: hendrikmuhs/ccache-action@v1
- name: Configure clang (with coverage)
run: |
echo "CC=/usr/lib/ccache/clang-12 -fprofile-instr-generate -fcoverage-mapping" >> $GITHUB_ENV
echo "CXX=/usr/lib/ccache/clang++-12 -fprofile-instr-generate -fcoverage-mapping" >> $GITHUB_ENV
echo "CC=clang" >> $GITHUB_ENV
echo "CXX=clang++" >> $GITHUB_ENV
- name: Configure CPython
run: ./configure --with-pydebug --with-openssl=$OPENSSL_DIR
- name: Build CPython
run: make -j4
- name: Collect coverage data
# Specify the LLVM_PROFILE_FILE using %m so multiple shared objects can write
# in parallel. Set the full path to the directory so results aren't written
# into temporary directories created by tests.
# Using "-j 1" is important, or the Github Action runs out of memory
run: LLVM_PROFILE_FILE=${PWD}/python%m.profraw xvfb-run ./python -m test -j 1
- name: Generate coverage report
run: |
llvm-profdata-12 merge -sparse python*.profraw -o python.profdata
llvm-cov-12 show -format=html -output-dir=cpython-coverage -instr-profile=python.profdata -show-branches=count -show-regions python .
# Using "-j1" is important, or the Github Action runs out of memory
run: EXTRATESTOPTS=-j1 xvfb-run make coverage-report-llvm
- name: Publish coverage-report
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does every run clobber the previous run's report? What about CI runs on PRs and CI runs from release branches? Can this be configured to commit the coverage results into a branch in the repo matching the reponame+branchname? Or do branches not render in gh-pages? in which case it'd need to be subdirectories in the repo.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently, this clobbers the previous run. That is easily changed with a flag, but then we could run into Github repository size limits (each result is around 100MB of HTML). It's probably possible to keep the last N commits, but the tool I'm using to publish doesn't support that directly.

This is currently configured to just run on the main branch once a day. We could do multiple branches that publish to subdirectories if you think there's a good use case for that. (Github pages only publishes a single branch, but subdirectories would work).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we would get some funding to run a persistent VM with public hostname from ... let's say Azure, then it would be trivial to create a buildbot worker and serve the LCOV results from HTTP server. They are static HTTP and JS files on the file system after all. Just saying :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't mind main branch only and once a day. Anyone working on coverage is presumably doing their own local coverage runs while creating PRs.

Regarding a buildbot configured to host the results, while I could simply set one up it'd probably make more sense for mdboom to do that and be an admin given who's driving this work. :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I'd be happy to admin that if it comes to it. I think it's fine to go with the Github Action here as an MVP, and if the amount of history or frequency of runs isn't good enough, we can revisit migrating to our own VM down the road.

uses: JamesIves/github-pages-deploy-action@v4
with:
folder: cpython-coverage
folder: llvm-cov-report
repository-name: '' # TODO Destination
token: ${{ secrets.COVERAGE_DEPLOY_TOKEN }} # TODO: Use an organization-level token
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What permissions does the token need?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good question, and it isn't terribly well-documented: https://github.com/JamesIves/github-pages-deploy-action#required-setup

I think the permission to push to the coverage results repo is all that's needed, but we may not know until we try.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it need two separate tokens then, one (with read permissions) for the cpython repo, and another (with write permissions) for the coverage results repo?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need a token for read permissions to the cpython repo. Just one to write to a repo under the python org.

single-commit: true
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
*.gc??
*.profclang?
*.profraw
*.profdata
*.dyn
.gdb_history
.purify
Expand Down
44 changes: 44 additions & 0 deletions Makefile.pre.in
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ PGO_PROF_USE_FLAG=@PGO_PROF_USE_FLAG@
LLVM_PROF_MERGER=@LLVM_PROF_MERGER@
LLVM_PROF_FILE=@LLVM_PROF_FILE@
LLVM_PROF_ERR=@LLVM_PROF_ERR@
LLVM_PROFDATA=@LLVM_PROFDATA@
LLVM_COV=@LLVM_COV@
DTRACE= @DTRACE@
DFLAGS= @DFLAGS@
DTRACE_HEADERS= @DTRACE_HEADERS@
Expand Down Expand Up @@ -316,6 +318,10 @@ COVERAGE_REPORT=$(abs_builddir)/lcov-report
COVERAGE_LCOV_OPTIONS=--rc lcov_branch_coverage=1
COVERAGE_REPORT_OPTIONS=--rc lcov_branch_coverage=1 --branch-coverage --title "CPython $(VERSION) LCOV report [commit $(shell $(GITVERSION))]"

# report files for llvm-cov coverage report
COVERAGE_INFO_LLVM= $(abs_builddir)/coverage.profdata
COVERAGE_REPORT_LLVM=$(abs_builddir)/llvm-cov-report
COVERAGE_REPORT_OPTIONS_LLVM=-show-branches=count -show-regions

# === Definitions added by makesetup ===

Expand Down Expand Up @@ -701,6 +707,44 @@ coverage-report: regen-token regen-frozen
@ # build lcov report
$(MAKE) coverage-lcov

# Compile and calculate coverage with llvm-cov
.PHONY=check-clang coverage-llvm coverage-profdata coverage-report-llvm

# Check whether the compiler is clang, and if not, error out.
check-clang:
($(CC) --version | grep clang) || \
(echo "LLVM coverage only works with clang. Set CC=clang and CXX=clang++ and re-run ./configure"; exit 1)

coverage-llvm: check-clang
@echo "Building with support for coverage checking:"
$(MAKE) clean
@ # Override CC rather than CFLAGS since these flags must come first
$(MAKE) @DEF_MAKE_RULE@ CC="$(CC) -fprofile-instr-generate -fcoverage-mapping"

coverage-profdata:
@echo "Creating Coverage HTML report with llvm-profdata/llvm-cov:"
@rm -f $(COVERAGE_INFO_LLVM)
@rm -rf $(COVERAGE_REPORT_LLVM)
@ # Merge coverage results
$(LLVM_PROFDATA) merge -sparse python*.profraw -o $(COVERAGE_INFO_LLVM)
@ # Generate HTML
$(LLVM_COV) show -format=html -output-dir=$(COVERAGE_REPORT_LLVM) -instr-profile=$(COVERAGE_INFO_LLVM) $(COVERAGE_REPORT_OPTIONS_LLVM) python .
@echo
@echo "llvm-cov report at $(COVERAGE_REPORT_LLVM)/index.html"
@echo

# Force regeneration of parser and importlib
# Specify the LLVM_PROFILE_FILE using %m so multiple shared objects can write
# in parallel. Set the full path to the directory so results aren't written
# into temporary directories created by tests.
coverage-report-llvm: regen-token regen-importlib
@ # build with coverage info
$(MAKE) coverage-llvm
@ # run tests, ignore failures
LLVM_PROFILE_FILE=${PWD}/python%m.profraw $(TESTRUNNER) $(TESTOPTS) || true
@ # build llvm-cov report
$(MAKE) coverage-profdata

# Run "Argument Clinic" over all source files
.PHONY=clinic
clinic: check-clean-src $(srcdir)/Modules/_blake2/blake2s_impl.c
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
A new Makefile target ``coverage-report-llvm`` will use ``clang`` and
``llvm-cov`` to generate a coverage report. This provides more details about
branch coverage and subexpressions than the existing ``gcc`` and ``lcov``
based ``coverage-report``.
100 changes: 100 additions & 0 deletions configure

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -2055,6 +2055,8 @@ case $CC in
LLVM_PROF_FILE=""
;;
esac
AC_SUBST(LLVM_COV)
AC_PATH_TOOL(LLVM_COV, llvm-cov, '', ${llvm_path})

# XXX Shouldn't the code above that fiddles with BASECFLAGS and OPT be
# merged with this chunk of code?
Expand Down