mirror of
https://github.com/andreinechaev/nvcc4jupyter.git
synced 2026-06-13 18:50:47 +05:30
Feature: Passing arguments to NVCC compiler (#26)
* Add option to give nvcc extra arguments * Add test for nvcc options that changes c++ dialect from c++17 to c++14 * Add make and the english language pack to devcontainer to be able to build the documentation * Update documentation config to automatically import the current version of the package * Document new --compiler-args argument * Improve tests coverage by testing for bad arguments and the error output during a failed compilation * Add IPython to docs requirements to allow the __version__ import for readthedocs env * Change devcontainer base image to have the latest CUDA toolkit * Mock the nsight compute tool with a bash script * Add test to compile with opencv * Add new page to documentation that contains a new notebook that explains compiling with external libraries * Add autodocstring vscode extension to devcontainer * Add function that modifies the default profiler/compiler arguments to allow reusing them in multiple magic command calls * Update pylint exceptions * Update contributing instructions * Change version from 1.0.3 to 1.1.0 due to adding features in a backward-compatible manner * Install latest CUDA toolkit on the test runner to pass the OpenCV compilation test * Install opencv in test runner and update code coverage install * Add CUDA bin to PATH in test and coverage runners * Add cuda bin to path variable in .bashrc * Update way to set environment variable PATH in github action * Change devcontainer base image back to ubuntu:22.04 to match the environment from the test runner
This commit is contained in:
committed by
GitHub
parent
5cd225851b
commit
781ff5b76b
@@ -1,15 +1,29 @@
|
|||||||
FROM ubuntu
|
FROM ubuntu:22.04
|
||||||
|
|
||||||
ARG VENV_PATH=/opt/dev-venv
|
ARG VENV_PATH=/opt/dev-venv
|
||||||
ENV VENV_ACTIVATE=${VENV_PATH}/bin/activate
|
ENV VENV_ACTIVATE=${VENV_PATH}/bin/activate
|
||||||
|
ENV DEBIAN_FRONTEND="noninteractive"
|
||||||
|
|
||||||
|
# install the latest CUDA toolkit (https://developer.nvidia.com/cuda-downloads)
|
||||||
RUN apt update
|
RUN apt update
|
||||||
RUN apt install -y python3.10-venv nvidia-cuda-toolkit gcc vim git
|
RUN apt install -y wget
|
||||||
|
RUN wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-keyring_1.1-1_all.deb
|
||||||
|
RUN dpkg -i cuda-keyring_1.1-1_all.deb
|
||||||
|
RUN apt update
|
||||||
|
RUN apt -y install cuda-toolkit-12-3
|
||||||
|
RUN echo "PATH=\"\$PATH:/usr/local/cuda/bin\"" >> ~/.bashrc
|
||||||
|
|
||||||
# the mkdir command bypasses a profiler error, which allows us to run it with
|
# install OpenCV to test compilation with external libraries
|
||||||
# host code only to at least check that the profiler parameters are correctly
|
RUN apt install -y libopencv-dev pkg-config
|
||||||
# provided; without this line, some tests will fail
|
|
||||||
RUN mkdir -p /usr/lib/x86_64-linux-gnu/nsight-compute/sections
|
# make & language-pack-en are for documentation
|
||||||
|
RUN apt install -y \
|
||||||
|
gcc \
|
||||||
|
git \
|
||||||
|
language-pack-en \
|
||||||
|
make \
|
||||||
|
python3.10-venv \
|
||||||
|
vim
|
||||||
|
|
||||||
# we create the virtualenv here so that the devcontainer.json setting
|
# we create the virtualenv here so that the devcontainer.json setting
|
||||||
# python.defaultInterpreterPath can be used to find it; if we do it in the
|
# python.defaultInterpreterPath can be used to find it; if we do it in the
|
||||||
|
|||||||
@@ -16,10 +16,12 @@
|
|||||||
"ms-python.isort",
|
"ms-python.isort",
|
||||||
"ms-python.flake8",
|
"ms-python.flake8",
|
||||||
"ms-python.black-formatter",
|
"ms-python.black-formatter",
|
||||||
"ryanluker.vscode-coverage-gutters"
|
"ryanluker.vscode-coverage-gutters",
|
||||||
|
"njpwerner.autodocstring"
|
||||||
],
|
],
|
||||||
"settings": {
|
"settings": {
|
||||||
"python.defaultInterpreterPath": "/opt/dev-venv/bin/python"
|
"python.defaultInterpreterPath": "/opt/dev-venv/bin/python",
|
||||||
|
"autoDocstring.docstringFormat": "google-notypes"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,14 +27,19 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python-version }}
|
python-version: ${{ matrix.python-version }}
|
||||||
|
|
||||||
# the mkdir command bypasses a profiler error, which allows us to run it
|
- name: Install CUDA toolkit
|
||||||
# with host code only to at least check that the profiler parameters are
|
|
||||||
# correctly provided
|
|
||||||
- name: Install CUDA tools
|
|
||||||
run: |
|
run: |
|
||||||
sudo apt update
|
sudo apt update
|
||||||
sudo apt install nvidia-cuda-toolkit
|
sudo apt install -y wget
|
||||||
sudo mkdir -p /usr/lib/x86_64-linux-gnu/nsight-compute/sections
|
wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-keyring_1.1-1_all.deb
|
||||||
|
sudo dpkg -i cuda-keyring_1.1-1_all.deb
|
||||||
|
sudo apt update
|
||||||
|
sudo apt -y install cuda-toolkit-12-3
|
||||||
|
echo "PATH=$PATH:/usr/local/cuda/bin" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Install OpenCV
|
||||||
|
run: |
|
||||||
|
sudo apt install -y libopencv-dev pkg-config
|
||||||
|
|
||||||
- name: Install Python dependencies
|
- name: Install Python dependencies
|
||||||
run: |
|
run: |
|
||||||
@@ -65,11 +70,19 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
python-version: "3.10"
|
python-version: "3.10"
|
||||||
|
|
||||||
- name: Install CUDA tools
|
- name: Install CUDA toolkit
|
||||||
run: |
|
run: |
|
||||||
sudo apt update
|
sudo apt update
|
||||||
sudo apt install nvidia-cuda-toolkit
|
sudo apt install -y wget
|
||||||
sudo mkdir -p /usr/lib/x86_64-linux-gnu/nsight-compute/sections
|
wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-keyring_1.1-1_all.deb
|
||||||
|
sudo dpkg -i cuda-keyring_1.1-1_all.deb
|
||||||
|
sudo apt update
|
||||||
|
sudo apt -y install cuda-toolkit-12-3
|
||||||
|
echo "PATH=$PATH:/usr/local/cuda/bin" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Install OpenCV
|
||||||
|
run: |
|
||||||
|
sudo apt install -y libopencv-dev pkg-config
|
||||||
|
|
||||||
- name: Install Python dependencies
|
- name: Install Python dependencies
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ Here are just a few of the things that nvcc4jupyter does well:
|
|||||||
|
|
||||||
- [Easily run CUDA C++ code](https://nvcc4jupyter.readthedocs.io/en/latest/usage.html#hello-world)
|
- [Easily run CUDA C++ code](https://nvcc4jupyter.readthedocs.io/en/latest/usage.html#hello-world)
|
||||||
- [Profile your code with NVIDIA Nsight Compute](https://nvcc4jupyter.readthedocs.io/en/latest/usage.html#profiling)
|
- [Profile your code with NVIDIA Nsight Compute](https://nvcc4jupyter.readthedocs.io/en/latest/usage.html#profiling)
|
||||||
|
- [Compile your code with external libraries (e.g. OpenCV)](https://nvcc4jupyter.readthedocs.io/en/latest/notebooks.html#compiling-with-external-libraries)
|
||||||
- [Share code between different programs in the same notebook / split your code into multiple files for improved readability](https://nvcc4jupyter.readthedocs.io/en/latest/usage.html#groups)
|
- [Share code between different programs in the same notebook / split your code into multiple files for improved readability](https://nvcc4jupyter.readthedocs.io/en/latest/usage.html#groups)
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
@@ -88,13 +89,14 @@ The official documentation is hosted on [readthedocs](https://nvcc4jupyter.readt
|
|||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
Install the package with the development dependencies:
|
The recommended setup for development is using the devcontainer in GitHub
|
||||||
|
Codespaces or locally in VSCode.
|
||||||
|
|
||||||
|
If not using the devcontainer you need to install the package with the
|
||||||
|
development dependencies and install the pre-commit hook before commiting any
|
||||||
|
changes:
|
||||||
```bash
|
```bash
|
||||||
pip install .[dev]
|
pip install .[dev]
|
||||||
```
|
|
||||||
|
|
||||||
As a developer, make sure you install the pre-commit hook before commiting any changes:
|
|
||||||
```bash
|
|
||||||
pre-commit install
|
pre-commit install
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
sphinx==7.1.2
|
sphinx==7.1.2
|
||||||
sphinx-rtd-theme==1.3.0rc1
|
sphinx-rtd-theme==1.3.0rc1
|
||||||
|
IPython>=8.19.0
|
||||||
|
|||||||
+9
-2
@@ -6,11 +6,18 @@
|
|||||||
# -- Project information -----------------------------------------------------
|
# -- Project information -----------------------------------------------------
|
||||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
sys.path.append(os.path.join("..", ".."))
|
||||||
|
from nvcc4jupyter.__init__ import __version__ # noqa: E402
|
||||||
|
|
||||||
project = "nvcc4jupyter"
|
project = "nvcc4jupyter"
|
||||||
copyright = "2024, Andrei Nechaev & Cosmin Stefan Ciocan"
|
copyright = "2024, Andrei Nechaev & Cosmin Stefan Ciocan"
|
||||||
author = "Andrei Nechaev & Cosmin Stefan Ciocan"
|
author = "Andrei Nechaev & Cosmin Stefan Ciocan"
|
||||||
release = "1.0.1"
|
release = __version__
|
||||||
version = "1.0.1"
|
version = __version__
|
||||||
|
|
||||||
|
|
||||||
# -- General configuration ---------------------------------------------------
|
# -- General configuration ---------------------------------------------------
|
||||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
||||||
|
|||||||
@@ -10,4 +10,5 @@ which provides CUDA capable GPUs with the CUDA toolkit already installed.
|
|||||||
:caption: Contents:
|
:caption: Contents:
|
||||||
|
|
||||||
usage
|
usage
|
||||||
|
notebooks
|
||||||
magics
|
magics
|
||||||
|
|||||||
+21
-4
@@ -21,24 +21,40 @@ Usage
|
|||||||
- ``%%cuda``: Compile and run this cell.
|
- ``%%cuda``: Compile and run this cell.
|
||||||
- ``%%cuda -p``: Also runs the Nsight Compute profiler.
|
- ``%%cuda -p``: Also runs the Nsight Compute profiler.
|
||||||
- ``%%cuda -p -a "<SPACE SEPARATED PROFILER ARGS>"``: Also runs the Nsight Compute profiler.
|
- ``%%cuda -p -a "<SPACE SEPARATED PROFILER ARGS>"``: Also runs the Nsight Compute profiler.
|
||||||
|
- ``%%cude -c "<SPACE SEPARATED COMPILER ARGS"``: Passes additional arguments to "nvcc".
|
||||||
- ``%%cuda -t``: Outputs the "timeit" built-in magic results.
|
- ``%%cuda -t``: Outputs the "timeit" built-in magic results.
|
||||||
|
|
||||||
Options
|
Options
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
.. _timeit:
|
||||||
|
|
||||||
-t, --timeit
|
-t, --timeit
|
||||||
Boolean. If set, returns the output of the "timeit" built-in
|
Boolean. If set, returns the output of the "timeit" built-in
|
||||||
ipython magic instead of stdout.
|
ipython magic instead of stdout.
|
||||||
|
|
||||||
|
.. _profile:
|
||||||
|
|
||||||
-p, --profile
|
-p, --profile
|
||||||
Boolean. If set, runs the NVIDIA Nsight Compute profiler whose
|
Boolean. If set, runs the NVIDIA Nsight Compute profiler whose
|
||||||
output is appended to standard output.
|
output is appended to standard output.
|
||||||
|
|
||||||
|
.. _profiler_args:
|
||||||
|
|
||||||
-a, --profiler-args
|
-a, --profiler-args
|
||||||
String. Optional profiler arguments that can be space separated
|
String. Optional profiler arguments that can be space separated
|
||||||
by wrapping them in double quotes. See all options here:
|
by wrapping them in double quotes. See all options here:
|
||||||
`Nsight Compute CLI <https://docs.nvidia.com/nsight-compute/NsightComputeCli/index.html#command-line-options>`_
|
`Nsight Compute CLI <https://docs.nvidia.com/nsight-compute/NsightComputeCli/index.html#command-line-options>`_
|
||||||
|
|
||||||
|
.. _compiler_args:
|
||||||
|
|
||||||
|
-c, --compiler-args
|
||||||
|
String. Optional compiler arguments that can be space separated
|
||||||
|
by wrapping them in double quotes. They will be passed to "nvcc".
|
||||||
|
See all options here:
|
||||||
|
`NVCC Options <https://docs.nvidia.com/cuda/cuda-compiler-driver-nvcc/index.html#nvcc-command-options>`_
|
||||||
|
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
If both "\-\-profile" and "\-\-timeit" are used then no profiling is
|
If both "\-\-profile" and "\-\-timeit" are used then no profiling is
|
||||||
done.
|
done.
|
||||||
@@ -47,10 +63,11 @@ Examples
|
|||||||
--------
|
--------
|
||||||
::
|
::
|
||||||
|
|
||||||
# compile, run, and profile the code in the cell with the Nsight
|
# compile, run, and profile the code in the cell with the Nsight compute
|
||||||
# compute profiler while collecting only metrics from the
|
# profiler while collecting only metrics from the "MemoryWorkloadAnalysis"
|
||||||
# "MemoryWorkloadAnalysis" section.
|
# section; also provides the "--optimize 3" option to "nvcc" during
|
||||||
%%cuda --profile --profiler-args "--section MemoryWorkloadAnalysis"
|
# compilation to optimize host code
|
||||||
|
%%cuda -p -a "--section MemoryWorkloadAnalysis" -c "--optimize 3"
|
||||||
|
|
||||||
------
|
------
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
*********
|
||||||
|
Notebooks
|
||||||
|
*********
|
||||||
|
|
||||||
|
This page provides a list of useful Jupyter notebooks written with the
|
||||||
|
**nvcc4jupyter** library.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
These notebooks are written for Google's Colab, but you may run them in
|
||||||
|
other environments by installing all expected dependencies. If running in
|
||||||
|
Colab, make sure to set the runtime type to a GPU instance (at the time of
|
||||||
|
writing this, T4 is the GPU offered for free by Colab).
|
||||||
|
|
||||||
|
------
|
||||||
|
|
||||||
|
.. _compiling_with_external_libraries:
|
||||||
|
|
||||||
|
Compiling with external libraries
|
||||||
|
=================================
|
||||||
|
|
||||||
|
[`NOTEBOOK <https://colab.research.google.com/drive/1iuY46DCwv4hy3SqDhJgFeO8kgpHnzjTh?usp=sharing>`_]
|
||||||
|
|
||||||
|
If you need to compile CUDA C++ code that uses external libraries in the host
|
||||||
|
code (e.g. OpenCV for reading and writing images to disk) then this section is
|
||||||
|
for you.
|
||||||
|
|
||||||
|
To achieve this, use the :ref:`compiler-args <compiler_args>` option of the
|
||||||
|
:ref:`cuda <cuda_magic>` magic command to pass the correct compiler options
|
||||||
|
of the OpenCV library to **nvcc** for it to link the OpenCV code with the
|
||||||
|
code in your Jupyter cell. Those compiler options can be provided by the
|
||||||
|
`pkg-config <https://www.freedesktop.org/wiki/Software/pkg-config/>`_ tool.
|
||||||
|
|
||||||
|
In the notebook we show how to use OpenCV to load an image, blur it with a CUDA
|
||||||
|
kernel, and then save it back to disk using OpenCV again.
|
||||||
@@ -255,3 +255,47 @@ Running the cell above will compile and execute the vector addition code in the
|
|||||||
SM Active Cycles cycle 383.65
|
SM Active Cycles cycle 383.65
|
||||||
Compute (SM) Throughput % 1.19
|
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
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
nvcc4jupyter: CUDA C++ plugin for Jupyter Notebook
|
nvcc4jupyter: CUDA C++ plugin for Jupyter Notebook
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from .parsers import set_defaults # noqa: F401
|
||||||
from .plugin import NVCCPlugin, load_ipython_extension # noqa: F401
|
from .plugin import NVCCPlugin, load_ipython_extension # noqa: F401
|
||||||
|
|
||||||
__version__ = "1.0.3"
|
__version__ = "1.1.0"
|
||||||
|
|||||||
+49
-1
@@ -3,6 +3,39 @@ Parsers for the CUDA magic commands.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import argparse
|
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:
|
def get_parser_cuda() -> argparse.ArgumentParser:
|
||||||
@@ -18,7 +51,22 @@ def get_parser_cuda() -> argparse.ArgumentParser:
|
|||||||
)
|
)
|
||||||
parser.add_argument("-t", "--timeit", action="store_true")
|
parser.add_argument("-t", "--timeit", action="store_true")
|
||||||
parser.add_argument("-p", "--profile", action="store_true")
|
parser.add_argument("-p", "--profile", action="store_true")
|
||||||
parser.add_argument("-a", "--profiler-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
|
return parser
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+15
-14
@@ -87,7 +87,10 @@ class NVCCPlugin(Magics):
|
|||||||
shutil.rmtree(group_dirpath)
|
shutil.rmtree(group_dirpath)
|
||||||
|
|
||||||
def _compile(
|
def _compile(
|
||||||
self, group_name: str, executable_fname: str = DEFAULT_EXEC_FNAME
|
self,
|
||||||
|
group_name: str,
|
||||||
|
executable_fname: str = DEFAULT_EXEC_FNAME,
|
||||||
|
compiler_args: str = "",
|
||||||
) -> str:
|
) -> str:
|
||||||
"""
|
"""
|
||||||
Compiles all source files in a given group together with all source
|
Compiles all source files in a given group together with all source
|
||||||
@@ -97,6 +100,7 @@ class NVCCPlugin(Magics):
|
|||||||
group_name: The name of the source file group to be compiled.
|
group_name: The name of the source file group to be compiled.
|
||||||
executable_fname: The output executable file name. Defaults to
|
executable_fname: The output executable file name. Defaults to
|
||||||
"cuda_exec.out".
|
"cuda_exec.out".
|
||||||
|
compiler_args: The optional "nvcc" compiler arguments.
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
RuntimeError: If the group does not exist or if does not have any
|
RuntimeError: If the group does not exist or if does not have any
|
||||||
@@ -121,18 +125,12 @@ class NVCCPlugin(Magics):
|
|||||||
|
|
||||||
executable_fpath = os.path.join(group_dirpath, executable_fname)
|
executable_fpath = os.path.join(group_dirpath, executable_fname)
|
||||||
|
|
||||||
args = [
|
args = ["nvcc"]
|
||||||
"nvcc",
|
args.extend(compiler_args.split())
|
||||||
"-I" + shared_dirpath + "," + group_dirpath,
|
args.append("-I" + shared_dirpath + "," + group_dirpath)
|
||||||
]
|
|
||||||
args.extend(source_files)
|
args.extend(source_files)
|
||||||
args.extend(
|
args.extend(["-o", executable_fpath, "-Wno-deprecated-gpu-targets"])
|
||||||
[
|
|
||||||
"-o",
|
|
||||||
executable_fpath,
|
|
||||||
"-Wno-deprecated-gpu-targets",
|
|
||||||
]
|
|
||||||
)
|
|
||||||
subprocess.check_output(args, stderr=subprocess.STDOUT)
|
subprocess.check_output(args, stderr=subprocess.STDOUT)
|
||||||
|
|
||||||
return executable_fpath
|
return executable_fpath
|
||||||
@@ -188,12 +186,15 @@ class NVCCPlugin(Magics):
|
|||||||
self, group_name: str, args: argparse.Namespace
|
self, group_name: str, args: argparse.Namespace
|
||||||
) -> str:
|
) -> str:
|
||||||
try:
|
try:
|
||||||
exec_fpath = self._compile(group_name)
|
exec_fpath = self._compile(
|
||||||
|
group_name=group_name,
|
||||||
|
compiler_args=args.compiler_args(),
|
||||||
|
)
|
||||||
output = self._run(
|
output = self._run(
|
||||||
exec_fpath=exec_fpath,
|
exec_fpath=exec_fpath,
|
||||||
timeit=args.timeit,
|
timeit=args.timeit,
|
||||||
profile=args.profile,
|
profile=args.profile,
|
||||||
profiler_args=args.profiler_args,
|
profiler_args=args.profiler_args(),
|
||||||
)
|
)
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
output = e.output.decode("utf8")
|
output = e.output.decode("utf8")
|
||||||
|
|||||||
+2
-2
@@ -286,6 +286,6 @@ deprecated-modules="optparse,tkinter.tix"
|
|||||||
|
|
||||||
[tool.pylint.'EXCEPTIONS']
|
[tool.pylint.'EXCEPTIONS']
|
||||||
overgeneral-exceptions= [
|
overgeneral-exceptions= [
|
||||||
"BaseException",
|
"builtins.BaseException",
|
||||||
"Exception"
|
"builtins.Exception"
|
||||||
]
|
]
|
||||||
|
|||||||
Vendored
+47
@@ -0,0 +1,47 @@
|
|||||||
|
#include <cstdlib>
|
||||||
|
#include <iostream>
|
||||||
|
#include <set>
|
||||||
|
#include <string>
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
struct S {
|
||||||
|
int n;
|
||||||
|
std::string s;
|
||||||
|
float d;
|
||||||
|
bool operator<(const S& rhs) const
|
||||||
|
{
|
||||||
|
// compares n to rhs.n,
|
||||||
|
// then s to rhs.s,
|
||||||
|
// then d to rhs.d
|
||||||
|
return std::tie(n, s, d) < std::tie(rhs.n, rhs.s, rhs.d);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
std::set<S> mySet;
|
||||||
|
|
||||||
|
// pre C++17:
|
||||||
|
{
|
||||||
|
S value{42, "Test", 3.14};
|
||||||
|
std::set<S>::iterator iter;
|
||||||
|
bool inserted;
|
||||||
|
|
||||||
|
// unpacks the return val of insert into iter and inserted
|
||||||
|
std::tie(iter, inserted) = mySet.insert(value);
|
||||||
|
|
||||||
|
if (inserted)
|
||||||
|
std::cout << "Value was inserted\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// with C++17:
|
||||||
|
{
|
||||||
|
S value{100, "abc", 100.0};
|
||||||
|
const auto [iter, inserted] = mySet.insert(value);
|
||||||
|
|
||||||
|
if (inserted)
|
||||||
|
std::cout << "Value(" << iter->n << ", " << iter->s << ", ...) was inserted" << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
+8
@@ -0,0 +1,8 @@
|
|||||||
|
#include <opencv2/core.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
std::cout << cv::getBuildInformation() << std::endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Vendored
+16
-1
@@ -27,10 +27,25 @@ def fixtures_path(tests_path):
|
|||||||
return os.path.join(tests_path, "fixtures")
|
return os.path.join(tests_path, "fixtures")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="session")
|
||||||
|
def scripts_path(fixtures_path: str):
|
||||||
|
return os.path.join(fixtures_path, "scripts")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="session")
|
||||||
|
def compiler_cpp_17_fpath(fixtures_path: str):
|
||||||
|
return os.path.join(fixtures_path, "compiler", "cpp_17.cu")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="session")
|
||||||
|
def compiler_opencv_fpath(fixtures_path: str):
|
||||||
|
return os.path.join(fixtures_path, "compiler", "opencv.cu")
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="session")
|
@pytest.fixture(scope="session")
|
||||||
def sample_magic_cu_line():
|
def sample_magic_cu_line():
|
||||||
# fmt: off
|
# fmt: off
|
||||||
return '--profile --profiler-args "--metrics l1tex__t_sectors_pipe_lsu_mem_global_op_ld.sum"' # noqa: E501
|
return '--profile --profiler-args "--metrics l1tex__t_sectors_pipe_lsu_mem_global_op_ld.sum" --compiler-args "--optimize 3"' # noqa: E501
|
||||||
# fmt: on
|
# fmt: on
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# this is a mock of nsight compute cli tool that just executes the program
|
||||||
|
# given as the last argument
|
||||||
|
"${@: -1}"
|
||||||
|
|
||||||
|
echo "==WARNING== No kernels were profiled"
|
||||||
+115
-4
@@ -3,10 +3,12 @@ import math
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
|
import subprocess
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from nvcc4jupyter.parsers import get_parser_cuda, set_defaults
|
||||||
from nvcc4jupyter.plugin import NVCCPlugin
|
from nvcc4jupyter.plugin import NVCCPlugin
|
||||||
|
|
||||||
|
|
||||||
@@ -36,11 +38,19 @@ def copy_source_to_group(
|
|||||||
return destination_fpath
|
return destination_fpath
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True, scope="session")
|
||||||
|
def before_all(scripts_path: str):
|
||||||
|
os.environ["PATH"] = scripts_path + os.pathsep + os.environ["PATH"]
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(autouse=True, scope="function")
|
@pytest.fixture(autouse=True, scope="function")
|
||||||
def before_each(plugin: NVCCPlugin):
|
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
|
yield
|
||||||
pass # after test
|
# AFTER TESTS
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def test_save_source(plugin: NVCCPlugin, sample_cuda_code: str) -> None:
|
def test_save_source(plugin: NVCCPlugin, sample_cuda_code: str) -> None:
|
||||||
@@ -88,6 +98,62 @@ def test_compile(
|
|||||||
plugin._compile(gname)
|
plugin._compile(gname)
|
||||||
|
|
||||||
|
|
||||||
|
def test_compile_args(
|
||||||
|
plugin: NVCCPlugin,
|
||||||
|
compiler_cpp_17_fpath: str,
|
||||||
|
):
|
||||||
|
gname = "test_compile_args"
|
||||||
|
copy_source_to_group(compiler_cpp_17_fpath, gname, plugin.workdir)
|
||||||
|
|
||||||
|
exec_fpath = plugin._compile(gname, compiler_args="--std c++17")
|
||||||
|
assert os.path.exists(exec_fpath)
|
||||||
|
|
||||||
|
# should fail due to the source file having c++ 17 features
|
||||||
|
with pytest.raises(subprocess.CalledProcessError):
|
||||||
|
exec_fpath = plugin._compile(gname, compiler_args="--std c++14")
|
||||||
|
|
||||||
|
output = plugin._compile_and_run(
|
||||||
|
group_name=gname,
|
||||||
|
args=argparse.Namespace(
|
||||||
|
timeit=False,
|
||||||
|
profile=True,
|
||||||
|
profiler_args=lambda: "",
|
||||||
|
compiler_args=lambda: "--std c++14",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
assert "errors detected in the compilation of" in output
|
||||||
|
|
||||||
|
|
||||||
|
def test_compile_opencv(
|
||||||
|
plugin: NVCCPlugin,
|
||||||
|
compiler_opencv_fpath: str,
|
||||||
|
):
|
||||||
|
gname = "test_compile_opencv"
|
||||||
|
copy_source_to_group(compiler_opencv_fpath, gname, plugin.workdir)
|
||||||
|
|
||||||
|
# check that "pkg-config" exists
|
||||||
|
assert subprocess.check_call(["which", "pkg-config"]) == 0
|
||||||
|
|
||||||
|
opencv_compile_options = (
|
||||||
|
subprocess.check_output(
|
||||||
|
args=["pkg-config", "--cflags", "--libs", "opencv4"]
|
||||||
|
)
|
||||||
|
.decode()
|
||||||
|
.strip()
|
||||||
|
)
|
||||||
|
|
||||||
|
output = plugin._compile_and_run(
|
||||||
|
group_name=gname,
|
||||||
|
args=argparse.Namespace(
|
||||||
|
timeit=False,
|
||||||
|
profile=True,
|
||||||
|
profiler_args=lambda: "",
|
||||||
|
compiler_args=lambda: opencv_compile_options,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
assert "General configuration for OpenCV" in output
|
||||||
|
|
||||||
|
|
||||||
def test_run(
|
def test_run(
|
||||||
plugin: NVCCPlugin,
|
plugin: NVCCPlugin,
|
||||||
sample_cuda_fpath: str,
|
sample_cuda_fpath: str,
|
||||||
@@ -143,7 +209,13 @@ def test_compile_and_run_multiple_files(
|
|||||||
for fpath in multiple_source_fpaths:
|
for fpath in multiple_source_fpaths:
|
||||||
copy_source_to_group(fpath, gname, plugin.workdir)
|
copy_source_to_group(fpath, gname, plugin.workdir)
|
||||||
output = plugin._compile_and_run(
|
output = plugin._compile_and_run(
|
||||||
gname, argparse.Namespace(timeit=False, profile=True, profiler_args="")
|
group_name=gname,
|
||||||
|
args=argparse.Namespace(
|
||||||
|
timeit=False,
|
||||||
|
profile=True,
|
||||||
|
profiler_args=lambda: "",
|
||||||
|
compiler_args=lambda: "",
|
||||||
|
),
|
||||||
)
|
)
|
||||||
check_profiler_output(output)
|
check_profiler_output(output)
|
||||||
|
|
||||||
@@ -165,7 +237,13 @@ def test_compile_and_run_multiple_files_shared(
|
|||||||
else:
|
else:
|
||||||
copy_source_to_group(fpath, "shared", plugin.workdir)
|
copy_source_to_group(fpath, "shared", plugin.workdir)
|
||||||
output = plugin._compile_and_run(
|
output = plugin._compile_and_run(
|
||||||
gname, argparse.Namespace(timeit=False, profile=True, profiler_args="")
|
group_name=gname,
|
||||||
|
args=argparse.Namespace(
|
||||||
|
timeit=False,
|
||||||
|
profile=True,
|
||||||
|
profiler_args=lambda: "",
|
||||||
|
compiler_args=lambda: "",
|
||||||
|
),
|
||||||
)
|
)
|
||||||
check_profiler_output(output)
|
check_profiler_output(output)
|
||||||
|
|
||||||
@@ -181,6 +259,29 @@ def test_read_args(plugin: NVCCPlugin):
|
|||||||
assert math.isclose(args.b, 0.75)
|
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(
|
def test_magic_cuda(
|
||||||
capsys,
|
capsys,
|
||||||
plugin: NVCCPlugin,
|
plugin: NVCCPlugin,
|
||||||
@@ -191,6 +292,16 @@ def test_magic_cuda(
|
|||||||
check_profiler_output(capsys.readouterr().out)
|
check_profiler_output(capsys.readouterr().out)
|
||||||
|
|
||||||
|
|
||||||
|
def test_magic_cuda_bad_args(
|
||||||
|
capsys,
|
||||||
|
plugin: NVCCPlugin,
|
||||||
|
sample_cuda_code: str,
|
||||||
|
):
|
||||||
|
plugin.cuda("--this-is-an-unrecognized-argument", sample_cuda_code)
|
||||||
|
output = capsys.readouterr().out
|
||||||
|
assert output.startswith("usage: ")
|
||||||
|
|
||||||
|
|
||||||
def test_magic_cuda_group_save(plugin: NVCCPlugin, sample_cuda_code: str):
|
def test_magic_cuda_group_save(plugin: NVCCPlugin, sample_cuda_code: str):
|
||||||
gname = "test_save_source"
|
gname = "test_save_source"
|
||||||
sname = "sample.cu"
|
sname = "sample.cu"
|
||||||
|
|||||||
Reference in New Issue
Block a user