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
1 change: 1 addition & 0 deletions benchmarks/cuda_pathfinder/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
results-*.json
6 changes: 6 additions & 0 deletions benchmarks/cuda_pathfinder/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# cuda.pathfinder benchmarks

Read the README.md in this directory for benchmark scope and usage.

Keep benchmark fixtures outside timed loops. Verify benchmark behavior against
the source in `../../cuda_pathfinder` and preserve support for Linux and Windows.
55 changes: 55 additions & 0 deletions benchmarks/cuda_pathfinder/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# cuda.pathfinder benchmarks

These benchmarks measure filesystem-discovery latency in `cuda.pathfinder`.
They exercise the in-tree source package and do not require a GPU or CUDA
Toolkit.

The suite uses temporary directory trees prepared before timing starts. It has
two levels of coverage:

- `find_sub_dirs.*` isolates the underlying filesystem mechanism with realistic
one-root and three-root cases, plus wildcard and cache diagnostics.
- `public_discovery.*` measures cold-cache calls through the public header,
binary, and static-library APIs. Fixtures use real NVIDIA wheel layouts such
as `nvidia/cuda_runtime/include` and `nvidia/cuda_nvcc/bin`.

The public cold-cache benchmarks clear pathfinder's process-lifetime caches on
each iteration. This intentionally models first use in a fresh process; the
small cache-clear cost is included in the reported time. Three roots represent
a virtual environment, user site-packages, and system site-packages, with the
target in the last root to measure the complete search order.

## Usage

Requires pixi. The `source` environment installs `cuda-pathfinder` from this
checkout and works on Linux and Windows.

```bash
# List benchmark IDs.
pixi run -e source bench --list

# Quick functional validation; timings are not meaningful.
pixi run -e source bench-smoke-test

# Run the full suite and write results-python.json.
pixi run -e source bench

# Reduce runtime while iterating.
pixi run -e source bench --min-time 0.1
```

## Comparing changes

Save results from the base revision and the modified checkout under distinct
names, then use pyperf's statistical comparison:

```bash
pixi run -e source bench -o results-before.json
pixi run -e source bench -o results-after.json
pixi run -e source -- python -m pyperf compare_to \
results-before.json results-after.json --table
```

For stable results, minimize other system activity and use the same machine,
Python version, and Pixi environment for both runs. See pyperf's system tuning
guidance: https://pyperf.readthedocs.io/en/latest/system.html#system
90 changes: 90 additions & 0 deletions benchmarks/cuda_pathfinder/benchmarks/bench_find_sub_dirs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# SPDX-License-Identifier: Apache-2.0

import atexit
import tempfile
import time
from pathlib import Path

from cuda.pathfinder._utils.find_sub_dirs import find_sub_dirs, find_sub_dirs_cached, find_sub_dirs_no_cache

_WILDCARD_CHILD_COUNT = 50
_SUB_DIRS = ("nvidia", "cuda_runtime", "lib")
_MISSING_SUB_DIRS = ("nvidia", "not_installed", "lib")

_TEMP_DIR = tempfile.TemporaryDirectory()
_ROOT = Path(_TEMP_DIR.name)
_PARENTS: tuple[str, ...] = tuple(str(_ROOT / f"environment-{index}") for index in range(3))

for parent in _PARENTS:
(Path(parent) / Path(*_SUB_DIRS)).mkdir(parents=True)

_WILDCARD_PARENT = _ROOT / "wildcard-environment"
for index in range(_WILDCARD_CHILD_COUNT):
(_WILDCARD_PARENT / "nvidia" / f"package-{index}" / "lib").mkdir(parents=True)

_WILDCARD_PARENTS = (str(_WILDCARD_PARENT),)
_WILDCARD_SUB_DIRS = ("nvidia", "*", "lib")

find_sub_dirs_cached.cache_clear()
find_sub_dirs(_PARENTS, _SUB_DIRS)


def bench_exact_hit_1_parent(loops: int) -> float:
_fn = find_sub_dirs_no_cache
_parents = _PARENTS[:1]
_sub_dirs = _SUB_DIRS

t0 = time.perf_counter()
for _ in range(loops):
_fn(_parents, _sub_dirs)
return time.perf_counter() - t0


def bench_exact_hit_3_parents(loops: int) -> float:
_fn = find_sub_dirs_no_cache
_parents = _PARENTS
_sub_dirs = _SUB_DIRS

t0 = time.perf_counter()
for _ in range(loops):
_fn(_parents, _sub_dirs)
return time.perf_counter() - t0


def bench_exact_miss_3_parents(loops: int) -> float:
_fn = find_sub_dirs_no_cache
_parents = _PARENTS
_sub_dirs = _MISSING_SUB_DIRS

t0 = time.perf_counter()
for _ in range(loops):
_fn(_parents, _sub_dirs)
return time.perf_counter() - t0


def bench_wildcard_hit_50_children(loops: int) -> float:
_fn = find_sub_dirs_no_cache
_parents = _WILDCARD_PARENTS
_sub_dirs = _WILDCARD_SUB_DIRS

t0 = time.perf_counter()
for _ in range(loops):
_fn(_parents, _sub_dirs)
return time.perf_counter() - t0


def bench_cached_exact_hit(loops: int) -> float:
_fn = find_sub_dirs
_parents = _PARENTS
_sub_dirs = _SUB_DIRS
_fn(_parents, _sub_dirs)

t0 = time.perf_counter()
for _ in range(loops):
_fn(_parents, _sub_dirs)
return time.perf_counter() - t0


