Skip to content

Commit 10018ba

Browse files
Merge pull request #1373 from vlad-perevezentsev/add_gen_coverage
Adds a new github CI Action to generate coverage and upload to coveralls
2 parents 5adbab0 + d2c3fbc commit 10018ba

File tree

9 files changed

+386
-32
lines changed

9 files changed

+386
-32
lines changed

.coveragerc

Lines changed: 0 additions & 15 deletions
This file was deleted.
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
name: Generate coverage data for dpnp
2+
on:
3+
pull_request:
4+
push:
5+
branches: [use-skbuild-and-cmake]
6+
7+
jobs:
8+
generate-coverage:
9+
name: Generate coverage and push to Coveralls.io
10+
runs-on: ubuntu-20.04
11+
12+
defaults:
13+
run:
14+
shell: bash -l {0}
15+
16+
env:
17+
python-ver: '3.10'
18+
19+
steps:
20+
- name: Cancel Previous Runs
21+
uses: styfle/[email protected]
22+
with:
23+
access_token: ${{ github.token }}
24+
25+
- name: Checkout repo
26+
uses: actions/checkout@v3
27+
with:
28+
fetch-depth: 0
29+
30+
- name: Setup miniconda
31+
uses: conda-incubator/[email protected]
32+
with:
33+
auto-update-conda: true
34+
python-version: ${{ env.python-ver }}
35+
miniconda-version: 'latest'
36+
activate-environment: 'coverage'
37+
channels: intel, conda-forge
38+
39+
- name: Install Lcov
40+
run: |
41+
sudo apt-get install lcov
42+
- name: Install dpnp dependencies
43+
run: |
44+
conda install cython llvm cmake scikit-build ninja pytest pytest-cov coverage[toml] \
45+
dppy/label/dev::dpctl dpcpp_linux-64 mkl-devel-dpcpp tbb-devel onedpl-devel
46+
- name: Conda info
47+
run: |
48+
conda info
49+
conda list
50+
- name: Build dpnp with coverage
51+
run: |
52+
python scripts/gen_coverage.py --pytest-opts="--ignore tests/test_random.py \
53+
--ignore tests/test_strides.py"
54+
- name: Install coverall dependencies
55+
run: |
56+
sudo gem install coveralls-lcov
57+
conda install coveralls
58+
- name: Upload coverage data to coveralls.io
59+
run: |
60+
echo "Processing pytest-coverage"
61+
export DPNP_PYTEST_LCOV=$(find . -name dpnp_pytest.lcov)
62+
coveralls-lcov -v -n $DPNP_PYTEST_LCOV > pytest-dpnp-c-api-coverage.json
63+
# merge file with coverage data and upload
64+
echo "Merging files with coverage data"
65+
coveralls --service=github --merge=pytest-dpnp-c-api-coverage.json
66+
env:
67+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
68+
COVERALLS_PARALLEL: true
69+
70+
coveralls:
71+
name: Indicate completion to coveralls.io
72+
needs: generate-coverage
73+
runs-on: ubuntu-latest
74+
container: python:3-slim
75+
steps:
76+
- name: Finished
77+
run: |
78+
pip3 install --upgrade coveralls
79+
coveralls --finish
80+
env:
81+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

codecov.yml

Lines changed: 0 additions & 1 deletion
This file was deleted.

dpnp/CMakeLists.txt

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,24 @@ function(build_dpnp_cython_ext _trgt _src _dest)
1515
target_include_directories(${_trgt} PRIVATE ${Dpctl_INCLUDE_DIR})
1616
target_link_directories(${_trgt} PRIVATE ${Dpctl_INCLUDE_DIR}/..)
1717
target_link_libraries(${_trgt} DPCTLSyclInterface)
18-
18+
1919
set(_linker_options "LINKER:${DPNP_LDFLAGS}")
2020
target_link_options(${_trgt} PRIVATE ${_linker_options})
2121
python_extension_module(${_trgt})
22-
22+
23+
if (DPNP_GENERATE_COVERAGE)
24+
set(_copy_cxx_trgt "${_trgt}_copy_cxx")
25+
add_custom_target(
26+
${_copy_cxx_trgt} ALL
27+
COMMAND ${CMAKE_COMMAND}
28+
-DSOURCE_FILE=${_generated_src}
29+
-DDEST=${CMAKE_CURRENT_SOURCE_DIR}
30+
-P ${CMAKE_SOURCE_DIR}/dpnp/cmake/copy_existing.cmake
31+
DEPENDS ${_trgt}
32+
VERBATIM
33+
COMMENT "Copying Cython-generated source for target ${_trgt} to dpnp source layout"
34+
)
35+
endif()
2336
install(TARGETS ${_trgt} LIBRARY DESTINATION ${_dest})
2437
endfunction()
2538

@@ -40,4 +53,3 @@ add_subdirectory(dpnp_utils)
4053
add_subdirectory(fft)
4154
add_subdirectory(linalg)
4255
add_subdirectory(random)
43-

dpnp/cmake/copy_existing.cmake

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
if (EXISTS ${SOURCE_FILE})
2+
configure_file(${SOURCE_FILE} ${DEST} COPYONLY)
3+
endif()

