mirror of
https://github.com/andreinechaev/nvcc4jupyter.git
synced 2026-06-15 19:50:50 +05:30
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5741c52254 | |||
| 4664a4ef47 | |||
| 0bddf6a6e6 | |||
| 781ff5b76b | |||
| 5cd225851b |
@@ -1,15 +1,29 @@
|
||||
FROM ubuntu
|
||||
FROM ubuntu:22.04
|
||||
|
||||
ARG VENV_PATH=/opt/dev-venv
|
||||
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 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
|
||||
# host code only to at least check that the profiler parameters are correctly
|
||||
# provided; without this line, some tests will fail
|
||||
RUN mkdir -p /usr/lib/x86_64-linux-gnu/nsight-compute/sections
|
||||
# install OpenCV to test compilation with external libraries
|
||||
RUN apt install -y libopencv-dev pkg-config
|
||||
|
||||
# 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
|
||||
# python.defaultInterpreterPath can be used to find it; if we do it in the
|
||||
|
||||
@@ -16,10 +16,12 @@
|
||||
"ms-python.isort",
|
||||
"ms-python.flake8",
|
||||
"ms-python.black-formatter",
|
||||
"ryanluker.vscode-coverage-gutters"
|
||||
"ryanluker.vscode-coverage-gutters",
|
||||
"njpwerner.autodocstring"
|
||||
],
|
||||
"settings": {
|
||||
"python.defaultInterpreterPath": "/opt/dev-venv/bin/python"
|
||||
"python.defaultInterpreterPath": "/opt/dev-venv/bin/python",
|
||||
"autoDocstring.docstringFormat": "google-notypes"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
# install developer dependencies
|
||||
pip install .[dev]
|
||||
pip install -e .[dev]
|
||||
|
||||
# make sure the developer uses pre-commit hooks
|
||||
pre-commit install
|
||||
|
||||
@@ -27,14 +27,19 @@ jobs:
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
# the mkdir command bypasses a profiler error, which allows us to run it
|
||||
# with host code only to at least check that the profiler parameters are
|
||||
# correctly provided
|
||||
- name: Install CUDA tools
|
||||
- name: Install CUDA toolkit
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install nvidia-cuda-toolkit
|
||||
sudo mkdir -p /usr/lib/x86_64-linux-gnu/nsight-compute/sections
|
||||
sudo apt install -y wget
|
||||
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
|
||||
run: |
|
||||
@@ -65,11 +70,19 @@ jobs:
|
||||
with:
|
||||
python-version: "3.10"
|
||||
|
||||
- name: Install CUDA tools
|
||||
- name: Install CUDA toolkit
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install nvidia-cuda-toolkit
|
||||
sudo mkdir -p /usr/lib/x86_64-linux-gnu/nsight-compute/sections
|
||||
sudo apt install -y wget
|
||||
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
|
||||
run: |
|
||||
|
||||
@@ -28,9 +28,6 @@ pip-delete-this-directory.txt
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
|
||||
# Virtual Environment
|
||||
*env*
|
||||
|
||||
# Misc
|
||||
.pytest_cache/
|
||||
.DS_Store
|
||||
|
||||
@@ -45,7 +45,8 @@ to own a GPU yourself.
|
||||
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)
|
||||
- [Profile your code with NVIDIA Nsight Compute](https://nvcc4jupyter.readthedocs.io/en/latest/usage.html#profiling)
|
||||
- [Profile your code with NVIDIA Nsight Compute or Nsight Systems](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)
|
||||
|
||||
## Install
|
||||
@@ -88,13 +89,14 @@ The official documentation is hosted on [readthedocs](https://nvcc4jupyter.readt
|
||||
|
||||
## Contributing
|
||||
|
||||
Install the package with the development dependencies:
|
||||
```bash
|
||||
pip install .[dev]
|
||||
```
|
||||
The recommended setup for development is using the devcontainer in GitHub
|
||||
Codespaces or locally in VSCode.
|
||||
|
||||
As a developer, make sure you install the pre-commit hook before commiting any changes:
|
||||
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
|
||||
pip install -e .[dev]
|
||||
pre-commit install
|
||||
```
|
||||
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
sphinx==7.1.2
|
||||
sphinx-rtd-theme==1.3.0rc1
|
||||
IPython>=8.19.0
|
||||
|
||||
+9
-2
@@ -6,11 +6,18 @@
|
||||
# -- 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"
|
||||
copyright = "2024, Andrei Nechaev & Cosmin Stefan Ciocan"
|
||||
author = "Andrei Nechaev & Cosmin Stefan Ciocan"
|
||||
release = "1.0.1"
|
||||
version = "1.0.1"
|
||||
release = __version__
|
||||
version = __version__
|
||||
|
||||
|
||||
# -- 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:
|
||||
|
||||
usage
|
||||
notebooks
|
||||
magics
|
||||
|
||||
+45
-8
@@ -21,23 +21,59 @@ Usage
|
||||
- ``%%cuda``: Compile and run this cell.
|
||||
- ``%%cuda -p``: Also runs the Nsight Compute profiler.
|
||||
- ``%%cuda -p -a "<SPACE SEPARATED PROFILER ARGS>"``: Also runs the Nsight Compute profiler.
|
||||
- ``%%cuda -c "<SPACE SEPARATED COMPILER ARGS"``: Passes additional arguments to "nvcc".
|
||||
- ``%%cuda -t``: Outputs the "timeit" built-in magic results.
|
||||
|
||||
Options
|
||||
-------
|
||||
|
||||
.. _timeit:
|
||||
|
||||
-t, --timeit
|
||||
Boolean. If set, returns the output of the "timeit" built-in
|
||||
ipython magic instead of stdout.
|
||||
|
||||
.. _profile:
|
||||
|
||||
-p, --profile
|
||||
Boolean. If set, runs the NVIDIA Nsight Compute profiler whose
|
||||
output is appended to standard output.
|
||||
Boolean. If set, runs the NVIDIA Nsight Compute (or NVIDIA Nsight Systems
|
||||
if changed via the \-\-profiler option) profiler whose output is appended to
|
||||
standard output.
|
||||
|
||||
.. _profiler:
|
||||
|
||||
-l, --profiler
|
||||
String. Can either be "ncu" (the default) to use NVIDIA Nsight Compute
|
||||
profiling tool, or "nsys" to use NVIDIA Nsight Systems profiling tool.
|
||||
|
||||
.. _profiler_args:
|
||||
|
||||
.. _profiler_args:
|
||||
|
||||
-a, --profiler-args
|
||||
String. Optional profiler arguments that can be space separated
|
||||
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>`_
|
||||
by wrapping them in double quotes. Will be passed to the profiler selected
|
||||
by the \-\-profiler option.. See profiler options here:
|
||||
`Nsight Compute <https://docs.nvidia.com/nsight-compute/NsightComputeCli/index.html#command-line-options>`_
|
||||
or `Nsight Systems <https://docs.nvidia.com/nsight-systems/UserGuide/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>`_
|
||||
|
||||
|
||||
.. _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::
|
||||
If both "\-\-profile" and "\-\-timeit" are used then no profiling is
|
||||
@@ -47,10 +83,11 @@ Examples
|
||||
--------
|
||||
::
|
||||
|
||||
# compile, run, and profile the code in the cell with the Nsight
|
||||
# compute profiler while collecting only metrics from the
|
||||
# "MemoryWorkloadAnalysis" section.
|
||||
%%cuda --profile --profiler-args "--section MemoryWorkloadAnalysis"
|
||||
# compile, run, and profile the code in the cell with the Nsight compute
|
||||
# profiler while collecting only metrics from the "MemoryWorkloadAnalysis"
|
||||
# section; also provides the "--optimize 3" option to "nvcc" during
|
||||
# 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.
|
||||
+69
-3
@@ -225,10 +225,11 @@ Profiling
|
||||
---------
|
||||
|
||||
Another important feature of nvcc4jupyter is its integration with the NVIDIA
|
||||
Nsight Compute profiler, which you need to make sure is installed and its
|
||||
executable can be found in a directory in your PATH environment variable.
|
||||
Nsight Compute / NVIDIA Nsight Systems profilers, which you need to make sure
|
||||
are installed and the executables can be found in a directory in your PATH
|
||||
environment variable.
|
||||
|
||||
In order to use it and provide the profiler with custom arguments, simply run:
|
||||
To profile using Nsight Compute with custom arguments:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
@@ -255,3 +256,68 @@ 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
|
||||
----------------------- ------------- ------------
|
||||
|
||||
To profile using Nsight Systems with custom arguments:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
%cuda_group_run --group "vector_add" --profiler nsys --profile --profiler-args "profile --stats=true"
|
||||
|
||||
Running the cell above will compile and execute the vector addition code in the
|
||||
"vector_add" group and profile it with Nsight Systems. The output will contain
|
||||
multiple tables, one of which will look similar to this:
|
||||
|
||||
.. code-block::
|
||||
|
||||
[5/8] Executing 'cuda_api_sum' stats report
|
||||
|
||||
Time (%) Total Time (ns) Num Calls Avg (ns) Med (ns) Min (ns) Max (ns) StdDev (ns) Name
|
||||
-------- --------------- --------- ------------- ------------- ----------- ----------- ----------- ----------------------
|
||||
77.3 200,844,276 1 200,844,276.0 200,844,276.0 200,844,276 200,844,276 0.0 cudaMalloc
|
||||
22.6 58,594,762 2 29,297,381.0 29,297,381.0 29,153,999 29,440,763 202,772.8 cudaMemcpy
|
||||
0.1 305,450 1 305,450.0 305,450.0 305,450 305,450 0.0 cudaLaunchKernel
|
||||
0.0 1,970 1 1,970.0 1,970.0 1,970 1,970 0.0 cuModuleGetLoadingMode
|
||||
|
||||
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
|
||||
"""
|
||||
|
||||
from .parsers import Profiler, set_defaults # noqa: F401
|
||||
from .plugin import NVCCPlugin, load_ipython_extension # noqa: F401
|
||||
|
||||
__version__ = "1.0.3"
|
||||
__version__ = "1.2.1"
|
||||
|
||||
+79
-1
@@ -3,6 +3,63 @@ Parsers for the CUDA magic commands.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
from enum import Enum
|
||||
from typing import Callable, Optional, Type, TypeVar
|
||||
|
||||
|
||||
class Profiler(Enum):
|
||||
"""Choice between Nsight Compute and Nsight Systems profilers."""
|
||||
|
||||
NCU = "ncu"
|
||||
NSYS = "nsys"
|
||||
|
||||
|
||||
_default_profiler: Profiler = Profiler.NCU
|
||||
_default_profiler_args: str = ""
|
||||
_default_compiler_args: str = ""
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
def set_defaults(
|
||||
profiler: Optional[Profiler] = None,
|
||||
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:
|
||||
profiler: If not None, this value becomes the new default profiler.
|
||||
Defaults to None.
|
||||
compiler_args: If not None, this value becomes the new default compiler
|
||||
config. Defaults to None.
|
||||
profiler_args: If not None, this value becomes the new default profiler
|
||||
config. Defaults to None.
|
||||
"""
|
||||
|
||||
# pylint: disable=global-statement
|
||||
global _default_profiler
|
||||
if profiler is not None:
|
||||
_default_profiler = profiler
|
||||
global _default_compiler_args
|
||||
if compiler_args is not None:
|
||||
_default_compiler_args = compiler_args
|
||||
global _default_profiler_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 class_to_lambda(arg: str, cls: Type[T]) -> Callable[[], T]:
|
||||
"""Convert string value to class and then to lambda"""
|
||||
return lambda: cls(arg)
|
||||
|
||||
|
||||
def get_parser_cuda() -> argparse.ArgumentParser:
|
||||
@@ -18,7 +75,28 @@ 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="")
|
||||
|
||||
# the type of the following arguments is a lambda lambda function to allow
|
||||
# changing the default value at runtime
|
||||
parser.add_argument(
|
||||
"-l",
|
||||
"--profiler",
|
||||
type=lambda arg: class_to_lambda(arg, cls=Profiler),
|
||||
default=lambda: _default_profiler,
|
||||
)
|
||||
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
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
"""
|
||||
Helper functions relating to file paths.
|
||||
"""
|
||||
|
||||
import os
|
||||
from glob import glob
|
||||
from typing import List, Optional
|
||||
|
||||
CUDA_SEARCH_PATHS: List[str] = [
|
||||
"/opt/nvidia/nsight-compute",
|
||||
"/usr/local/cuda",
|
||||
"/opt",
|
||||
"/usr",
|
||||
]
|
||||
|
||||
|
||||
def is_executable(fpath: str) -> bool:
|
||||
"""Check if file exists and is executable"""
|
||||
return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
|
||||
|
||||
|
||||
def which(name: str) -> Optional[str]:
|
||||
"""Find an executable by name by searching the PATH directories"""
|
||||
for path_dir in os.environ.get("PATH", "").split(os.pathsep):
|
||||
exec_path = os.path.join(path_dir, name)
|
||||
if is_executable(exec_path):
|
||||
return exec_path
|
||||
return None
|
||||
|
||||
|
||||
def find_executable(
|
||||
name: str, search_paths: Optional[List[str]] = None
|
||||
) -> Optional[str]:
|
||||
"""
|
||||
Find an executable, either by searching in the directories of the PATH
|
||||
environment variable or, if that did not work, by searching recursively
|
||||
in directories a list given as parameter.
|
||||
|
||||
Args:
|
||||
name: The name of the executable to be found.
|
||||
search_paths: If None, only executables that are available from PATH
|
||||
will be found. Otherwise, will recursively search these
|
||||
directories. Defaults to None.
|
||||
|
||||
Returns:
|
||||
The path to the executable if it is found, and None otherwise.
|
||||
"""
|
||||
if search_paths is None:
|
||||
search_paths = []
|
||||
|
||||
which_path = which(name)
|
||||
if which_path is not None:
|
||||
return which_path
|
||||
|
||||
for search_path in search_paths:
|
||||
search_path = os.path.abspath(search_path)
|
||||
search_path = os.path.join(search_path, f"**/{name}")
|
||||
for exec_path in glob(search_path, recursive=True):
|
||||
return exec_path
|
||||
|
||||
return None
|
||||
+73
-24
@@ -9,13 +9,21 @@ import shutil
|
||||
import subprocess
|
||||
import tempfile
|
||||
import uuid
|
||||
from typing import List, Optional
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
# pylint: disable=import-error
|
||||
from IPython.core.interactiveshell import InteractiveShell
|
||||
from IPython.core.magic import Magics, cell_magic, line_magic, magics_class
|
||||
|
||||
from . import parsers
|
||||
from .parsers import (
|
||||
Profiler,
|
||||
get_parser_cuda,
|
||||
get_parser_cuda_group_delete,
|
||||
get_parser_cuda_group_run,
|
||||
get_parser_cuda_group_save,
|
||||
)
|
||||
from .path_utils import CUDA_SEARCH_PATHS, find_executable
|
||||
from .setup_env import setup_environment
|
||||
|
||||
DEFAULT_EXEC_FNAME = "cuda_exec.out"
|
||||
SHARED_GROUP_NAME = "shared"
|
||||
@@ -37,14 +45,19 @@ class NVCCPlugin(Magics):
|
||||
super().__init__(shell)
|
||||
self.shell: InteractiveShell # type hint not provided by parent class
|
||||
|
||||
self.parser_cuda = parsers.get_parser_cuda()
|
||||
self.parser_cuda_group_save = parsers.get_parser_cuda_group_save()
|
||||
self.parser_cuda_group_delete = parsers.get_parser_cuda_group_delete()
|
||||
self.parser_cuda_group_run = parsers.get_parser_cuda_group_run()
|
||||
self.parser_cuda = get_parser_cuda()
|
||||
self.parser_cuda_group_save = get_parser_cuda_group_save()
|
||||
self.parser_cuda_group_delete = get_parser_cuda_group_delete()
|
||||
self.parser_cuda_group_run = get_parser_cuda_group_run()
|
||||
|
||||
self.workdir = tempfile.mkdtemp()
|
||||
print(f'Source files will be saved in "{self.workdir}".')
|
||||
|
||||
self.profiler_paths: Dict[Profiler, Optional[str]] = {
|
||||
Profiler.NCU: None,
|
||||
Profiler.NSYS: None,
|
||||
}
|
||||
|
||||
def _save_source(
|
||||
self, source_name: str, source_code: str, group_name: str
|
||||
) -> None:
|
||||
@@ -87,7 +100,10 @@ class NVCCPlugin(Magics):
|
||||
shutil.rmtree(group_dirpath)
|
||||
|
||||
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:
|
||||
"""
|
||||
Compiles all source files in a given group together with all source
|
||||
@@ -97,6 +113,7 @@ class NVCCPlugin(Magics):
|
||||
group_name: The name of the source file group to be compiled.
|
||||
executable_fname: The output executable file name. Defaults to
|
||||
"cuda_exec.out".
|
||||
compiler_args: The optional "nvcc" compiler arguments.
|
||||
|
||||
Raises:
|
||||
RuntimeError: If the group does not exist or if does not have any
|
||||
@@ -121,27 +138,52 @@ class NVCCPlugin(Magics):
|
||||
|
||||
executable_fpath = os.path.join(group_dirpath, executable_fname)
|
||||
|
||||
args = [
|
||||
"nvcc",
|
||||
"-I" + shared_dirpath + "," + group_dirpath,
|
||||
]
|
||||
args = ["nvcc"]
|
||||
args.extend(compiler_args.split())
|
||||
args.append("-I" + shared_dirpath + "," + group_dirpath)
|
||||
args.extend(source_files)
|
||||
args.extend(
|
||||
[
|
||||
"-o",
|
||||
executable_fpath,
|
||||
"-Wno-deprecated-gpu-targets",
|
||||
]
|
||||
)
|
||||
args.extend(["-o", executable_fpath, "-Wno-deprecated-gpu-targets"])
|
||||
|
||||
subprocess.check_output(args, stderr=subprocess.STDOUT)
|
||||
|
||||
return executable_fpath
|
||||
|
||||
def _run(
|
||||
def _get_profiler_path(self, profiler: Profiler) -> str:
|
||||
"""
|
||||
Get the path of the executable of a given profiling tool. Searches
|
||||
the directories of the PATH environment variable and some extra
|
||||
directories where CUDA is usually installed.
|
||||
|
||||
Args:
|
||||
profiler: The profiler whose executable should be found.
|
||||
|
||||
Raises:
|
||||
RuntimeError: If the profiler executable could not be found.
|
||||
|
||||
Returns:
|
||||
The file path of the executable.
|
||||
"""
|
||||
profiler_path = self.profiler_paths[profiler]
|
||||
if profiler_path is not None:
|
||||
return profiler_path
|
||||
|
||||
profiler_path = find_executable(profiler.value, CUDA_SEARCH_PATHS)
|
||||
if profiler_path is None:
|
||||
raise RuntimeError(
|
||||
f'Could not find the "{profiler.value}" profiling tool.'
|
||||
" Consider searching for where it is installed and adding its"
|
||||
" directory to the PATH environment variable."
|
||||
)
|
||||
|
||||
self.profiler_paths[profiler] = profiler_path
|
||||
return profiler_path
|
||||
|
||||
def _run( # pylint: disable=too-many-arguments
|
||||
self,
|
||||
exec_fpath: str,
|
||||
timeit: bool = False,
|
||||
profile: bool = False,
|
||||
profiler: Profiler = Profiler.NCU,
|
||||
profiler_args: str = "",
|
||||
) -> str:
|
||||
"""
|
||||
@@ -152,8 +194,9 @@ class NVCCPlugin(Magics):
|
||||
timeit: If True, returns the result of the "timeit" magic instead
|
||||
of the standard output of the CUDA process. Defaults to False.
|
||||
profile: If True, the executable is profiled with NVIDIA Nsight
|
||||
Compute profiling tool and its output is added to stdout.
|
||||
Defaults to False.
|
||||
Compute or NVIDIA Nsight Systems and the profiling output is
|
||||
added to stdout. Defaults to False.
|
||||
profiler: The profiling tool to use.
|
||||
profiler_args: The profiler arguments used to customize the
|
||||
information gathered by it and its overall behaviour. Defaults
|
||||
to an empty string.
|
||||
@@ -175,7 +218,8 @@ class NVCCPlugin(Magics):
|
||||
else:
|
||||
run_args = []
|
||||
if profile:
|
||||
run_args.extend(["ncu"] + profiler_args.split())
|
||||
profiler_path = self._get_profiler_path(profiler)
|
||||
run_args.extend([profiler_path] + profiler_args.split())
|
||||
run_args.append(exec_fpath)
|
||||
output = subprocess.check_output(
|
||||
run_args, stderr=subprocess.STDOUT
|
||||
@@ -188,12 +232,16 @@ class NVCCPlugin(Magics):
|
||||
self, group_name: str, args: argparse.Namespace
|
||||
) -> str:
|
||||
try:
|
||||
exec_fpath = self._compile(group_name)
|
||||
exec_fpath = self._compile(
|
||||
group_name=group_name,
|
||||
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.profiler(),
|
||||
profiler_args=args.profiler_args(),
|
||||
)
|
||||
except subprocess.CalledProcessError as e:
|
||||
output = e.output.decode("utf8")
|
||||
@@ -317,5 +365,6 @@ def load_ipython_extension(shell: InteractiveShell):
|
||||
"""
|
||||
Method used by IPython to load the extension.
|
||||
"""
|
||||
setup_environment()
|
||||
nvcc_plugin = NVCCPlugin(shell)
|
||||
shell.register_magics(nvcc_plugin)
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
"""
|
||||
Setup steps for platforms such as Kaggle, Colab, etc. to allow our extension
|
||||
to work on them immediately after loading it.
|
||||
"""
|
||||
|
||||
# pylint: disable=missing-function-docstring
|
||||
|
||||
import os
|
||||
import traceback
|
||||
from subprocess import DEVNULL, STDOUT, check_call
|
||||
from typing import Optional
|
||||
|
||||
PATH_PRIORITY_DIR = "/usr/bin/priority"
|
||||
KAGGLE_GCC_8_PATH = "/usr/bin/gcc-8"
|
||||
|
||||
|
||||
def print_platform(platform: str) -> None:
|
||||
print(f'Detected platform "{platform}". Running its setup...')
|
||||
|
||||
|
||||
def kaggle_setup() -> None:
|
||||
print("Updating the package lists...")
|
||||
check_call(["/usr/bin/apt-get", "update"], stdout=DEVNULL, stderr=STDOUT)
|
||||
|
||||
print("Installing nvidia-cuda-toolkit, this may take a few minutes...")
|
||||
check_call(
|
||||
["/usr/bin/apt-get", "install", "-y", "nvidia-cuda-toolkit"],
|
||||
stdout=DEVNULL,
|
||||
stderr=STDOUT,
|
||||
)
|
||||
os.makedirs(PATH_PRIORITY_DIR, exist_ok=True)
|
||||
|
||||
gcc_symlink_path = os.path.join(PATH_PRIORITY_DIR, "gcc")
|
||||
if not os.path.exists(gcc_symlink_path):
|
||||
os.symlink(KAGGLE_GCC_8_PATH, gcc_symlink_path)
|
||||
|
||||
if PATH_PRIORITY_DIR not in os.environ["PATH"].split(":"):
|
||||
os.environ["PATH"] = f"{PATH_PRIORITY_DIR}:" + os.environ["PATH"]
|
||||
|
||||
|
||||
def colab_setup() -> None:
|
||||
pass
|
||||
|
||||
|
||||
def setup_environment() -> None:
|
||||
"""
|
||||
Detect the platform the extension was loaded on and run the necessary
|
||||
steps (install dependencies, add executables to PATH, etc.) for the
|
||||
extension to work.
|
||||
"""
|
||||
|
||||
if "NVCC4JUPYTER_NO_SETUP" in os.environ:
|
||||
return
|
||||
|
||||
platform: Optional[str] = None
|
||||
try:
|
||||
if "KAGGLE_URL_BASE" in os.environ:
|
||||
platform = "Kaggle"
|
||||
print_platform(platform)
|
||||
kaggle_setup()
|
||||
elif "COLAB_RELEASE_TAG" in os.environ:
|
||||
platform = "Colab"
|
||||
print_platform(platform)
|
||||
colab_setup()
|
||||
except Exception: # pylint: disable=broad-exception-caught
|
||||
print(
|
||||
f'Setup failed for detected platform "{platform}". Set the'
|
||||
' "NVCC4JUPYTER_NO_SETUP" environment variable to disable running'
|
||||
" the setup on load. Please report the following error to"
|
||||
" https://github.com/andreinechaev/nvcc4jupyter/issues:"
|
||||
f" following error message:\n{traceback.format_exc()}"
|
||||
)
|
||||
+9
-3
@@ -69,6 +69,7 @@ exclude_lines = [
|
||||
|
||||
[tool.isort]
|
||||
profile = "black"
|
||||
src_paths = ["nvcc4jupyter"] # tells isort where to find local modules to not consider them 3rd party libraries
|
||||
|
||||
[tool.bandit]
|
||||
exclude_dirs = ["build","dist","tests","scripts"]
|
||||
@@ -82,10 +83,15 @@ skips = ["B101", "B311", "B404", "B603"]
|
||||
[tool.black]
|
||||
line-length = 79
|
||||
fast = true
|
||||
experimental-string-processing = true
|
||||
preview = true
|
||||
enable-unstable-feature = ["string_processing"]
|
||||
|
||||
[tool.coverage.run]
|
||||
branch = true
|
||||
omit = [
|
||||
# cannot test installing dependencies on platforms such as kaggle
|
||||
"nvcc4jupyter/setup_env.py",
|
||||
]
|
||||
|
||||
[tool.pyright]
|
||||
include = ["src"]
|
||||
@@ -286,6 +292,6 @@ deprecated-modules="optparse,tkinter.tix"
|
||||
|
||||
[tool.pylint.'EXCEPTIONS']
|
||||
overgeneral-exceptions= [
|
||||
"BaseException",
|
||||
"Exception"
|
||||
"builtins.BaseException",
|
||||
"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
+29
-1
@@ -1,9 +1,11 @@
|
||||
import argparse
|
||||
import glob
|
||||
import os
|
||||
|
||||
import pytest
|
||||
from IPython.core.interactiveshell import InteractiveShell
|
||||
|
||||
from nvcc4jupyter.parsers import Profiler
|
||||
from nvcc4jupyter.plugin import NVCCPlugin
|
||||
|
||||
|
||||
@@ -27,10 +29,25 @@ def fixtures_path(tests_path):
|
||||
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")
|
||||
def sample_magic_cu_line():
|
||||
# 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
|
||||
|
||||
|
||||
@@ -55,3 +72,14 @@ def multiple_source_fpaths(fixtures_path: str):
|
||||
pattern_h = os.path.join(fixtures_path, "multiple_files", "*.h")
|
||||
pattern_cu = os.path.join(fixtures_path, "multiple_files", "*.cu")
|
||||
return list(glob.glob(pattern_h)) + list(glob.glob(pattern_cu))
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def default_args():
|
||||
return argparse.Namespace(
|
||||
timeit=False,
|
||||
profile=True,
|
||||
profiler=lambda: Profiler.NCU,
|
||||
profiler_args=lambda: "",
|
||||
compiler_args=lambda: "",
|
||||
)
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "[NCU]"
|
||||
|
||||
# this is a mock of nsight compute cli tool that just executes the program
|
||||
# given as the last argument
|
||||
"${@: -1}"
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "[NSYS]"
|
||||
|
||||
# this is a mock of nsight systems cli tool that just executes the program
|
||||
# given as the last argument
|
||||
"${@: -1}"
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "This is just used to test the path_utils.find_executable function"
|
||||
@@ -0,0 +1,16 @@
|
||||
import os
|
||||
|
||||
from nvcc4jupyter.path_utils import find_executable
|
||||
|
||||
|
||||
def test_which():
|
||||
assert find_executable("ls") == "/usr/bin/ls"
|
||||
|
||||
|
||||
def test_find_executable(fixtures_path: str):
|
||||
exec_path = find_executable("searchforme", [fixtures_path])
|
||||
assert exec_path is not None
|
||||
|
||||
exec_dir, exec_fname = os.path.split(exec_path)
|
||||
assert exec_fname == "searchforme"
|
||||
assert os.path.basename(exec_dir) == "scripts"
|
||||
+118
-23
@@ -1,27 +1,26 @@
|
||||
import argparse
|
||||
import math
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
from argparse import ArgumentParser, Namespace
|
||||
from copy import deepcopy
|
||||
from typing import List
|
||||
|
||||
import pytest
|
||||
|
||||
from nvcc4jupyter.parsers import Profiler, get_parser_cuda, set_defaults
|
||||
from nvcc4jupyter.plugin import NVCCPlugin
|
||||
|
||||
|
||||
def check_profiler_output(output: str):
|
||||
# the profiler output will be a line of "Hello World!" along with some
|
||||
# warning lines which start with "==WARNING=="
|
||||
def check_profiler_output(output: str, profiler: str = "[NCU]"):
|
||||
# the output from the profiler will first be a line containing only
|
||||
# "[NCU]" or "[NSYS]" depending on what profiler was used and another
|
||||
# line containing the string "Hello World!"
|
||||
lines = output.strip().split("\n")
|
||||
warn_count = 0
|
||||
for line in lines:
|
||||
if not line.startswith("==WARNING=="):
|
||||
assert line == "Hello World!"
|
||||
else:
|
||||
warn_count += 1
|
||||
assert warn_count >= 1
|
||||
assert warn_count == len(lines) - 1
|
||||
assert len(lines) >= 2
|
||||
assert lines[0] == profiler
|
||||
assert lines[1] == "Hello World!"
|
||||
|
||||
|
||||
def copy_source_to_group(
|
||||
@@ -36,11 +35,19 @@ def copy_source_to_group(
|
||||
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")
|
||||
def before_each(plugin: NVCCPlugin):
|
||||
shutil.rmtree(plugin.workdir, ignore_errors=True) # before test
|
||||
# BEFORE TESTS
|
||||
set_defaults(profiler=Profiler.NCU, 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:
|
||||
@@ -88,6 +95,49 @@ def test_compile(
|
||||
plugin._compile(gname)
|
||||
|
||||
|
||||
def test_compile_args(
|
||||
plugin: NVCCPlugin,
|
||||
compiler_cpp_17_fpath: str,
|
||||
default_args: Namespace,
|
||||
):
|
||||
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")
|
||||
|
||||
args = deepcopy(default_args)
|
||||
args.compiler_args = lambda: "--std c++14"
|
||||
output = plugin._compile_and_run(group_name=gname, args=args)
|
||||
assert "errors detected in the compilation of" in output
|
||||
|
||||
|
||||
def test_compile_opencv(
|
||||
plugin: NVCCPlugin,
|
||||
compiler_opencv_fpath: str,
|
||||
default_args: Namespace,
|
||||
):
|
||||
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
|
||||
|
||||
pkg_config_args = ["pkg-config", "--cflags", "--libs", "opencv4"]
|
||||
opencv_compile_options = (
|
||||
subprocess.check_output(args=pkg_config_args).decode().strip()
|
||||
)
|
||||
|
||||
args = deepcopy(default_args)
|
||||
args.compiler_args = lambda: opencv_compile_options
|
||||
output = plugin._compile_and_run(group_name=gname, args=args)
|
||||
assert "General configuration for OpenCV" in output
|
||||
|
||||
|
||||
def test_run(
|
||||
plugin: NVCCPlugin,
|
||||
sample_cuda_fpath: str,
|
||||
@@ -133,7 +183,9 @@ def test_run_profile(plugin: NVCCPlugin, sample_cuda_fpath: str):
|
||||
|
||||
|
||||
def test_compile_and_run_multiple_files(
|
||||
plugin: NVCCPlugin, multiple_source_fpaths: List[str]
|
||||
plugin: NVCCPlugin,
|
||||
multiple_source_fpaths: List[str],
|
||||
default_args: Namespace,
|
||||
):
|
||||
"""
|
||||
Compiles and executes 3 cuda source files from
|
||||
@@ -142,14 +194,14 @@ def test_compile_and_run_multiple_files(
|
||||
gname = "test_compile_and_run_multiple_files"
|
||||
for fpath in multiple_source_fpaths:
|
||||
copy_source_to_group(fpath, gname, plugin.workdir)
|
||||
output = plugin._compile_and_run(
|
||||
gname, argparse.Namespace(timeit=False, profile=True, profiler_args="")
|
||||
)
|
||||
output = plugin._compile_and_run(group_name=gname, args=default_args)
|
||||
check_profiler_output(output)
|
||||
|
||||
|
||||
def test_compile_and_run_multiple_files_shared(
|
||||
plugin: NVCCPlugin, multiple_source_fpaths: List[str]
|
||||
plugin: NVCCPlugin,
|
||||
multiple_source_fpaths: List[str],
|
||||
default_args: Namespace,
|
||||
):
|
||||
"""
|
||||
Compiles and executes 3 cuda source files from
|
||||
@@ -164,14 +216,12 @@ def test_compile_and_run_multiple_files_shared(
|
||||
copy_source_to_group(fpath, gname, plugin.workdir)
|
||||
else:
|
||||
copy_source_to_group(fpath, "shared", plugin.workdir)
|
||||
output = plugin._compile_and_run(
|
||||
gname, argparse.Namespace(timeit=False, profile=True, profiler_args="")
|
||||
)
|
||||
output = plugin._compile_and_run(group_name=gname, args=default_args)
|
||||
check_profiler_output(output)
|
||||
|
||||
|
||||
def test_read_args(plugin: NVCCPlugin):
|
||||
parser = argparse.ArgumentParser()
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument("-a", type=str, required=True)
|
||||
parser.add_argument("-b", type=float, required=True)
|
||||
args = plugin._read_args(
|
||||
@@ -181,6 +231,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,
|
||||
@@ -191,6 +264,28 @@ def test_magic_cuda(
|
||||
check_profiler_output(capsys.readouterr().out)
|
||||
|
||||
|
||||
def test_magic_cuda_set_default_profiler(
|
||||
capsys,
|
||||
plugin: NVCCPlugin,
|
||||
sample_cuda_code: str,
|
||||
sample_magic_cu_line: str,
|
||||
):
|
||||
# set the default profiler to Nsight Systems
|
||||
set_defaults(profiler=Profiler.NSYS)
|
||||
plugin.cuda(sample_magic_cu_line, sample_cuda_code)
|
||||
check_profiler_output(capsys.readouterr().out, profiler="[NSYS]")
|
||||
|
||||
|
||||
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):
|
||||
gname = "test_save_source"
|
||||
sname = "sample.cu"
|
||||
|
||||
Reference in New Issue
Block a user