Skip to content
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

Adds a new github CI Action to generate coverage and upload to coveralls #1373

Merged
Show file tree
Hide file tree
Changes from all commits
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
15 changes: 0 additions & 15 deletions .coveragerc

This file was deleted.

81 changes: 81 additions & 0 deletions .github/workflows/generate_coverage.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
name: Generate coverage data for dpnp
on:
pull_request:
push:
branches: [use-skbuild-and-cmake]

jobs:
generate-coverage:
name: Generate coverage and push to Coveralls.io
runs-on: ubuntu-20.04

defaults:
run:
shell: bash -l {0}

env:
python-ver: '3.10'

steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.11.0
with:
access_token: ${{ github.token }}

- name: Checkout repo
uses: actions/checkout@v3
with:
fetch-depth: 0

- name: Setup miniconda
uses: conda-incubator/setup-miniconda@v2.2.0
with:
auto-update-conda: true
python-version: ${{ env.python-ver }}
miniconda-version: 'latest'
activate-environment: 'coverage'
channels: intel, conda-forge

- name: Install Lcov
run: |
sudo apt-get install lcov
- name: Install dpnp dependencies
run: |
conda install cython llvm cmake scikit-build ninja pytest pytest-cov coverage[toml] \
dppy/label/dev::dpctl dpcpp_linux-64 mkl-devel-dpcpp tbb-devel onedpl-devel
- name: Conda info
run: |
conda info
conda list
- name: Build dpnp with coverage
run: |
python scripts/gen_coverage.py --pytest-opts="--ignore tests/test_random.py \
--ignore tests/test_strides.py"
Copy link
Contributor

Choose a reason for hiding this comment

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

Probably it would be good to have a separate variable with a list of ignoring tests.

- name: Install coverall dependencies
run: |
sudo gem install coveralls-lcov
conda install coveralls
- name: Upload coverage data to coveralls.io
run: |
echo "Processing pytest-coverage"
export DPNP_PYTEST_LCOV=$(find . -name dpnp_pytest.lcov)
coveralls-lcov -v -n $DPNP_PYTEST_LCOV > pytest-dpnp-c-api-coverage.json
# merge file with coverage data and upload
echo "Merging files with coverage data"
coveralls --service=github --merge=pytest-dpnp-c-api-coverage.json
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COVERALLS_PARALLEL: true

coveralls:
name: Indicate completion to coveralls.io
needs: generate-coverage
runs-on: ubuntu-latest
container: python:3-slim
steps:
- name: Finished
run: |
pip3 install --upgrade coveralls
coveralls --finish
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
1 change: 0 additions & 1 deletion codecov.yml

This file was deleted.

18 changes: 15 additions & 3 deletions dpnp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,24 @@ function(build_dpnp_cython_ext _trgt _src _dest)
target_include_directories(${_trgt} PRIVATE ${Dpctl_INCLUDE_DIR})
target_link_directories(${_trgt} PRIVATE ${Dpctl_INCLUDE_DIR}/..)
target_link_libraries(${_trgt} DPCTLSyclInterface)

set(_linker_options "LINKER:${DPNP_LDFLAGS}")
target_link_options(${_trgt} PRIVATE ${_linker_options})
python_extension_module(${_trgt})


if (DPNP_GENERATE_COVERAGE)
set(_copy_cxx_trgt "${_trgt}_copy_cxx")
add_custom_target(
${_copy_cxx_trgt} ALL
COMMAND ${CMAKE_COMMAND}
-DSOURCE_FILE=${_generated_src}
-DDEST=${CMAKE_CURRENT_SOURCE_DIR}
-P ${CMAKE_SOURCE_DIR}/dpnp/cmake/copy_existing.cmake
DEPENDS ${_trgt}
VERBATIM
COMMENT "Copying Cython-generated source for target ${_trgt} to dpnp source layout"
)
endif()
install(TARGETS ${_trgt} LIBRARY DESTINATION ${_dest})
endfunction()

Expand All @@ -40,4 +53,3 @@ add_subdirectory(dpnp_utils)
add_subdirectory(fft)
add_subdirectory(linalg)
add_subdirectory(random)

3 changes: 3 additions & 0 deletions dpnp/cmake/copy_existing.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
if (EXISTS ${SOURCE_FILE})
configure_file(${SOURCE_FILE} ${DEST} COPYONLY)
endif()
34 changes: 34 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
[tool.coverage.run]
plugins = [
"Cython.Coverage"
]
branch = true
source = [
"dpnp",
]
omit = [
"tests/*",
"dpnp/_version.py",
]

