Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
21 changes: 8 additions & 13 deletions tutorials/accelerated-python/brev/test.bash
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,20 @@ START_TIME=$(date +%s.%N)

nvidia-smi

# Run regular package tests.
echo "Running regular package tests..."
pytest /accelerated-computing-hub/tutorials/accelerated-python/test/test_packages.py
EXIT_CODE_PACKAGES=$?
# Run tests.
echo "Running tests..."
pytest /accelerated-computing-hub/tutorials/accelerated-python/test/ \
--ignore=/accelerated-computing-hub/tutorials/accelerated-python/test/test_rapids.py
EXIT_CODE_TESTS=$?

# Run RAPIDS tests.
# Run RAPIDS tests separately because they require a different virtual environment.
echo ""
echo "Running RAPIDS package tests in virtual environment..."
echo "Running RAPIDS tests in virtual environment..."
/opt/venvs/rapids/bin/pytest /accelerated-computing-hub/tutorials/accelerated-python/test/test_rapids.py
EXIT_CODE_RAPIDS=$?

# Test solution notebooks.
echo ""
echo "Running solution notebook tests..."
pytest /accelerated-computing-hub/tutorials/accelerated-python/test/test_notebooks.py
EXIT_CODE_NOTEBOOKS=$?

# Overall exit code is non-zero if any test suite failed.
EXIT_CODE=$((EXIT_CODE_PACKAGES || EXIT_CODE_RAPIDS || EXIT_CODE_NOTEBOOKS))
EXIT_CODE=$((EXIT_CODE_TESTS || EXIT_CODE_RAPIDS))

END_TIME=$(date +%s.%N)
ELAPSED=$(awk "BEGIN {print $END_TIME - $START_TIME}")
Expand Down
105 changes: 105 additions & 0 deletions tutorials/accelerated-python/test/test_cuda_tools.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
"""
Test that CUDA tools (nvcc, nsys, ncu) work correctly.

Compiles a minimal CUDA C++ program using Thrust and verifies that both
Nsight Systems and Nsight Compute can successfully profile it.
"""

import pytest
import shutil
import subprocess
from pathlib import Path

CUDA_PROGRAM = r"""
#include <thrust/device_vector.h>
#include <thrust/sequence.h>
#include <thrust/reduce.h>
#include <iostream>
#include <cstdlib>

int main() {
constexpr int n = 256;

thrust::device_vector<float> d(n);
thrust::sequence(d.begin(), d.end());

float sum = thrust::reduce(d.begin(), d.end());
float expected = n * (n - 1) / 2.0f;

if (sum != expected) {
std::cerr << "Mismatch: got " << sum << ", expected " << expected << std::endl;
return EXIT_FAILURE;
}

std::cout << "PASS" << std::endl;
}
"""


@pytest.fixture(scope="module")
def cuda_binary(tmp_path_factory):
"""Compile a minimal CUDA C++ program and return the path to the binary."""
tmp_dir = tmp_path_factory.mktemp("nsight_test")
src_path = tmp_dir / "test_program.cu"
bin_path = tmp_dir / "test_program"

src_path.write_text(CUDA_PROGRAM)

nvcc_path = shutil.which("nvcc")
print(f"nvcc resolves to: {nvcc_path}")

result = subprocess.run(
["nvcc", "-o", str(bin_path), str(src_path)],
capture_output=True, text=True, timeout=120
)
assert result.returncode == 0, \
f"nvcc compilation failed:\nstdout: {result.stdout}\nstderr: {result.stderr}"
assert bin_path.exists(), "Binary was not created"

return bin_path


def test_cuda_binary_runs(cuda_binary):
"""Verify the compiled CUDA binary runs successfully."""
result = subprocess.run(
[str(cuda_binary)],
capture_output=True, text=True, timeout=30
)
assert result.returncode == 0, \
f"CUDA binary failed:\nstdout: {result.stdout}\nstderr: {result.stderr}"
assert "PASS" in result.stdout


def test_nsys_profile(cuda_binary, tmp_path):
"""Test that nsys can profile the CUDA binary."""
nsys_path = shutil.which("nsys")
print(f"nsys resolves to: {nsys_path}")

report_path = tmp_path / "test_report.nsys-rep"

