Skip to content

Commit 991bd99

Browse files
committed
Update optimize-for-gpu skill documentation and assets
- Enhanced the skill description for clarity and accuracy regarding GPU acceleration. - Updated compatibility notes to reflect requirements for RAPIDS 26.06 and Python 3.11+. - Revised the library selection guidance to emphasize preferred usage patterns and legacy considerations. - Improved the optimization workflow section with detailed steps for defining contracts and checking suitability. - Added new code transformation patterns and clarified the use of cuSpatial and cuVS. - Updated the cuCIM reference to include installation instructions and performance characteristics. - Replaced the existing optimize-for-gpu.png image with a new version to better illustrate the skill's capabilities.
1 parent 5c0d8b3 commit 991bd99

17 files changed

Lines changed: 438 additions & 306 deletions

docs/images/optimize-for-gpu.png

-23 KB
Loading

skills/optimize-for-gpu/SKILL.md

Lines changed: 104 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
---
22
name: optimize-for-gpu
3-
description: "GPU-accelerate Python code using CuPy, Numba CUDA, Warp, cuDF, cuML, cuGraph, KvikIO, cuCIM, cuxfilter, cuVS, cuSpatial, and RAFT. Use whenever the user mentions GPU/CUDA/NVIDIA acceleration, or wants to speed up NumPy, pandas, scikit-learn, scikit-image, NetworkX, GeoPandas, or Faiss workloads. Covers physics simulation, differentiable rendering, mesh ray casting, particle systems (DEM/SPH/fluids), vector/similarity search, GPUDirect Storage file IO, interactive dashboards, geospatial analysis, medical imaging, and sparse eigensolvers. Also use when you see CPU-bound Python code (loops, large arrays, ML pipelines, graph analytics, image processing) that would benefit from GPU acceleration, even if not explicitly requested."
3+
description: GPU-accelerates scientific Python on NVIDIA hardware and verifies that the result is correct and faster. Use for CUDA/GPU optimization; CPU-bound NumPy, SciPy, pandas, scikit-learn, NetworkX, scikit-image, vector-search, image-processing, graph, simulation, or file-I/O workloads; CuPy, cuDF, cuML, cuGraph, cuVS, cuCIM, KvikIO, Warp, Newton, Numba-CUDA, or RAFT questions; and profiling, memory-transfer, kernel, or multi-GPU bottlenecks. Also use when large data-parallel Python code is slow and GPU acceleration is a plausible option, even if the user does not name CUDA.
4+
license: MIT
5+
compatibility: Requires an NVIDIA CUDA-capable GPU for GPU execution. RAPIDS 26.06 requires Python 3.11+ on Linux or WSL2 and matching CUDA 12 or 13 wheels. Package installation needs network access.
46
metadata:
5-
version: "1.2"
6-
author: K-Dense, Inc.
7+
version: "1.3"
8+
skill-author: K-Dense, Inc.
79
---
810

911
# GPU Optimization for Python with NVIDIA
1012

11-
You are an expert GPU optimization engineer. Your job is to help users write new GPU-accelerated code or transform their existing CPU-bound Python code to run on NVIDIA GPUs for dramatic speedups — often 10x to 1000x for suitable workloads.
13+
Treat GPU acceleration as an evidence-driven optimization, not an automatic rewrite. Preserve the
14+
user's numerical and algorithmic contract, measure with representative data, and keep the GPU
15+
version only when synchronized end-to-end benchmarks show a useful improvement.
1216

1317
## When This Skill Applies
1418

@@ -36,24 +40,34 @@ You are an expert GPU optimization engineer. Your job is to help users write new
3640
- User is doing simulations, signal processing, financial modeling, bioinformatics, physics, or any compute-intensive work
3741
- User wants to optimize existing code and GPU acceleration is the right answer
3842

39-
## Choosing a Library
43+
## Choose the Smallest Suitable Layer
4044

41-
Pick the GPU library by the CPU library it replaces:
45+
Prefer a maintained library implementation over a custom kernel:
4246