atexit.register(_TEMP_DIR.cleanup)
139 changes: 139 additions & 0 deletions benchmarks/cuda_pathfinder/benchmarks/bench_public_discovery.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# SPDX-License-Identifier: Apache-2.0

import atexit
import os
import site
import tempfile
import time
from pathlib import Path

from cuda.pathfinder import find_nvidia_binary_utility, find_nvidia_header_directory, locate_static_lib
from cuda.pathfinder._headers.find_nvidia_headers import locate_nvidia_header_directory
from cuda.pathfinder._utils.find_sub_dirs import find_sub_dirs_cached
from cuda.pathfinder._utils.platform_aware import IS_WINDOWS

_TEMP_DIR = tempfile.TemporaryDirectory()
_ROOT = Path(_TEMP_DIR.name)
_SITE_ROOTS = tuple(_ROOT / f"site-root-{index}" for index in range(3))
for root in _SITE_ROOTS:
root.mkdir()

_PACKAGE_ROOT = _SITE_ROOTS[-1] / "nvidia"
_HEADER_DIR = _PACKAGE_ROOT / "cuda_runtime" / "include"
_HEADER_DIR.mkdir(parents=True)
(_HEADER_DIR / "cuda_runtime.h").touch()

_BINARY_DIR = _PACKAGE_ROOT / "cuda_nvcc" / "bin"
_BINARY_DIR.mkdir(parents=True)
_BINARY_NAME = "nvdisasm.exe" if IS_WINDOWS else "nvdisasm"
_BINARY_PATH = _BINARY_DIR / _BINARY_NAME
_BINARY_PATH.touch()
if not IS_WINDOWS:
_BINARY_PATH.chmod(0o755)

_STATIC_LIB_DIR = _PACKAGE_ROOT / "cuda_runtime" / "lib"
if IS_WINDOWS:
_STATIC_LIB_DIR /= "x64"
_STATIC_LIB_DIR.mkdir(parents=True)
_STATIC_LIB_NAME = "cudadevrt.lib" if IS_WINDOWS else "libcudadevrt.a"
(_STATIC_LIB_DIR / _STATIC_LIB_NAME).touch()

_ORIGINAL_GETSITEPACKAGES = site.getsitepackages
_ORIGINAL_ENABLE_USER_SITE = site.ENABLE_USER_SITE
_ACTIVE_SITE_ROOTS: tuple[Path, ...] = _SITE_ROOTS


def _getsitepackages() -> list[str]:
return [str(root) for root in _ACTIVE_SITE_ROOTS]


site.getsitepackages = _getsitepackages
site.ENABLE_USER_SITE = False


def _clear_discovery_caches() -> None:
find_sub_dirs_cached.cache_clear()
find_nvidia_binary_utility.cache_clear()
locate_nvidia_header_directory.cache_clear()


def _cleanup() -> None:
site.getsitepackages = _ORIGINAL_GETSITEPACKAGES
site.ENABLE_USER_SITE = _ORIGINAL_ENABLE_USER_SITE
_TEMP_DIR.cleanup()


def bench_header_cold_1_root(loops: int) -> float:
global _ACTIVE_SITE_ROOTS
_ACTIVE_SITE_ROOTS = _SITE_ROOTS[-1:]
_fn = find_nvidia_header_directory
_clear = _clear_discovery_caches

t0 = time.perf_counter()
for _ in range(loops):
_clear()
_fn("cudart")
return time.perf_counter() - t0


def bench_header_cold_3_roots(loops: int) -> float:
global _ACTIVE_SITE_ROOTS
_ACTIVE_SITE_ROOTS = _SITE_ROOTS
_fn = find_nvidia_header_directory
_clear = _clear_discovery_caches

t0 = time.perf_counter()
for _ in range(loops):
_clear()
_fn("cudart")
return time.perf_counter() - t0


def bench_binary_cold_1_root(loops: int) -> float:
global _ACTIVE_SITE_ROOTS
_ACTIVE_SITE_ROOTS = _SITE_ROOTS[-1:]
_fn = find_nvidia_binary_utility
_clear = _clear_discovery_caches

t0 = time.perf_counter()
for _ in range(loops):
_clear()
_fn("nvdisasm")
return time.perf_counter() - t0


def bench_binary_cold_3_roots(loops: int) -> float:
global _ACTIVE_SITE_ROOTS
_ACTIVE_SITE_ROOTS = _SITE_ROOTS
_fn = find_nvidia_binary_utility
_clear = _clear_discovery_caches

t0 = time.perf_counter()
for _ in range(loops):
_clear()
_fn("nvdisasm")
return time.perf_counter() - t0


def bench_static_lib_cold_3_roots(loops: int) -> float:
global _ACTIVE_SITE_ROOTS
_ACTIVE_SITE_ROOTS = _SITE_ROOTS
_fn = locate_static_lib
_clear = find_sub_dirs_cached.cache_clear

t0 = time.perf_counter()
for _ in range(loops):
_clear()
_fn("cudadevrt")
return time.perf_counter() - t0


_clear_discovery_caches()
assert find_nvidia_header_directory("cudart") == os.path.normpath(os.path.abspath(_HEADER_DIR))
assert find_nvidia_binary_utility("nvdisasm") == os.path.abspath(_BINARY_PATH)
assert locate_static_lib("cudadevrt").abs_path == os.path.join(os.path.abspath(_STATIC_LIB_DIR), _STATIC_LIB_NAME)
_clear_discovery_caches()

atexit.register(_cleanup)
Loading
Loading