feat(cccl): integrate missing CCCL directories — python/, ci/, .agent/, docs/, test/
Sparse-checkout from NVIDIA/cccl main branch to complete cccl_upstream: Added: - python/cuda_cccl/ (226 files) — Python bindings for device-level algorithms Critical for muh toolchain: cuda.compute.reduce_into, scan, radix_sort, etc. Includes 204 .py files with full test coverage for all 27 algorithms - ci/ (163 files) — Build/test infrastructure build_cub.sh, test_cub.sh, build_and_test_targets.sh, matrix.yaml Directly maps to our [INFRA-CI] and [INFRA-BUILD] items - .agent/skills/ (7 files) — NVIDIA's own agent skills for CCCL cccl-style/SKILL.md, cccl-test/SKILL.md, sass-diff/SKILL.md - docs/ (491 files) — Official CCCL documentation CI references, CMake guides, Python compute docs, libcudacxx PTX docs - test/ (12 files) — Top-level integration tests (cuda_smoke, stdpar) - Root configs: .clang-format, .clang-tidy, CONTRIBUTING.md, pyproject.toml - CLAUDE.md symlink → AGENTS.md (NVIDIA's standard) cccl_upstream now mirrors full NVIDIA/cccl structure: Before: 42M (cub + thrust + libcudacxx + cudax + c + examples + benchmarks) After: 53M (+python +ci +docs +.agent +test +configs) This completes the CCCL base needed for: - [muh-bench] items: ci/util/build_and_test_targets.sh for targeted builds - [CCCL-verify] items: python/cuda_cccl/tests/ as reference implementations - [CCCL-test] items: ci/test_cub.sh, ci/test_thrust.sh - Agent workflow: .agent/skills/ for consistent style and test patterns
This commit is contained in:
82
cccl_upstream/ci/bench/README.md
Normal file
82
cccl_upstream/ci/bench/README.md
Normal file
@@ -0,0 +1,82 @@
|
||||
# Benchmark Compare Scripts
|
||||
|
||||
This directory contains the scripts used by `.github/workflows/bench.yml` to compare benchmark results between two code states.
|
||||
|
||||
## Scripts
|
||||
|
||||
- `ci/bench/bench.sh`: CI-oriented wrapper that calls `ci/bench/compare_git_refs.sh`.
|
||||
- `ci/bench/compare_git_refs.sh`: checks out `<base-ref>` and `<test-ref>` in temporary worktrees, then forwards all remaining args to `ci/bench/compare_paths.sh`.
|
||||
- `ci/bench/compare_paths.sh`: configures/builds/runs CUB benchmarks and/or Python benchmarks in two source trees and runs comparison tools on produced JSON outputs.
|
||||
- `ci/bench/parse_bench_matrix.sh`: parses `ci/bench.yaml` and emits a dispatch matrix JSON object for `.github/workflows/bench.yml`.
|
||||
|
||||
## Usage
|
||||
|
||||
Compare CUB benchmarks between two refs:
|
||||
|
||||
```bash
|
||||
"./ci/bench/bench.sh" "origin/main" "HEAD" \
|
||||
--cub-filter "^cub\\.bench\\.copy\\.memcpy\\.base$"
|
||||
```
|
||||
|
||||
Compare Python benchmarks between two refs:
|
||||
|
||||
```bash
|
||||
"./ci/bench/bench.sh" "origin/main" "HEAD" \
|
||||
--python-filter "compute/reduce/sum\\.py"
|
||||
```
|
||||
|
||||
Run both CUB and Python benchmarks:
|
||||
|
||||
```bash
|
||||
"./ci/bench/bench.sh" \
|
||||
"origin/main" \
|
||||
"HEAD" \
|
||||
--arch "native" \
|
||||
--nvbench-args "..." \
|
||||
--cub-filter "^cub\\.bench\\.reduce\\..*$" \
|
||||
--python-filter "compute/reduce/sum\\.py"
|
||||
```
|
||||
|
||||
Compare already checked-out trees:
|
||||
|
||||
```bash
|
||||
"./ci/bench/compare_paths.sh" \
|
||||
"/path/to/base/cccl" \
|
||||
"/path/to/test/cccl" \
|
||||
--arch "native" \
|
||||
--cub-filter "^cub\\.bench\\.copy\\.memcpy\\.base$" \
|
||||
--python-filter "compute/transform/.*\\.py"
|
||||
```
|
||||
|
||||
## Workflow Inputs
|
||||
|
||||
In `.github/workflows/bench.yml`:
|
||||
|
||||
- If `raw_args` is non-empty, it is parsed and passed directly to `ci/bench/bench.sh`.
|
||||
- Otherwise, args are assembled from `base_ref`, `test_ref`, `arch`, `cub_filters`, `python_filters`, `nvbench_args`, and `nvbench_compare_args`.
|
||||
- CUB filters are passed as `--cub-filter` flags. Python filters are passed as `--python-filter` flags.
|
||||
- Malformed quoted input (for example unmatched quotes) fails the workflow step.
|
||||
|
||||
## Python Benchmarks
|
||||
|
||||
Python benchmarks live under `python/cuda_cccl/benchmarks/` and use `cuda.bench` (the Python nvbench bindings). Each benchmark script outputs nvbench-compatible JSON.
|
||||
|
||||
For Python benchmarks, `compare_paths.sh`:
|
||||
|
||||
1. Creates isolated virtual environments for base and test trees.
|
||||
2. Installs `cuda-cccl[bench-cuXX]` (editable, from each worktree), which pulls in `cuda-bench`, `cupy`, and all other benchmark dependencies.
|
||||
3. Runs matching benchmark scripts in each venv.
|
||||
4. Compares results using `nvbench-compare` (installed with `cuda-bench`).
|
||||
|
||||
Python filters are regex patterns matched against relative paths under `python/cuda_cccl/benchmarks/`, for example:
|
||||
- `compute/reduce/sum\.py` — single benchmark
|
||||
- `compute/transform/.*\.py` — all transform benchmarks
|
||||
|
||||
## Artifacts
|
||||
|
||||
`compare_paths.sh` writes a run directory under `${CCCL_BENCH_ARTIFACT_ROOT:-$(pwd)/bench-artifacts}` containing:
|
||||
|
||||
- per-target JSON and markdown outputs for base/test runs,
|
||||
- grouped build logs (`build.base.log`, `build.test.log`), per-target run logs, and per-target compare logs (`compare.<target>.log`),
|
||||
- Python venv setup logs (`py.venv.base.log`, `py.venv.test.log`),
|
||||
- `summary.md` with run metadata and per-target collapsible full compare reports.
|
||||
26
cccl_upstream/ci/bench/bench.sh
Executable file
26
cccl_upstream/ci/bench/bench.sh
Executable file
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
die() {
|
||||
local message="$1"
|
||||
local code="${2:-2}"
|
||||
echo "${message}" >&2
|
||||
exit "${code}"
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
Usage: $0 <base-ref> <test-ref> [compare_paths args...]
|
||||
|
||||
Wrapper for ci/bench/compare_git_refs.sh.
|
||||
EOF
|
||||
}
|
||||
|
||||
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
|
||||
usage
|
||||
exit 0
|
||||
fi
|
||||
|
||||
bench_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
"${bench_dir}/compare_git_refs.sh" "$@"
|
||||
137
cccl_upstream/ci/bench/compare_git_refs.sh
Executable file
137
cccl_upstream/ci/bench/compare_git_refs.sh
Executable file
@@ -0,0 +1,137 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
die() {
|
||||
local message="$1"
|
||||
local code="${2:-2}"
|
||||
echo "${message}" >&2
|
||||
exit "${code}"
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
Usage: $0 <base-ref> <test-ref> [compare_paths args...]
|
||||
|
||||
Compare benchmark performance between two git refs from the current CCCL repo.
|
||||
Each ref is checked out in an isolated worktree and compared via compare_paths.sh.
|
||||
EOF
|
||||
}
|
||||
|
||||
display_label_for_ref() {
|
||||
local ref="$1"
|
||||
local short_sha="$2"
|
||||
if [[ "${ref}" =~ ^[0-9a-fA-F]{7,40}$ ]]; then
|
||||
printf "%s" "${short_sha}"
|
||||
return 0
|
||||
fi
|
||||
if [[ "${ref}" == "HEAD" ]]; then
|
||||
printf "%s" "${short_sha}"
|
||||
return 0
|
||||
fi
|
||||
printf "%s" "${ref}"
|
||||
}
|
||||
|
||||
resolve_ref_to_commit() {
|
||||
local repo_root="$1"
|
||||
local ref="$2"
|
||||
local remote=""
|
||||
local branch=""
|
||||
local alternate_ref=""
|
||||
|
||||
if git -C "${repo_root}" rev-parse --verify "${ref}^{commit}" >/dev/null 2>&1; then
|
||||
git -C "${repo_root}" rev-parse --verify "${ref}^{commit}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ "${ref}" =~ ^([^/]+)/(.+)$ ]] && git -C "${repo_root}" remote get-url "${BASH_REMATCH[1]}" >/dev/null 2>&1; then
|
||||
remote="${BASH_REMATCH[1]}"
|
||||
branch="${BASH_REMATCH[2]}"
|
||||
git -C "${repo_root}" fetch --no-tags "${remote}" \
|
||||
"+refs/heads/${branch}:refs/remotes/${remote}/${branch}" >/dev/null 2>&1 || true
|
||||
elif [[ "${ref}" != refs/* ]]; then
|
||||
# Try unqualified refs as origin branches/tags.
|
||||
git -C "${repo_root}" fetch --no-tags origin \
|
||||
"+refs/heads/${ref}:refs/remotes/origin/${ref}" >/dev/null 2>&1 || true
|
||||
git -C "${repo_root}" fetch --no-tags origin \
|
||||
"refs/tags/${ref}:refs/tags/${ref}" >/dev/null 2>&1 || true
|
||||
alternate_ref="origin/${ref}"
|
||||
fi
|
||||
|
||||
# Final best-effort fetch for raw refs (e.g. refs/pull/* or specific SHAs).
|
||||
git -C "${repo_root}" fetch --no-tags origin "${ref}" >/dev/null 2>&1 || true
|
||||
|
||||
if git -C "${repo_root}" rev-parse --verify "${ref}^{commit}" >/dev/null 2>&1; then
|
||||
git -C "${repo_root}" rev-parse --verify "${ref}^{commit}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ -n "${alternate_ref}" ]] && git -C "${repo_root}" rev-parse --verify "${alternate_ref}^{commit}" >/dev/null 2>&1; then
|
||||
git -C "${repo_root}" rev-parse --verify "${alternate_ref}^{commit}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
|
||||
usage
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "$#" -lt 2 ]]; then
|
||||
usage
|
||||
exit 2
|
||||
fi
|
||||
|
||||
base_ref="$1"
|
||||
test_ref="$2"
|
||||
shift 2
|
||||
compare_paths_args=("$@")
|
||||
|
||||
ci_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
repo_root="$(cd "${ci_dir}/../.." && pwd)"
|
||||
|
||||
if [[ ! -f "${repo_root}/cccl-version.json" ]]; then
|
||||
die "This script must run from a CCCL checkout."
|
||||
fi
|
||||
|
||||
if ! base_commit="$(resolve_ref_to_commit "${repo_root}" "${base_ref}")"; then
|
||||
die "Unable to resolve base ref: ${base_ref}"
|
||||
fi
|
||||
if ! test_commit="$(resolve_ref_to_commit "${repo_root}" "${test_ref}")"; then
|
||||
die "Unable to resolve test ref: ${test_ref}"
|
||||
fi
|
||||
|
||||
base_short_sha="$(git -C "${repo_root}" rev-parse --short=12 "${base_commit}")"
|
||||
test_short_sha="$(git -C "${repo_root}" rev-parse --short=12 "${test_commit}")"
|
||||
base_label="$(display_label_for_ref "${base_ref}" "${base_short_sha}")"
|
||||
test_label="$(display_label_for_ref "${test_ref}" "${test_short_sha}")"
|
||||
|
||||
worktree_root="$(mktemp -d "/tmp/cccl-bench-worktrees-XXXXXX")"
|
||||
base_path="${worktree_root}/base"
|
||||
test_path="${worktree_root}/test"
|
||||
|
||||
cleanup() {
|
||||
git -C "${repo_root}" worktree remove --force "${base_path}" >/dev/null 2>&1 || true
|
||||
git -C "${repo_root}" worktree remove --force "${test_path}" >/dev/null 2>&1 || true
|
||||
rm -rf "${worktree_root}"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
echo "Creating worktree for base ref: ${base_ref}"
|
||||
git -C "${repo_root}" worktree add --detach "${base_path}" "${base_commit}" >/dev/null
|
||||
|
||||
echo "Creating worktree for test ref: ${test_ref}"
|
||||
git -C "${repo_root}" worktree add --detach "${test_path}" "${test_commit}" >/dev/null
|
||||
|
||||
compare_cmd=(
|
||||
"${ci_dir}/compare_paths.sh"
|
||||
"${base_path}"
|
||||
"${test_path}"
|
||||
"${compare_paths_args[@]}"
|
||||
)
|
||||
|
||||
CCCL_BENCH_BASE_LABEL="${base_label}" \
|
||||
CCCL_BENCH_TEST_LABEL="${test_label}" \
|
||||
"${compare_cmd[@]}"
|
||||
1048
cccl_upstream/ci/bench/compare_paths.sh
Executable file
1048
cccl_upstream/ci/bench/compare_paths.sh
Executable file
File diff suppressed because it is too large
Load Diff
80
cccl_upstream/ci/bench/parse_bench_matrix.sh
Executable file
80
cccl_upstream/ci/bench/parse_bench_matrix.sh
Executable file
@@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
die() {
|
||||
local message="$1"
|
||||
local code="${2:-2}"
|
||||
echo "${message}" >&2
|
||||
exit "${code}"
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
Usage: $0 [bench-yaml-path]
|
||||
|
||||
Parse ci/bench.yaml and emit a GitHub Actions strategy matrix JSON object:
|
||||
{"include":[...]}
|
||||
|
||||
Each include entry maps one enabled GPU to a benchmark workflow invocation.
|
||||
EOF
|
||||
}
|
||||
|
||||
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
|
||||
usage
|
||||
exit 0
|
||||
fi
|
||||
|
||||
bench_yaml_path="${1:-ci/bench.yaml}"
|
||||
if [[ ! -f "${bench_yaml_path}" ]]; then
|
||||
die "Benchmark config file not found: ${bench_yaml_path}"
|
||||
fi
|
||||
|
||||
command -v "yq" >/dev/null 2>&1 || die "'yq' is required to parse ${bench_yaml_path}."
|
||||
command -v "jq" >/dev/null 2>&1 || die "'jq' is required to build the dispatch matrix."
|
||||
|
||||
if ! bench_cfg_json="$(yq -o=json '.benchmarks // {}' "${bench_yaml_path}" 2>&1)"; then
|
||||
die "Failed to parse ${bench_yaml_path} as YAML: ${bench_cfg_json}"
|
||||
fi
|
||||
|
||||
# Extract CUB and Python filter arrays (default to empty arrays).
|
||||
cub_filters_json="$(jq -c '.filters.cub // []' <<<"${bench_cfg_json}")"
|
||||
python_filters_json="$(jq -c '.filters.python // []' <<<"${bench_cfg_json}")"
|
||||
|
||||
has_cub_filters="$(jq -e 'type == "array" and length > 0 and all(.[]; type == "string")' <<<"${cub_filters_json}" >/dev/null 2>&1 && echo true || echo false)"
|
||||
has_python_filters="$(jq -e 'type == "array" and length > 0 and all(.[]; type == "string")' <<<"${python_filters_json}" >/dev/null 2>&1 && echo true || echo false)"
|
||||
|
||||
if [[ "${has_cub_filters}" != "true" && "${has_python_filters}" != "true" ]]; then
|
||||
die "${bench_yaml_path} must define at least one string entry in benchmarks.filters.cub or benchmarks.filters.python."
|
||||
fi
|
||||
|
||||
cub_filters_arg=""
|
||||
if [[ "${has_cub_filters}" == "true" ]]; then
|
||||
cub_filters_arg="$(jq -r '.filters.cub | map(@sh) | join(" ")' <<<"${bench_cfg_json}")"
|
||||
fi
|
||||
|
||||
python_filters_arg=""
|
||||
if [[ "${has_python_filters}" == "true" ]]; then
|
||||
python_filters_arg="$(jq -r '.filters.python | map(@sh) | join(" ")' <<<"${bench_cfg_json}")"
|
||||
fi
|
||||
|
||||
jq -cn \
|
||||
--argjson cfg "${bench_cfg_json}" \
|
||||
--arg cub_filters "${cub_filters_arg}" \
|
||||
--arg python_filters "${python_filters_arg}" \
|
||||
'{
|
||||
"include": [
|
||||
($cfg.gpus // [])[] as $gpu
|
||||
| {
|
||||
"gpu": $gpu,
|
||||
"launch_args": ($cfg.launch_args // ""),
|
||||
"arch": ($cfg.arch // "native"),
|
||||
"base_ref": ($cfg.base_ref // "origin/main"),
|
||||
"test_ref": ($cfg.test_ref // "HEAD"),
|
||||
"cub_filters": $cub_filters,
|
||||
"python_filters": $python_filters,
|
||||
"nvbench_args": ($cfg.nvbench_args // ""),
|
||||
"nvbench_compare_args": ($cfg.nvbench_compare_args // "")
|
||||
}
|
||||
]
|
||||
}'
|
||||
Reference in New Issue
Block a user