43-
| CPU library | GPU replacement | Use for |
47+
| Existing workload | Preferred path | Use for |
4448
| --- | --- | --- |
45-
| NumPy | **CuPy** | array and matrix operations |
46-
| (custom loops) | **Numba CUDA** | hand-written GPU kernels |
47-
| (simulation) | **Warp** | simulation, spatial computing, differentiable programming |
48-
| pandas | **cuDF** | dataframe operations |
49-
| scikit-learn | **cuML** | machine learning |
50-
| NetworkX | **cuGraph** | graph analytics |
51-
| (file IO) | **KvikIO** | high-performance GPU file IO |
52-
| (dashboards) | **cuxfilter** | GPU-accelerated interactive dashboards |
53-
| scikit-image | **cuCIM** | image processing |
54-
| Faiss / Annoy | **cuVS** | vector search |
55-
| GeoPandas | **cuSpatial** | geospatial analytics |
56-
| (low-level) | **RAFT** (pylibraft) | GPU primitives and multi-GPU |
49+
| NumPy / SciPy | **CuPy** | arrays, sparse matrices, linear algebra, FFTs, signal processing |
50+
| pandas | **cudf.pandas**, then **cuDF** | accelerator mode first; native API for more control |
51+
| scikit-learn | **cuml.accel**, then **cuML** | accelerator mode first; native estimators as needed |
52+
| NetworkX | **nx-cugraph**, then **cuGraph** | backend dispatch first; native graph API at scale |
53+
| scikit-image | **cuCIM** | GPU image processing and whole-slide imaging |
54+
| Faiss / Annoy / k-NN | **cuVS** | exact and approximate vector search |
55+
| Raw or remote file I/O | **KvikIO** | GPU buffers and GPUDirect Storage |
56+
| Custom array kernels | **Numba-CUDA-MLIR** for new work; **Numba-CUDA** for existing code | explicit SIMT kernels and shared memory |
57+
| Spatial or differentiable kernels | **Warp** | geometry, simulation kernels, robotics, autodiff |
58+
| High-level physics simulation | **Newton** | maintained engine that succeeds the removed `warp.sim` module |
59+
| Low-level RAPIDS primitives | **RAFT** (`pylibraft`) | sparse eigensolvers, resources, multi-GPU building blocks |
60+
61+
Do not move code out of PyTorch, JAX, TensorFlow, or another GPU-native framework merely to use
62+
one of these libraries. First remove CPU round trips and use the framework's compiler, profiler,
63+
mixed-precision, and batching facilities.
64+
65+
Treat these as legacy-only:
66+
67+
| Project | Status | Guidance |
68+
| --- | --- | --- |
69+
| **cuxfilter** | Final release 26.06 | Maintain existing dashboards only. For new work, combine cuDF with HoloViews/hvPlot/Datashader and serve with Panel, Dash, Streamlit, or Bokeh. |
70+
| **cuSpatial** | Archived at 25.04 | Use only in an isolated legacy environment. For new work, keep geometry in GeoPandas/Shapely and accelerate compatible tabular stages with cuDF. |
5771

5872
Full per-library guidance, including when each is the *wrong* choice and how to combine
5973
them, is in [references/decision_framework.md](references/decision_framework.md).
@@ -64,56 +78,81 @@ every library are in
6478

6579
## Optimization Workflow
6680