[tool.coverage.report]
omit = [
"tests/*",
"dpnp/_version.py",
]

[tool.pytest.ini.options]
minversion = "6.0"
norecursedirs= [
".*", "*.egg*", "build", "dist", "conda-recipe",
]
addopts = [
"--junitxml=junit.xml",
"--ignore setup.py",
"--ignore run_test.py",
"--cov-report term-missing",
"--tb native",
"--strict",
"--durations=20",
"-q -ra",
]
145 changes: 145 additions & 0 deletions scripts/gen_coverage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import os
import subprocess
import sys

def run(
c_compiler=None,
cxx_compiler=None,
bin_llvm=None,
pytest_opts = "",
):

IS_LIN = False

if "linux" in sys.platform:
IS_LIN = True
elif sys.platform in ["win32", "cygwin"]:
pass
else:
assert False, sys.platform + " not supported"

if not IS_LIN:
raise RuntimeError(
"This scripts only supports coverage collection on Linux"
)

setup_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
dpctl_cmake_dir = subprocess.check_output([sys.executable, "-m", "dpctl", "--cmakedir"])

cmake_args = [
sys.executable,
"setup.py",
"develop",
"-G=Ninja",
"--",
"-DCMAKE_C_COMPILER:PATH=" + c_compiler,
"-DCMAKE_CXX_COMPILER:PATH=" + cxx_compiler,
"-DDPCTL_MODULE_PATH=" + dpctl_cmake_dir.decode().rstrip(),
"-DCMAKE_VERBOSE_MAKEFILE=ON",
"-DDPNP_GENERATE_COVERAGE=ON",
]

env = None
if bin_llvm:
env = {
"PATH": ":".join((os.environ.get("PATH", ""), bin_llvm)),
"LLVM_TOOLS_HOME": bin_llvm,
}
env.update({k: v for k, v in os.environ.items() if k != "PATH"})


subprocess.check_call(cmake_args, shell=False, cwd=setup_dir, env=env)

env["LLVM_PROFILE_FILE"] = "dpnp_pytest.profraw"
subprocess.check_call(
[
"pytest",
"-q",
"-ra",
"--disable-warnings",
"--cov-config",
"pyproject.toml",
"--cov",
"dpnp",
"--cov-report",
"term-missing",
"--pyargs",
"tests",
"-vv",
*pytest_opts.split(),
],
cwd=setup_dir,
shell=False,
env=env,
)

def find_objects():
import os

objects = []
dpnp_path = os.getcwd()
search_path = os.path.join(dpnp_path, "dpnp")
files = os.listdir(search_path)
for file in files:
if file.endswith("_c.so"):
objects.extend(["-object", os.path.join(search_path, file)])
return objects

objects = find_objects()
instr_profile_fn = "dpnp_pytest.profdata"
# generate instrumentation profile data
subprocess.check_call(
[
os.path.join(bin_llvm, "llvm-profdata"),
"merge",
"-sparse",
env["LLVM_PROFILE_FILE"],
"-o",
instr_profile_fn,
]
)

# export lcov
with open("dpnp_pytest.lcov", "w") as fh:
subprocess.check_call(
[
os.path.join(bin_llvm, "llvm-cov"),
"export",
"-format=lcov",
"-ignore-filename-regex=/tmp/icpx*",
"-instr-profile=" + instr_profile_fn,
]
+ objects,
stdout=fh,
)

if __name__ == "__main__":
import argparse

parser = argparse.ArgumentParser(
description="Driver to build dpnp and generate coverage"
)
driver = parser.add_argument_group(title="Coverage driver arguments")
driver.add_argument(
"--pytest-opts",
help="Channels through additional pytest options",
dest="pytest_opts",
default="",
type=str,
)

args = parser.parse_args()

c_compiler = "icx"
cxx_compiler = "icpx"
oleksandr-pavlyk marked this conversation as resolved.
Show resolved Hide resolved
icx_path = subprocess.check_output(["which", "icx"])
bin_dir = os.path.dirname(os.path.dirname(icx_path))
bin_llvm = os.path.join(bin_dir.decode("utf-8"), "bin-llvm")


run(
c_compiler=c_compiler,
cxx_compiler=cxx_compiler,
bin_llvm=bin_llvm,
pytest_opts = args.pytest_opts,
)
Loading