result = subprocess.run(
["nsys", "profile",
"--force-overwrite=true",
"--output", str(report_path),
str(cuda_binary)],
capture_output=True, text=True, timeout=120
)
assert result.returncode == 0, \
f"nsys profile failed:\nstdout: {result.stdout}\nstderr: {result.stderr}"
assert report_path.exists(), "nsys report file was not created"


def test_ncu_profile(cuda_binary):
"""Test that ncu can profile the CUDA binary."""
ncu_path = shutil.which("ncu")
print(f"ncu resolves to: {ncu_path}")

result = subprocess.run(
["ncu",
"--target-processes=all",
"--set=basic",
str(cuda_binary)],
capture_output=True, text=True, timeout=120
)
assert result.returncode == 0, \
f"ncu profile failed:\nstdout: {result.stdout}\nstderr: {result.stderr}"
29 changes: 29 additions & 0 deletions tutorials/accelerated-python/test/test_notebook.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from nsightful.notebook import is_interactive_notebook\n",
"\n",
"assert is_interactive_notebook() == False, \"nsightful interactive notebook check failed\""
]
}
],
"metadata": {
"accelerator": "GPU",
"colab": {
"gpuType": "T4",
"provenance": []
},
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
14 changes: 12 additions & 2 deletions tutorials/accelerated-python/test/test_notebooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,25 @@

# Define the path to the notebooks directory
NOTEBOOKS_DIR = Path(__file__).resolve().parent.parent / 'notebooks'
TEST_DIR = Path(__file__).resolve().parent

# Discover all solution notebooks (excluding checkpoint files)
solution_notebooks = sorted([
nb for nb in NOTEBOOKS_DIR.rglob('*SOLUTION*.ipynb')
if '.ipynb_checkpoints' not in str(nb)
])

# Discover test notebooks in the test directory
test_notebooks = sorted([
nb for nb in TEST_DIR.glob('*.ipynb')
if '.ipynb_checkpoints' not in str(nb)
])

all_notebooks = solution_notebooks + test_notebooks

# Create test IDs from notebook paths for better test output
notebook_ids = [nb.relative_to(NOTEBOOKS_DIR).as_posix() for nb in solution_notebooks]
notebook_ids = [nb.relative_to(NOTEBOOKS_DIR).as_posix() for nb in solution_notebooks] + \
[nb.name for nb in test_notebooks]


def extract_cell_outputs(nb, cell_times=None):
Expand Down Expand Up @@ -66,7 +76,7 @@ def check_gpu_state():
print(f" GPU State check failed: {e}")


@pytest.mark.parametrize('notebook_path', solution_notebooks, ids=notebook_ids)
@pytest.mark.parametrize('notebook_path', all_notebooks, ids=notebook_ids)
def test_solution_notebook_executes(notebook_path):
"""
Test that a solution notebook executes without errors.
Expand Down
3 changes: 3 additions & 0 deletions tutorials/cuda-cpp/brev/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,6 @@ jupyterlab-execute-time

# NVIDIA devtools
nsightful[notebook] @ git+https://github.com/brycelelbach/nsightful.git

# Testing
pytest
20 changes: 20 additions & 0 deletions tutorials/cuda-cpp/brev/test.bash
Original file line number Diff line number Diff line change
@@ -1,3 +1,23 @@
#! /bin/bash

START_TIME=$(date +%s.%N)

nvidia-smi

# Run tests.
echo "Running tests..."
pytest /accelerated-computing-hub/tutorials/cuda-cpp/test/
EXIT_CODE=$?

END_TIME=$(date +%s.%N)
ELAPSED=$(awk "BEGIN {print $END_TIME - $START_TIME}")

echo ""
awk -v elapsed="$ELAPSED" 'BEGIN {
hours = int(elapsed / 3600)
minutes = int((elapsed % 3600) / 60)
seconds = elapsed % 60
printf "Elapsed time: %dh %dm %.3fs\n", hours, minutes, seconds
}'

exit $EXIT_CODE
2 changes: 2 additions & 0 deletions tutorials/cuda-cpp/test/pytest.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[pytest]
addopts = -v -s --durations=0 --durations-min=0.0
105 changes: 105 additions & 0 deletions tutorials/cuda-cpp/test/test_cuda_tools.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
"""
Test that CUDA tools (nvcc, nsys, ncu) work correctly.

Compiles a minimal CUDA C++ program using Thrust and verifies that both
Nsight Systems and Nsight Compute can successfully profile it.
"""

import pytest
import shutil
import subprocess
from pathlib import Path

CUDA_PROGRAM = r"""
#include <thrust/device_vector.h>
#include <thrust/sequence.h>
#include <thrust/reduce.h>
#include <iostream>
#include <cstdlib>

int main() {
constexpr int n = 256;

thrust::device_vector<float> d(n);
thrust::sequence(d.begin(), d.end());

float sum = thrust::reduce(d.begin(), d.end());
float expected = n * (n - 1) / 2.0f;

if (sum != expected) {
std::cerr << "Mismatch: got " << sum << ", expected " << expected << std::endl;
return EXIT_FAILURE;
}

std::cout << "PASS" << std::endl;
}
"""


@pytest.fixture(scope="module")
def cuda_binary(tmp_path_factory):
"""Compile a minimal CUDA C++ program and return the path to the binary."""
tmp_dir = tmp_path_factory.mktemp("nsight_test")
src_path = tmp_dir / "test_program.cu"
bin_path = tmp_dir / "test_program"

src_path.write_text(CUDA_PROGRAM)

nvcc_path = shutil.which("nvcc")
print(f"nvcc resolves to: {nvcc_path}")

result = subprocess.run(
["nvcc", "-o", str(bin_path), str(src_path)],
capture_output=True, text=True, timeout=120
)
assert result.returncode == 0, \
f"nvcc compilation failed:\nstdout: {result.stdout}\nstderr: {result.stderr}"
assert bin_path.exists(), "Binary was not created"

return bin_path


def test_cuda_binary_runs(cuda_binary):
"""Verify the compiled CUDA binary runs successfully."""
result = subprocess.run(
[str(cuda_binary)],
capture_output=True, text=True, timeout=30
)
assert result.returncode == 0, \
f"CUDA binary failed:\nstdout: {result.stdout}\nstderr: {result.stderr}"
assert "PASS" in result.stdout


def test_nsys_profile(cuda_binary, tmp_path):
"""Test that nsys can profile the CUDA binary."""
nsys_path = shutil.which("nsys")
print(f"nsys resolves to: {nsys_path}")

report_path = tmp_path / "test_report.nsys-rep"

result = subprocess.run(
["nsys", "profile",
"--force-overwrite=true",
"--output", str(report_path),
str(cuda_binary)],
capture_output=True, text=True, timeout=120
)
assert result.returncode == 0, \
f"nsys profile failed:\nstdout: {result.stdout}\nstderr: {result.stderr}"
assert report_path.exists(), "nsys report file was not created"


def test_ncu_profile(cuda_binary):
"""Test that ncu can profile the CUDA binary."""
ncu_path = shutil.which("ncu")
print(f"ncu resolves to: {ncu_path}")

result = subprocess.run(
["ncu",
"--target-processes=all",
"--set=basic",
str(cuda_binary)],
capture_output=True, text=True, timeout=120
)
assert result.returncode == 0, \
f"ncu profile failed:\nstdout: {result.stdout}\nstderr: {result.stderr}"
3 changes: 3 additions & 0 deletions tutorials/stdpar/brev/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,6 @@ jupyterlab-execute-time

# NVIDIA devtools
nsightful[notebook] @ git+https://github.com/brycelelbach/nsightful.git

# Testing
pytest
20 changes: 20 additions & 0 deletions tutorials/stdpar/brev/test.bash
Original file line number Diff line number Diff line change
@@ -1,3 +1,23 @@
#! /bin/bash

START_TIME=$(date +%s.%N)

nvidia-smi

# Run tests.
echo "Running tests..."
pytest /accelerated-computing-hub/tutorials/stdpar/test/
EXIT_CODE=$?

END_TIME=$(date +%s.%N)
ELAPSED=$(awk "BEGIN {print $END_TIME - $START_TIME}")

echo ""
awk -v elapsed="$ELAPSED" 'BEGIN {
hours = int(elapsed / 3600)
minutes = int((elapsed % 3600) / 60)
seconds = elapsed % 60
printf "Elapsed time: %dh %dm %.3fs\n", hours, minutes, seconds
}'

exit $EXIT_CODE
2 changes: 2 additions & 0 deletions tutorials/stdpar/test/pytest.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[pytest]
addopts = -v -s --durations=0 --durations-min=0.0
Loading
Loading