67-
When helping a user optimize code, follow this process:
81+
### 1. Define the contract and baseline
82+
83+
- Capture a representative input, expected output, and acceptable numerical tolerance.
84+
- Measure the current end-to-end path, including input, transfers, compute, and output.
85+
- Profile before changing code. Use CPU profilers for CPU code and identify whether the real limit
86+
is compute, memory bandwidth, allocation, transfer, synchronization, or storage.
87+
- Record hardware, package versions, dtypes, shapes, batch size, and warm-up policy with results.
88+
89+
### 2. Check suitability before porting
90+
91+
GPU execution is promising when the hot path exposes substantial independent work, runs often
92+
enough to amortize initialization and transfer, and has a working set that fits available device
93+
memory with room for temporaries. Keep a CPU path when the workload is small, mostly sequential,
94+
dominated by unsupported operations, or requires frequent host-device round trips.
95+
96+
Do not use fixed row-count thresholds as proof. Benchmark the user's actual shapes and hardware.
97+
For out-of-core data, estimate peak working memory and choose chunking, Dask, or a streaming design
98+
before allocating.
99+
100+
### 3. Try the least disruptive implementation
101+
102+
1. If the code already uses a GPU-native framework, optimize within that framework.
103+
2. Try accelerator or backend modes (`cudf.pandas`, `cuml.accel`, `nx-cugraph`).
104+
3. Move to a native GPU API only where accelerator coverage or performance is insufficient.
105+
4. Write a custom kernel only when profiling shows an operation without a suitable library
106+
implementation.
107+
108+
Read the relevant library reference before writing code; compatible names can still differ in
109+
defaults, dtypes, output types, and supported arguments.
110+
111+
### 4. Keep a coherent GPU data path
112+
113+
- Transfer inputs once and keep intermediates device-resident.
114+
- Reuse allocations and prefer `out=` or in-place forms when semantics allow.
115+
- Batch small operations; fuse elementwise work when it removes intermediate arrays.
116+
- Use pinned host memory and non-default streams only after profiling shows transfer overlap matters.
117+
- Choose `float32`, mixed precision, or reduced-precision storage only when the contract permits it.
118+
119+
### 5. Validate semantics before speed
120+
121+
- Compare CPU and GPU outputs on small deterministic fixtures and representative data.
122+
- Use explicit tolerances for floating-point results and test edge cases, NaNs, ordering, and dtypes.
123+
- For approximate nearest-neighbor indexes, report recall@k against exact search; do not compare an
124+
exact CPU algorithm with an approximate GPU algorithm as if they were equivalent.
125+
- Check accelerator warnings and logs for CPU fallback.
126+
127+
### 6. Benchmark GPU code correctly
128+
129+
GPU work is asynchronous, so a CPU timer around an unsynchronized call measures enqueue time.
130+
Warm up context creation and JIT compilation, then use CUDA events or a library-aware timer:
68131

69-
### 1. Profile First
70-
Before optimizing, understand where time is actually spent:
71132
```python
72-
import time
73-
# or use cProfile, line_profiler, or py-spy for detailed profiling
133+
from cupyx.profiler import benchmark
134+
135+
print(benchmark(gpu_function, (arg1, arg2), n_warmup=10, n_repeat=100))
74136
```
75-
Don't guess — measure. The bottleneck might not be where the user thinks.
76-
77-
### 2. Assess GPU Suitability
78-
Not all code benefits from GPU acceleration. GPU excels when:
79-
- **Data parallelism is high**: The same operation applies to thousands/millions of elements
80-
- **Compute intensity is high**: Many FLOPs per byte of memory accessed
81-
- **Data is large enough**: GPU overhead means small arrays (< ~10K elements) may be slower on GPU
82-
- **Memory fits**: Data must fit in GPU memory (typically 8-80 GB)
83-
84-
GPU is a poor fit when:
85-
- Data is tiny (< 10K elements)
86-
- Algorithm is inherently sequential with data dependencies between steps
87-
- Code is I/O bound (disk, network), not compute bound — though KvikIO with GPUDirect Storage can help when IO feeds GPU compute
88-
- Many small, heterogeneous operations (kernel launch overhead dominates)
89-
90-
### 3. Start Simple, Then Optimize
91-
1. **Try the drop-in replacement first.** CuPy for NumPy, cudf.pandas for pandas, cuml.accel for sklearn, nx-cugraph for NetworkX. This alone often gives 5-50x speedup.
92-
2. **Minimize host-device transfers.** Keep data on GPU. Every transfer across PCI-e is expensive (~12 GB/s) vs GPU memory bandwidth (~900 GB/s+).
93-
3. **Batch operations.** Fewer large GPU operations beat many small ones.
94-
4. **Only write custom kernels if needed.** CuPy and cuDF use NVIDIA's hand-tuned libraries. Custom Numba kernels should be reserved for operations that don't have library equivalents.
95-
5. **Profile the GPU version.** Use `nvprof`, `nsys`, or CuPy's built-in benchmarking.
96-
97-
### 4. Memory Management Principles
98-
These apply across all libraries:
99-
- **Pre-allocate output arrays** instead of creating new ones in loops
100-
- **Reuse GPU memory** — use memory pools (CuPy has this built-in)
101-
- **Use pinned (page-locked) host memory** for faster CPU-GPU transfers
102-
- **Avoid unnecessary copies** — use in-place operations where possible
103-
- **Stream operations** for overlapping compute and data transfer
104-
105-
### 5. Common Pitfalls to Watch For
106-
- **Implicit CPU fallback**: Some operations silently fall back to CPU. Watch for warnings.
107-
- **Synchronization overhead**: GPU operations are asynchronous. Calling `.get()` or `cp.asnumpy()` forces a sync.
108-
- **dtype mismatches**: Use `float32` instead of `float64` when precision allows — GPU float32 throughput is 2x-32x higher.
109-
- **Small kernel launches**: Each kernel launch has ~5-20us overhead. Fuse operations when possible.
137+
138+
Use `%gpu_timeit` in notebooks, Nsight Systems (`nsys`) for end-to-end timelines, and Nsight
139+
Compute (`ncu`) for kernel analysis. Report both synchronized kernel/region time and realistic
140+
end-to-end latency; include transfer and conversion costs when production pays them.
141+
142+
### 7. Keep, revise, or reject the port
143+
144+
Retain the GPU path only when it passes correctness checks and improves the metric the user cares
145+
about on representative data. If it does not, explain whether the limiting factor is problem size,
146+
transfers, unsupported fallback, memory pressure, launch granularity, or the algorithm itself.
110147

