diff --git a/docs/source/usage.rst b/docs/source/usage.rst index 38ff35c..50fe879 100644 --- a/docs/source/usage.rst +++ b/docs/source/usage.rst @@ -255,3 +255,47 @@ Running the cell above will compile and execute the vector addition code in the SM Active Cycles cycle 383.65 Compute (SM) Throughput % 1.19 ----------------------- ------------- ------------ + +Compiler arguments +------------------ + +In the same way profiler arguments can be passed to the profiling tool, +compiling arguments can be passed to **nvcc**: + +.. code-block:: c++ + + %cuda_group_run --group "vector_add" --compiler-args "--optimize 3" + +Running the cell above will compile and execute the vector addition code in the +"vector_add" group. During compilation, **nvcc** receives the "\-\-optimize" +option which specifies the optimization level for host code. + +Set default arguments +--------------------- + +In the case where you execute multiple magic commands with the same compiler or +profiler arguments you can avoid writing them every time by setting the default +arguments: + +.. code-block:: python + + from nvcc4jupyter import set_defaults + set_defaults(compiler_args="--optimize 3", profiler_args="--section SpeedOfLight") + +The same effect can be achieved by running "set_defaults" once for each config +due to the fact that the default value is not changed if an a value is not +given to the "set_defaults" function. + +.. code-block:: python + + from nvcc4jupyter import set_defaults + set_defaults(compiler_args="--optimize 3") + set_defaults(profiler_args="--section SpeedOfLight") + + +Now we can run the following cell without specifying the compiler and profiler +arguments once again. + +.. code-block:: c++ + + %cuda_group_run --group "vector_add" --profile diff --git a/nvcc4jupyter/__init__.py b/nvcc4jupyter/__init__.py index 97b8902..41d6337 100644 --- a/nvcc4jupyter/__init__.py +++ b/nvcc4jupyter/__init__.py @@ -2,6 +2,7 @@ nvcc4jupyter: CUDA C++ plugin for Jupyter Notebook """ +from .parsers import set_defaults # noqa: F401 from .plugin import NVCCPlugin, load_ipython_extension # noqa: F401 __version__ = "1.0.3" diff --git a/nvcc4jupyter/parsers.py b/nvcc4jupyter/parsers.py index 76a0392..a35e49f 100644 --- a/nvcc4jupyter/parsers.py +++ b/nvcc4jupyter/parsers.py @@ -3,6 +3,39 @@ Parsers for the CUDA magic commands. """ import argparse +from typing import Callable, Optional + +_default_profiler_args: str = "" +_default_compiler_args: str = "" + + +def set_defaults( + compiler_args: Optional[str] = None, profiler_args: Optional[str] = None +) -> None: + """ + Set the default values for various arguments of the magic commands. These + values will be used if the user does not explicitly provide those arguments + to override this behaviour on a cell by cell basis. + + Args: + compiler_args: If not None, this value becomes the new default compiler + config. Defaults to "". + profiler_args: If not None, this value becomes the new default profiler + config. Defaults to "". + """ + + # pylint: disable=global-statement + global _default_compiler_args + global _default_profiler_args + if compiler_args is not None: + _default_compiler_args = compiler_args + if profiler_args is not None: + _default_profiler_args = profiler_args + + +def str_to_lambda(arg: str) -> Callable[[], str]: + """Convert argparse string to lambda""" + return lambda: arg def get_parser_cuda() -> argparse.ArgumentParser: @@ -18,8 +51,22 @@ def get_parser_cuda() -> argparse.ArgumentParser: ) parser.add_argument("-t", "--timeit", action="store_true") parser.add_argument("-p", "--profile", action="store_true") - parser.add_argument("-a", "--profiler-args", type=str, default="") - parser.add_argument("-c", "--compiler-args", type=str, default="") + + # --profiler-args and --compiler-args values are lambda functions to allow + # changing the default value at runtime + parser.add_argument( + "-a", + "--profiler-args", + type=str_to_lambda, + default=lambda: _default_profiler_args, + ) + parser.add_argument( + "-c", + "--compiler-args", + type=str_to_lambda, + default=lambda: _default_compiler_args, + ) + return parser diff --git a/nvcc4jupyter/plugin.py b/nvcc4jupyter/plugin.py index 413f836..1da4f63 100644 --- a/nvcc4jupyter/plugin.py +++ b/nvcc4jupyter/plugin.py @@ -188,13 +188,13 @@ class NVCCPlugin(Magics): try: exec_fpath = self._compile( group_name=group_name, - compiler_args=args.compiler_args, + compiler_args=args.compiler_args(), ) output = self._run( exec_fpath=exec_fpath, timeit=args.timeit, profile=args.profile, - profiler_args=args.profiler_args, + profiler_args=args.profiler_args(), ) except subprocess.CalledProcessError as e: output = e.output.decode("utf8") diff --git a/tests/test_plugin.py b/tests/test_plugin.py index e290f91..4c6120b 100644 --- a/tests/test_plugin.py +++ b/tests/test_plugin.py @@ -8,6 +8,7 @@ from typing import List import pytest +from nvcc4jupyter.parsers import get_parser_cuda, set_defaults from nvcc4jupyter.plugin import NVCCPlugin @@ -44,9 +45,12 @@ def before_all(scripts_path: str): @pytest.fixture(autouse=True, scope="function") def before_each(plugin: NVCCPlugin): - shutil.rmtree(plugin.workdir, ignore_errors=True) # before test + # BEFORE TESTS + set_defaults(compiler_args="", profiler_args="") + shutil.rmtree(plugin.workdir, ignore_errors=True) yield - pass # after test + # AFTER TESTS + pass def test_save_source(plugin: NVCCPlugin, sample_cuda_code: str) -> None: @@ -113,8 +117,8 @@ def test_compile_args( args=argparse.Namespace( timeit=False, profile=True, - profiler_args="", - compiler_args="--std c++14", + profiler_args=lambda: "", + compiler_args=lambda: "--std c++14", ), ) assert "errors detected in the compilation of" in output @@ -143,8 +147,8 @@ def test_compile_opencv( args=argparse.Namespace( timeit=False, profile=True, - profiler_args="", - compiler_args=opencv_compile_options, + profiler_args=lambda: "", + compiler_args=lambda: opencv_compile_options, ), ) assert "General configuration for OpenCV" in output @@ -207,7 +211,10 @@ def test_compile_and_run_multiple_files( output = plugin._compile_and_run( group_name=gname, args=argparse.Namespace( - timeit=False, profile=True, profiler_args="", compiler_args="" + timeit=False, + profile=True, + profiler_args=lambda: "", + compiler_args=lambda: "", ), ) check_profiler_output(output) @@ -232,7 +239,10 @@ def test_compile_and_run_multiple_files_shared( output = plugin._compile_and_run( group_name=gname, args=argparse.Namespace( - timeit=False, profile=True, profiler_args="", compiler_args="" + timeit=False, + profile=True, + profiler_args=lambda: "", + compiler_args=lambda: "", ), ) check_profiler_output(output) @@ -249,6 +259,29 @@ def test_read_args(plugin: NVCCPlugin): assert math.isclose(args.b, 0.75) +def test_set_defaults(): + parser = get_parser_cuda() + args = parser.parse_args([]) + assert args.profiler_args() == "" + assert args.compiler_args() == "" + set_defaults(profiler_args="123") + args = parser.parse_args([]) + assert args.profiler_args() == "123" + assert args.compiler_args() == "" + set_defaults(compiler_args="456") + args = parser.parse_args([]) + assert args.profiler_args() == "123" + assert args.compiler_args() == "456" + set_defaults(profiler_args="") + args = parser.parse_args([]) + assert args.profiler_args() == "" + assert args.compiler_args() == "456" + set_defaults(profiler_args="123") + args = parser.parse_args(["--profiler-args", "789"]) + assert args.profiler_args() == "789" + assert args.compiler_args() == "456" + + def test_magic_cuda( capsys, plugin: NVCCPlugin,