pyproject.toml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
[tool.coverage.run]
2+
plugins = [
3+
"Cython.Coverage"
4+
]
5+
branch = true
6+
source = [
7+
"dpnp",
8+
]
9+
omit = [
10+
"tests/*",
11+
"dpnp/_version.py",
12+
]
13+
14+
[tool.coverage.report]
15+
omit = [
16+
"tests/*",
17+
"dpnp/_version.py",
18+
]
19+
20+
[tool.pytest.ini.options]
21+
minversion = "6.0"
22+
norecursedirs= [
23+
".*", "*.egg*", "build", "dist", "conda-recipe",
24+
]
25+
addopts = [
26+
"--junitxml=junit.xml",
27+
"--ignore setup.py",
28+
"--ignore run_test.py",
29+
"--cov-report term-missing",
30+
"--tb native",
31+
"--strict",
32+
"--durations=20",
33+
"-q -ra",
34+
]

scripts/gen_coverage.py

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
import os
2+
import subprocess
3+
import sys
4+
5+
def run(
6+
c_compiler=None,
7+
cxx_compiler=None,
8+
bin_llvm=None,
9+
pytest_opts = "",
10+
):
11+
12+
IS_LIN = False
13+
14+
if "linux" in sys.platform:
15+
IS_LIN = True
16+
elif sys.platform in ["win32", "cygwin"]:
17+
pass
18+
else:
19+
assert False, sys.platform + " not supported"
20+
21+
if not IS_LIN:
22+
raise RuntimeError(
23+
"This scripts only supports coverage collection on Linux"
24+
)
25+
26+
setup_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
27+
dpctl_cmake_dir = subprocess.check_output([sys.executable, "-m", "dpctl", "--cmakedir"])
28+
29+
cmake_args = [
30+
sys.executable,
31+
"setup.py",
32+
"develop",
33+
"-G=Ninja",
34+
"--",
35+
"-DCMAKE_C_COMPILER:PATH=" + c_compiler,
36+
"-DCMAKE_CXX_COMPILER:PATH=" + cxx_compiler,
37+
"-DDPCTL_MODULE_PATH=" + dpctl_cmake_dir.decode().rstrip(),
38+
"-DCMAKE_VERBOSE_MAKEFILE=ON",
39+
"-DDPNP_GENERATE_COVERAGE=ON",
40+
]
41+
42+
env = None
43+
if bin_llvm:
44+
env = {
45+
"PATH": ":".join((os.environ.get("PATH", ""), bin_llvm)),
46+
"LLVM_TOOLS_HOME": bin_llvm,
47+
}
48+
env.update({k: v for k, v in os.environ.items() if k != "PATH"})
49+
50+
51+
subprocess.check_call(cmake_args, shell=False, cwd=setup_dir, env=env)
52+
53+
env["LLVM_PROFILE_FILE"] = "dpnp_pytest.profraw"
54+
subprocess.check_call(
55+
[
56+
"pytest",
57+
"-q",
58+
"-ra",
59+
"--disable-warnings",
60+
"--cov-config",
61+
"pyproject.toml",
62+
"--cov",
63+
"dpnp",
64+
"--cov-report",
65+
"term-missing",
66+
"--pyargs",
67+
"tests",
68+
"-vv",
69+
*pytest_opts.split(),
70+
],
71+
cwd=setup_dir,
72+
shell=False,
73+
env=env,
74+
)
75+
76+
def find_objects():
77+
import os
78+
79+
objects = []
80+
dpnp_path = os.getcwd()
81+
search_path = os.path.join(dpnp_path, "dpnp")
82+
files = os.listdir(search_path)
83+
for file in files:
84+
if file.endswith("_c.so"):
85+
objects.extend(["-object", os.path.join(search_path, file)])
86+
return objects
87+
88+
objects = find_objects()
89+
instr_profile_fn = "dpnp_pytest.profdata"
90+
# generate instrumentation profile data
91+
subprocess.check_call(
92+
[
93+
os.path.join(bin_llvm, "llvm-profdata"),
94+
"merge",
95+
"-sparse",
96+
env["LLVM_PROFILE_FILE"],
97+
"-o",
98+
instr_profile_fn,
99+
]
100+
)
101+
102+
# export lcov
103+
with open("dpnp_pytest.lcov", "w") as fh:
104+
subprocess.check_call(
105+
[
106+
os.path.join(bin_llvm, "llvm-cov"),
107+
"export",
108+
"-format=lcov",
109+
"-ignore-filename-regex=/tmp/icpx*",
110+
"-instr-profile=" + instr_profile_fn,
111+
]
112+
+ objects,
113+
stdout=fh,
114+
)
115+
116+
if __name__ == "__main__":
117+
import argparse
118+
119+
parser = argparse.ArgumentParser(
120+
description="Driver to build dpnp and generate coverage"
121+
)
122+
driver = parser.add_argument_group(title="Coverage driver arguments")
123+
driver.add_argument(
124+
"--pytest-opts",
125+
help="Channels through additional pytest options",
126+
dest="pytest_opts",
127+
default="",
128+
type=str,
129+
)
130+
131+
args = parser.parse_args()
132+
133+
c_compiler = "icx"
134+
cxx_compiler = "icpx"
135+
icx_path = subprocess.check_output(["which", "icx"])
136+
bin_dir = os.path.dirname(os.path.dirname(icx_path))
137+
bin_llvm = os.path.join(bin_dir.decode("utf-8"), "bin-llvm")
138+
139+
140+
run(
141+
c_compiler=c_compiler,
142+
cxx_compiler=cxx_compiler,
143+
bin_llvm=bin_llvm,
144+
pytest_opts = args.pytest_opts,
145+
)

0 commit comments

Comments
 (0)