mirror of
https://github.com/NVIDIA/cuda-samples.git
synced 2026-10-13 00:08:26 +08:00
CUDA 13.2 samples update (#432)
- Added Python samples for CUDA Python 1.0 release - Renamed top-level `Samples` directory to `cpp` to accommodate Python samples.
This commit is contained in:
73
python/1_GettingStarted/numpyVsCupy/README.md
Normal file
73
python/1_GettingStarted/numpyVsCupy/README.md
Normal file
@@ -0,0 +1,73 @@
|
||||
# Sample: Numpy vs. Cupy (Python)
|
||||
|
||||
## Description
|
||||
|
||||
This sample demonstrates performance comparison between NumPy (CPU) and CuPy (GPU) for matrix multiplication operations. It benchmarks the execution time of matrix dot products on both CPU and GPU, showing the performance benefits of GPU acceleration for numerical computations.
|
||||
|
||||
## What you will learn
|
||||
|
||||
- How to set up and use CuPy for GPU-accelerated numerical computations.
|
||||
- How to benchmark NumPy vs CuPy performance for matrix operations.
|
||||
- How to transfer data between CPU (NumPy) and GPU (CuPy) memory using `cp.asarray()`.
|
||||
- How to use CUDA device management with the cuda-core library.
|
||||
- How to validate computational results between CPU and GPU implementations using `np.testing.assert_allclose()`.
|
||||
- How to handle GPU warmup to avoid first-run overhead in benchmarking.
|
||||
- How to create and manage explicit CUDA streams with `device.create_stream()`.
|
||||
- How to properly cleanup streams with `stream.close()` in try/finally blocks.
|
||||
- How to access GPU device information (name, compute capability).
|
||||
- How to create timing context managers for performance measurement using CUDA events.
|
||||
|
||||
## Key libraries
|
||||
|
||||
- `numpy`
|
||||
- `cupy`
|
||||
- `cuda-core`
|
||||
|
||||
## Key APIs
|
||||
|
||||
**From cuda.core:**
|
||||
- `Device()` – Get CUDA device object for specific GPU
|
||||
- `device.create_stream()` – Create explicit CUDA stream
|
||||
- `stream.close()` – Close and cleanup stream resources
|
||||
|
||||
## Requirements
|
||||
1. **NVIDIA Graphics Card** with CUDA support
|
||||
2. **CUDA Drivers** installed on your system
|
||||
3. **CUDA Toolkit** installed on your system
|
||||
4. **Python 3.12 or newer**
|
||||
|
||||
**Install packages:**
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
## How to run
|
||||
|
||||
Basic usage:
|
||||
```bash
|
||||
# Pre-steps:
|
||||
export LD_LIBRARY_PATH=/usr/local/cuda/lib64:$LD_LIBRARY_PATH
|
||||
# Run from the Python directory:
|
||||
cd /path/to/numpyVsCupy/Python
|
||||
python -m 1_GettingStarted.numpyVsCupy.numpyVsCupy
|
||||
```
|
||||
|
||||
With custom parameters:
|
||||
```bash
|
||||
python -m 1_GettingStarted.numpyVsCupy.numpyVsCupy --n_size 5000
|
||||
```
|
||||
|
||||
### Command line arguments
|
||||
|
||||
- `--n_size`, `-n`: Size of the matrix (n * n) for benchmarking (default: 4096)
|
||||
|
||||
## Expected Output
|
||||
```
|
||||
Validation PASSED: NumPy and CuPy results match within tolerance
|
||||
Demo completed successfully!
|
||||
```
|
||||
|
||||
## Files
|
||||
- `numpyVsCupy.py` – Python implementation
|
||||
- `README.md` – This file
|
||||
- `requirements.txt` – Required packages
|
||||
141
python/1_GettingStarted/numpyVsCupy/numpyVsCupy.py
Normal file
141
python/1_GettingStarted/numpyVsCupy/numpyVsCupy.py
Normal file
@@ -0,0 +1,141 @@
|
||||
# Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# distribution and/or other materials provided with the distribution.
|
||||
# * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
|
||||
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import argparse
|
||||
import contextlib
|
||||
import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
try:
|
||||
import cupy as cp
|
||||
import numpy as np
|
||||
from cuda.core import Device, EventOptions
|
||||
except ImportError as e:
|
||||
print(f"Error: Required package not found: {e}")
|
||||
print("Please install from requirements.txt:")
|
||||
print(" pip install -r requirements.txt")
|
||||
sys.exit(1)
|
||||
|
||||
# Add parent directory to path to import utilities
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent.parent / "Utilities"))
|
||||
from cuda_samples_utils import verify_array_result
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def timer(message):
|
||||
"""CPU timing context manager."""
|
||||
start = time.time()
|
||||
yield
|
||||
end = time.time()
|
||||
print(f"{message}: {(end - start):.6f} seconds")
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def gpu_timer(message, stream):
|
||||
"""GPU timing context manager using cuda.core CUDA events."""
|
||||
event_options = EventOptions(enable_timing=True)
|
||||
start_event = stream.record(options=event_options)
|
||||
yield
|
||||
end_event = stream.record(options=event_options)
|
||||
end_event.sync()
|
||||
|
||||
elapsed_time_ms = end_event - start_event # Returns milliseconds
|
||||
elapsed_time_s = elapsed_time_ms / 1000.0 # Convert to seconds
|
||||
print(f"{message}: {elapsed_time_s:.6f} seconds")
|
||||
|
||||
|
||||
def warmup():
|
||||
# Pre-runs a simple GPU operation to avoid first-run overhead in benchmarking.
|
||||
print("Warmup...")
|
||||
a_cp = cp.ones((16, 16))
|
||||
b_cp = cp.ones((16, 16))
|
||||
result_cp = cp.dot(a_cp, b_cp)
|
||||
return result_cp
|
||||
|
||||
|
||||
def run(n):
|
||||
# Benchmarks NumPy vs. CuPy matrix multiplication for n x n random arrays.
|
||||
# Prints timing results.
|
||||
|
||||
device = Device() # Use device 0 explicitly
|
||||
device.set_current()
|
||||
major, minor = device.compute_capability
|
||||
print()
|
||||
print(f"Device Name: {device.name}, SM: {major}.{minor}")
|
||||
print()
|
||||
|
||||
# Create explicit stream
|
||||
stream = device.create_stream()
|
||||
|
||||
try:
|
||||
# Warm up GPU before measuring
|
||||
warmup()
|
||||
stream.sync()
|
||||
|
||||
# Generate random matrices on CPU
|
||||
a_np = np.random.rand(n, n)
|
||||
b_np = np.random.rand(n, n)
|
||||
|
||||
# NumPy dot product (CPU)
|
||||
with timer(f"NumPy dot of {n}*{n} arrays"):
|
||||
result_np = np.dot(a_np, b_np)
|
||||
|
||||
# Transfer NumPy arrays to GPU (using events for timing)
|
||||
with gpu_timer("Transfer arrays to GPU", stream):
|
||||
a_cp = cp.asarray(a_np)
|
||||
b_cp = cp.asarray(b_np)
|
||||
|
||||
# CuPy dot product (GPU) - using events for accurate GPU timing
|
||||
with gpu_timer(f"CuPy dot of {n}*{n} arrays", stream):
|
||||
result_cp = cp.dot(a_cp, b_cp)
|
||||
|
||||
print()
|
||||
# Result validation
|
||||
if not verify_array_result(result_np, result_cp.get()):
|
||||
print(
|
||||
"Validation FAILED: NumPy and CuPy results do not match "
|
||||
"within tolerance"
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
print("Validation PASSED: NumPy and CuPy results match within tolerance")
|
||||
finally:
|
||||
stream.close()
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
"--n_size", "-n", default=4096, type=int, help="Size of the matrix(n * n)."
|
||||
)
|
||||
args = parser.parse_args()
|
||||
run(args.n_size)
|
||||
print("Demo completed successfully!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
7
python/1_GettingStarted/numpyVsCupy/requirements.txt
Normal file
7
python/1_GettingStarted/numpyVsCupy/requirements.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
# Numpy vs. Cupy - Requirements
|
||||
# Install with: pip install -r requirements.txt
|
||||
|
||||
numpy>=2.3.2
|
||||
cuda-python>=13.0.0
|
||||
cuda-core>=0.6.0
|
||||
cupy-cuda13x>=13.0.0
|
||||
Reference in New Issue
Block a user