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

[REVIEW] Adding Cython to Code Coverage #3111

Merged
merged 5 commits into from
Nov 6, 2020
Merged
Show file tree
Hide file tree
Changes from 3 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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
- PR #3067: Deleting prims moved to RAFT and updating header paths
- PR #3074: Reducing dask coordinate descent test runtime
- PR #3052: Speeding up MNMG KNN Cl&Re testing
- PR #3111: Adding Cython to Code Coverage

## Bug Fixes
- PR #3033: Splitting ml metrics to individual files
Expand Down
8 changes: 4 additions & 4 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ BUILD_TYPE=Release
INSTALL_TARGET=install
BUILD_ALL_GPU_ARCH=0
SINGLEGPU_CPP_FLAG=""
SINGLEGPU_PYTHON_FLAG=""
BUILD_PYTHON_ARGS=${BUILD_PYTHON_ARGS:=""}
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe this should be a command-line flag instead, like "--python-args"? Seems like that would be more consistent with the other inputs

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I can try and convert it to a command line argument, but it will be a little riskier since it will be a little different than all of our current command line args. This would be the only one that accepts an argument value. All of the current options (-g, -n, --singlegpu, etc.) are boolean flags which is much easier to parse. I'm just a little concerned that we may miss some edge cases when parsing arbitrary arguments since this runs on several platforms.

I'll give it a shot and see if there are any other build.sh scripts in rapids that take arbitrary values

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I ended up sticking with boolean flags and added a new --codecov option to build.sh. This doesn't add any risk from parsing argument values and is generic enough to possibly include C++ code coverage one day (if we can figure out how to do it).

I'm open to different argument name. Let me know if you have a better selection. Link to the help section: https://github.com/rapidsai/cuml/pull/3111/files#diff-4d2a8eefdf2a9783512a35da4dc7676a66404b6f3826a8af9aad038722da6823R46-R47

NVTX=OFF
CLEAN=0
BUILD_DISABLE_DEPRECATION_WARNING=ON
Expand Down Expand Up @@ -115,7 +115,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 Down Expand Up @@ -224,9 +224,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} --library-dir=${LIBCUML_BUILD_DIR} ${BUILD_PYTHON_ARGS}
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
BUILD_PYTHON_ARGS="--linetrace=1" $WORKSPACE/build.sh clean libcuml cuml prims bench -v

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
BUILD_PYTHON_ARGS="--linetrace=1" "$WORKSPACE/build.sh" -v cuml

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",
JohnZed marked this conversation as resolved.
Show resolved Hide resolved
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",
JohnZed marked this conversation as resolved.
Show resolved Hide resolved
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