Skip to content

Commit

Permalink
[REVIEW] Adding Cython to Code Coverage (#3111)
Browse files Browse the repository at this point in the history
* Adding ability to build with --linetrace=1 to support cython codecov

* Adding PR to CHANGELOG

* Style cleanup

* Converting BUILD_PYTHON_ARGS to be a argument in build.sh
  • Loading branch information
mdemoret-nv authored Nov 6, 2020
1 parent 93eef64 commit 25b29f5
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 32 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
- PR #3052: Speeding up MNMG KNN Cl&Re testing
- PR #3115: Speeding up MNMG UMAP testing
- PR #3112: Speed test_array
- PR #3111: Adding Cython to Code Coverage

## Bug Fixes
- PR #3065: Refactoring prims metrics function names from camelcase to underscore format
Expand Down
15 changes: 10 additions & 5 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ ARGS=$*
REPODIR=$(cd $(dirname $0); pwd)

VALIDTARGETS="clean libcuml cuml cpp-mgtests prims bench prims-bench cppdocs pydocs"
VALIDFLAGS="-v -g -n --allgpuarch --buildfaiss --buildgtest --singlegpu --nvtx --show_depr_warn -h --help "
VALIDFLAGS="-v -g -n --allgpuarch --buildfaiss --buildgtest --singlegpu --nvtx --show_depr_warn --codecov -h --help "
VALIDARGS="${VALIDTARGETS} ${VALIDFLAGS}"
HELP="$0 [<target> ...] [<flag> ...]
where <target> is:
Expand All @@ -43,6 +43,8 @@ HELP="$0 [<target> ...] [<flag> ...]
--singlegpu - Build libcuml and cuml without multigpu components
--nvtx - Enable nvtx for profiling support
--show_depr_warn - show cmake deprecation warnings
--codecov - Enable code coverage support by compiling with Cython linetracing
and profiling enabled (WARNING: Impacts performance)
-h - print this text
default action (no args) is to build and install 'libcuml', 'cuml', and 'prims' targets only for the detected GPU arch
Expand All @@ -58,7 +60,7 @@ BUILD_TYPE=Release
INSTALL_TARGET=install
BUILD_ALL_GPU_ARCH=0
SINGLEGPU_CPP_FLAG=""
SINGLEGPU_PYTHON_FLAG=""
BUILD_PYTHON_ARGS=${BUILD_PYTHON_ARGS:=""}
NVTX=OFF
CLEAN=0
BUILD_DISABLE_DEPRECATION_WARNING=ON
Expand Down Expand Up @@ -115,7 +117,7 @@ if hasArg --allgpuarch; then
BUILD_ALL_GPU_ARCH=1
fi
if hasArg --singlegpu; then
SINGLEGPU_PYTHON_FLAG="--singlegpu"
BUILD_PYTHON_ARGS="${BUILD_PYTHON_ARGS} --singlegpu"
SINGLEGPU_CPP_FLAG=ON
fi
if hasArg cpp-mgtests; then
Expand All @@ -133,6 +135,9 @@ fi
if hasArg --show_depr_warn; then
BUILD_DISABLE_DEPRECATION_WARNING=OFF
fi
if hasArg --codecov; then
BUILD_PYTHON_ARGS="${BUILD_PYTHON_ARGS} --linetrace=1 --profile"
fi
if hasArg clean; then
CLEAN=1
fi
Expand Down Expand Up @@ -224,9 +229,9 @@ fi
if completeBuild || hasArg cuml || hasArg pydocs; then
cd ${REPODIR}/python
if [[ ${INSTALL_TARGET} != "" ]]; then
python setup.py build_ext -j${PARALLEL_LEVEL:-1} ${SINGLEGPU_PYTHON_FLAG} --library-dir=${LIBCUML_BUILD_DIR} install --single-version-externally-managed --record=record.txt
python setup.py build_ext -j${PARALLEL_LEVEL:-1} ${BUILD_PYTHON_ARGS} --library-dir=${LIBCUML_BUILD_DIR} install --single-version-externally-managed --record=record.txt
else
python setup.py build_ext -j${PARALLEL_LEVEL:-1} --library-dir=${LIBCUML_BUILD_DIR} ${SINGLEGPU_PYTHON_FLAG}
python setup.py build_ext -j${PARALLEL_LEVEL:-1} ${BUILD_PYTHON_ARGS} --library-dir=${LIBCUML_BUILD_DIR}
fi

if hasArg pydocs; then
Expand Down
4 changes: 2 additions & 2 deletions ci/gpu/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ if [[ -z "$PROJECT_FLASH" || "$PROJECT_FLASH" == "0" ]]; then
################################################################################

gpuci_logger "Build from source"
$WORKSPACE/build.sh clean libcuml cuml prims bench -v
$WORKSPACE/build.sh clean libcuml cuml prims bench -v --codecov

gpuci_logger "Resetting LD_LIBRARY_PATH"

Expand Down Expand Up @@ -190,7 +190,7 @@ else
conda install -c $WORKSPACE/ci/artifacts/cuml/cpu/conda-bld/ libcuml

gpuci_logger "Building cuml"
"$WORKSPACE/build.sh" -v cuml
"$WORKSPACE/build.sh" -v cuml --codecov

gpuci_logger "Python pytest for cuml"
cd $WORKSPACE/python
Expand Down
1 change: 1 addition & 0 deletions python/.coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
[run]
include = cuml/*
omit = cuml/test/*
plugins = Cython.Coverage
110 changes: 85 additions & 25 deletions python/cython_build_ext.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,15 @@ class cython_build_ext(_build_ext, object):
Parameters
----------
language_level : {"2", "3", "3str"}, default="2"
Globally set the Python language level to be used for module
compilation. Default is compatibility with Python 2. To enable Python 3
source code semantics, set this to 3 (or 3str)
annotate : bool, default=False
If True, will produce a HTML file for each of the .pyx or .py files
compiled. The HTML file gives an indication of how much Python
interaction there is in each of the source code lines, compared to
plain C code. It also allows you to see the C/C++ code generated for
each line of Cython code. This report is invaluable when optimizing a
function for speed, and for determining when to release the GIL: in
general, a nogil block may contain only “white” code. See examples in
Determining where to add types or Primes.
binding : bool, default=True
Controls whether free functions behave more like Python’s CFunctions
(e.g. len()) or, when set to True, more like Python’s functions. When
Expand All @@ -59,46 +64,74 @@ class cython_build_ext(_build_ext, object):
annotations.
Changed in version 3.0.0: Default changed from False to True
profile : bool, default=False
Write hooks for Python profilers into the compiled C code.
cython_exclude : list of str
When passing glob patterns as module_list, you can exclude certain
module names explicitly by passing them into the exclude option.
embedsignature : bool, default=False
If set to True, Cython will embed a textual copy of the call signature
in the docstring of all Python visible functions and classes. Tools
like IPython and epydoc can thus display the signature, which cannot
otherwise be retrieved after compilation.
cython_exclude : list of str
When passing glob patterns as module_list, you can exclude certain
module names explicitly by passing them into the exclude option.
gdb_debug : bool, default=False
Passes the `gdb_debug` argument to `cythonize()`. Setting up debugging
for Cython can be difficult. See the debugging docs here
https://cython.readthedocs.io/en/latest/src/userguide/debugging.html
language_level : {"2", "3", "3str"}, default="2"
Globally set the Python language level to be used for module
compilation. Default is compatibility with Python 2. To enable Python 3
source code semantics, set this to 3 (or 3str)
linetrace : bool, default=False
Write line tracing hooks for Python profilers or coverage reporting
into the compiled C code. This also enables profiling. Default is
False. Note that the generated module will not actually use line
tracing, unless you additionally pass the C macro definition
``CYTHON_TRACE=1`` to the C compiler (e.g. using the setuptools option
define_macros). Define ``CYTHON_TRACE_NOGIL=1`` to also include nogil
functions and sections.
profile : bool, default=False
Write hooks for Python profilers into the compiled C code.
"""
user_options = [
('language-level=', None,
'Sets the python language syntax to use "2", "3", "3str".'),
("binding", None,
("annotate=",
None,
"Passes the `annotate` argument to `cythonize()`. See the Cython "
"docs for more info."),
("binding",
None,
"Sets the binding Cython compiler directive. See the Cython docs for "
"more info."),
("profile", None,
"Sets the profile Cython compiler directive. See the Cython docs for "
"more info."),
("embedsignature", None,
"Sets the `embedsignature` Cython compiler directive. See the Cython "
"docs for more info."),
("cython-exclude=", None,
("cython-exclude=",
None,
"Sets the exclude argument for `cythonize()`. See the Cython docs for"
" more info."),
("gdb-debug=", None,
("embedsignature",
None,
"Sets the `embedsignature` Cython compiler directive. See the Cython "
"docs for more info."),
("gdb-debug=",
None,
"Passes the `gdb_debug` argument to `cythonize()`. See the Cython "
"docs for more info.")
"docs for more info."),
('language-level=',
None,
'Sets the python language syntax to use "2", "3", "3str".'),
("linetrace=",
None,
"Passes the `linetrace` argument to `cythonize()`. See the Cython "
"docs for more info."),
("profile",
None,
"Sets the profile Cython compiler directive. See the Cython docs for "
"more info."),
] + _build_ext.user_options

boolean_options = [
"annotate",
"binding",
"profile",
"embedsignature",
"gdb-debug",
"linetrace",
"profile",
] + _build_ext.boolean_options

def initialize_options(self):
Expand All @@ -107,12 +140,15 @@ def initialize_options(self):
detect if they were set by the user
"""

self.language_level = None
self.annotate = None
self.binding = None
self.profile = None
self.embedsignature = None
self.cython_exclude = None
self.embedsignature = None
self.gdb_debug = None
self.language_level = None
self.linetrace = None
self.profile = None

super().initialize_options()

def finalize_options(self):
Expand Down Expand Up @@ -153,13 +189,37 @@ def finalize_options(self):
self.profile = bool(self.profile)
compiler_directives.update({"profile": self.profile})

if (self.linetrace is not None):
self.linetrace = bool(self.linetrace)
compiler_directives.update({"linetrace": self.linetrace})

# Also need the compiler directive. Only add if it hasnt been
# specified yet
for ext in self.distribution.ext_modules:
if (not hasattr(ext, "define_macros")):
ext.define_macros = []

found_macro = False

for mac in ext.define_macros:
if (mac[0] == "CYTHON_TRACE_NOGIL"):
found_macro = True
break

if not found_macro:
ext.define_macros.append(("CYTHON_TRACE_NOGIL", 1))

if (self.embedsignature is not None):
self.embedsignature = bool(self.embedsignature)
compiler_directives.update(
{"embedsignature": self.embedsignature})

cythonize_kwargs = {}

if (self.annotate is not None):

cythonize_kwargs.update({"annotate": self.annotate})

if (self.cython_exclude is not None):

if (isinstance(self.cython_exclude, str)):
Expand Down
1 change: 1 addition & 0 deletions python/setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,5 @@ inplace = True
binding = True
language_level = 3
profile = False
linetrace = False
embedsignature = True

0 comments on commit 25b29f5

Please sign in to comment.