111148
## Important Notes
112149

113-
- Always handle the case where no GPU is available — provide a CPU fallback or clear error message
150+
- Provide a CPU fallback when the application requires portability; otherwise fail early with a
151+
clear hardware and dependency error.
114152
- Test numerical correctness against CPU results (GPU floating point may differ slightly due to operation ordering)
115153
- GPU memory is limited — for datasets larger than GPU memory, consider chunking or using RAPIDS Dask for multi-GPU
116-
- The CUDA Array Interface enables zero-copy sharing between CuPy, Numba, Warp, cuDF, cuML, cuGraph, cuVS, cuSpatial, KvikIO, PyTorch, and JAX arrays on GPU
154+
- Prefer the CUDA Array Interface or DLPack for supported zero-copy interchange, but verify device,
155+
dtype, contiguity, ownership, and stream semantics rather than assuming every conversion is free.
117156

118157
## Reference Files
119158

@@ -122,16 +161,16 @@ Before writing any GPU optimization code, read the relevant reference file(s):
122161
| File | When to Read |
123162
|------|-------------|
124163
| `references/cupy.md` | User has NumPy/SciPy code, or needs array operations on GPU |
125-
| `references/numba.md` | User needs custom CUDA kernels, fine-grained GPU control, or GPU ufuncs |
164+
| `references/numba.md` | User has existing Numba-CUDA code or needs explicit SIMT kernels; note the migration path to Numba-CUDA-MLIR |
126165
| `references/cudf.md` | User has pandas code, or needs dataframe operations on GPU |
127166
| `references/cuml.md` | User has scikit-learn code, or needs ML training/inference/preprocessing on GPU |
128167
| `references/cugraph.md` | User has NetworkX code, or needs graph analytics on GPU |
129-
| `references/warp.md` | User needs GPU simulation, spatial computing, mesh/volume queries, differentiable programming, or robotics |
168+
| `references/warp.md` | User needs GPU kernels for simulation, spatial computing, mesh/volume queries, differentiable programming, or robotics; use Newton for a high-level physics engine |
130169
| `references/kvikio.md` | User needs high-performance file IO to/from GPU, GPUDirect Storage, reading S3/HTTP to GPU, or Zarr on GPU |
131-
| `references/cuxfilter.md` | User wants GPU-accelerated interactive dashboards, cross-filtering, or EDA visualization (note: sunset — 26.06 is the final release) |
170+
| `references/cuxfilter.md` | User maintains or explicitly requests cuxfilter (sunset — 26.06 is the final release) |
132171
| `references/cucim.md` | User has scikit-image code, or needs image processing, digital pathology, or WSI reading on GPU |
133172
| `references/cuvs.md` | User needs vector search, nearest neighbors, similarity search, or RAG retrieval on GPU |
134-
| `references/cuspatial.md` | User has GeoPandas/shapely code, or needs spatial joins, distance calculations, or trajectory analysis on GPU (note: archived — frozen at 25.04) |
173+
| `references/cuspatial.md` | User maintains or explicitly requests cuSpatial (archived — frozen at 25.04 and isolated from current RAPIDS) |
135174
| `references/raft.md` | User needs sparse eigensolvers, device memory management, or multi-GPU primitives |
136175

137176
Read the specific reference before writing code — they contain detailed API patterns, optimization techniques, and pitfalls specific to each library.

0 commit comments

Comments
 (0)