Skip to content

Commit

Permalink
introduce libcuvs wheels (#594)
Browse files Browse the repository at this point in the history
Contributes to rapidsai/build-planning#33.

Proposes packaging `libcuvs` as a wheel, which is then re-used by `cuvs-cu{11,12}`.

Similar changes were recently made in RAFT: rapidsai/raft#2531

As part of this, also proposes:

* introducing a new CMake option, `CUVS_COMPILE_DYNAMIC_ONLY`, to allow building/installing only the dynamic shared library (i.e. skipping the static library)
* enforcing `rapids-cmake`'s preferred CMake style (similar rapidsai/raft#2531 (comment))
* standardizing `clang` pins across the project, and pinning to `clang` 16 for Rust builds (#594 (comment))

## Notes for Reviewers

### Benefits of these changes

* smaller wheels for projects that depend on cuVS (they can dynamically link against `libcuvs` instead of statically linking in the pieces they need)
* fewer CI resources used for cuVS wheels (no more re-compiling for every Python minor version)
* faster, cheaper cuML wheel builds (rapidsai/cuml#6199 (comment))
* other benefits mentioned in rapidsai/build-planning#33

### Wheel contents

`libcuvs`:

* `libcuvs.so` and `libcuvs_c.so` (shared library)
* cuVS headers
* vendored dependencies (hnswlib)

`cuvs`:

* `cuvs` Python / Cython code and compiled Cython extensions

### Size changes (CUDA 12, Python 3.12, x86_64)

| wheel                | num files (before) | num files (this PR) | size (before)  | size (this PR) |
|:---------------:|------------------:|-----------------:|--------------:|---------------:|
| `libcuvs`          |   ---                        |  67                        | ---                   | 843M               |
| `cuvs`              | 88                          |   84                       |845M               | 2M                    |
|**TOTAL**          |   **88**                |   **131**                 | **845M**       | **845M**         |

*NOTES: size = compressed, "before" = 2025-01-22 nightlies*

<details><summary>how I calculated those (click me)</summary>

* nightly commit = rapidsai/cuml@7c715c4
* PR = this PR

```shell
docker run \
    --rm \
    --network host \
    --env RAPIDS_NIGHTLY_DATE=2025-01-22 \
    --env CUVS_NIGHTLY_SHA=f1de1b2 \
    --env CUVS_PR="pull-request/594" \
    --env CUVS_PR_SHA="97c56178cd0e07e4b6b138bb0904af78379f1bb3" \
    --env RAPIDS_PY_CUDA_SUFFIX=cu12 \
    --env WHEEL_DIR_BEFORE=/tmp/wheels-before \
    --env WHEEL_DIR_AFTER=/tmp/wheels-after \
    -it rapidsai/ci-wheel:cuda12.5.1-rockylinux8-py3.12 \
    bash

# --- nightly wheels --- #
mkdir -p ./wheels-before

export RAPIDS_BUILD_TYPE=branch
export RAPIDS_REF_NAME="branch-25.02"

# cuvs
RAPIDS_PY_WHEEL_NAME="cuvs_${RAPIDS_PY_CUDA_SUFFIX}" \
RAPIDS_REPOSITORY=rapidsai/cuvs \
RAPIDS_SHA=${CUVS_NIGHTLY_SHA} \
    rapids-download-wheels-from-s3 python ./wheels-before

# --- wheels from CI --- #
mkdir -p ./wheels-after

export RAPIDS_BUILD_TYPE="pull-request"

# libcuvs
RAPIDS_PY_WHEEL_NAME="libcuvs_${RAPIDS_PY_CUDA_SUFFIX}" \
RAPIDS_REPOSITORY=rapidsai/cuvs \
RAPIDS_REF_NAME="${CUVS_PR}" \
RAPIDS_SHA="${CUVS_PR_SHA}" \
    rapids-download-wheels-from-s3 cpp ./wheels-after

# cuvs
RAPIDS_PY_WHEEL_NAME="cuvs_${RAPIDS_PY_CUDA_SUFFIX}" \
RAPIDS_REPOSITORY=rapidsai/cuvs \
RAPIDS_REF_NAME="${CUVS_PR}" \
RAPIDS_SHA="${CUVS_PR_SHA}" \
    rapids-download-wheels-from-s3 python ./wheels-after

pip install pydistcheck
pydistcheck \
    --inspect \
    --select 'distro-too-large-compressed' \
    ./wheels-before/*.whl \
| grep -E '^checking|files: | compressed' \
> ./before.txt

# get more exact sizes
du -sh ./wheels-before/*

pydistcheck \
    --inspect \
    --select 'distro-too-large-compressed' \
    ./wheels-after/*.whl \
| grep -E '^checking|files: | compressed' \
> ./after.txt

# get more exact sizes
du -sh ./wheels-after/*
```

</details>

### How I tested this

* rapidsai/devcontainers#440
* rapidsai/cuml#6199

Authors:
  - James Lamb (https://github.com/jameslamb)

Approvers:
  - Bradley Dice (https://github.com/bdice)
  - Ben Frederickson (https://github.com/benfred)

URL: #594
  • Loading branch information
jameslamb authored Jan 23, 2025
1 parent 1c91e1f commit b62b11a
Show file tree
Hide file tree
Showing 43 changed files with 653 additions and 204 deletions.
24 changes: 24 additions & 0 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,30 @@ jobs:
node_type: "gpu-v100-latest-1"
run_script: "ci/build_docs.sh"
sha: ${{ inputs.sha }}
wheel-build-libcuvs:
secrets: inherit
uses: rapidsai/shared-workflows/.github/workflows/[email protected]
with:
build_type: ${{ inputs.build_type || 'branch' }}
branch: ${{ inputs.branch }}
sha: ${{ inputs.sha }}
date: ${{ inputs.date }}
script: ci/build_wheel_libcuvs.sh
# build for every combination of arch and CUDA version, but only for the latest Python
matrix_filter: group_by([.ARCH, (.CUDA_VER|split(".")|map(tonumber)|.[0])]) | map(max_by(.PY_VER|split(".")|map(tonumber)))
wheel-publish-libcuvs:
needs: wheel-build-libcuvs
secrets: inherit
uses: rapidsai/shared-workflows/.github/workflows/[email protected]
with:
build_type: ${{ inputs.build_type || 'branch' }}
branch: ${{ inputs.branch }}
sha: ${{ inputs.sha }}
date: ${{ inputs.date }}
package-name: libcuvs
package-type: cpp
wheel-build-cuvs:
needs: wheel-build-libcuvs
secrets: inherit
uses: rapidsai/shared-workflows/.github/workflows/[email protected]
with:
Expand All @@ -99,3 +122,4 @@ jobs:
sha: ${{ inputs.sha }}
date: ${{ inputs.date }}
package-name: cuvs
package-type: python
12 changes: 11 additions & 1 deletion .github/workflows/pr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ jobs:
- conda-python-tests
- docs-build
- rust-build
- wheel-build-libcuvs
- wheel-build-cuvs
- wheel-tests-cuvs
- devcontainer
Expand Down Expand Up @@ -135,10 +136,19 @@ jobs:
arch: "amd64"
container_image: "rapidsai/ci-conda:latest"
run_script: "ci/build_rust.sh"
wheel-build-cuvs:
wheel-build-libcuvs:
needs: checks
secrets: inherit
uses: rapidsai/shared-workflows/.github/workflows/[email protected]
with:
build_type: pull-request
script: ci/build_wheel_libcuvs.sh
# build for every combination of arch and CUDA version, but only for the latest Python
matrix_filter: group_by([.ARCH, (.CUDA_VER|split(".")|map(tonumber)|.[0])]) | map(max_by(.PY_VER|split(".")|map(tonumber)))
wheel-build-cuvs:
needs: wheel-build-libcuvs
secrets: inherit
uses: rapidsai/shared-workflows/.github/workflows/[email protected]
with:
build_type: pull-request
script: ci/build_wheel_cuvs.sh
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ repos:
cpp/cmake/modules/FindAVX\.cmake|
- id: verify-alpha-spec
- repo: https://github.com/rapidsai/dependency-file-generator
rev: v1.16.0
rev: v1.17.0
hooks:
- id: rapids-dependency-file-generator
args: ["--clean"]
Expand Down
8 changes: 1 addition & 7 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -313,12 +313,6 @@ if [[ ${CMAKE_TARGET} == "" ]]; then
CMAKE_TARGET="all"
fi


SKBUILD_EXTRA_CMAKE_ARGS="${EXTRA_CMAKE_ARGS}"
if [[ "${EXTRA_CMAKE_ARGS}" != *"DFIND_CUVS_CPP"* ]]; then
SKBUILD_EXTRA_CMAKE_ARGS="${SKBUILD_EXTRA_CMAKE_ARGS};-DFIND_CUVS_CPP=ON"
fi

# If clean given, run it prior to any other steps
if (( ${CLEAN} == 1 )); then
# If the dirs to clean are mounted dirs in a container, the
Expand Down Expand Up @@ -434,7 +428,7 @@ fi

# Build and (optionally) install the cuvs Python package
if (( ${NUMARGS} == 0 )) || hasArg python; then
SKBUILD_CMAKE_ARGS="${SKBUILD_EXTRA_CMAKE_ARGS}" \
SKBUILD_CMAKE_ARGS="${EXTRA_CMAKE_ARGS}" \
SKBUILD_BUILD_OPTIONS="-j${PARALLEL_LEVEL}" \
python -m pip install --no-build-isolation --no-deps --config-settings rapidsai.disable-cuda=true ${REPODIR}/python/cuvs
fi
Expand Down
34 changes: 18 additions & 16 deletions ci/build_wheel.sh
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
#!/bin/bash
# Copyright (c) 2023-2024, NVIDIA CORPORATION.
# Copyright (c) 2023-2025, NVIDIA CORPORATION.

set -euo pipefail

package_name=$1
package_dir=$2
package_type=$3
underscore_package_name=$(echo "${package_name}" | tr "-" "_")

source rapids-configure-sccache
Expand All @@ -16,21 +17,22 @@ rapids-generate-version > ./VERSION

cd "${package_dir}"

case "${RAPIDS_CUDA_VERSION}" in
12.*)
EXCLUDE_ARGS=(
--exclude "libcublas.so.12"
--exclude "libcublasLt.so.12"
--exclude "libcurand.so.10"
--exclude "libcusolver.so.11"
--exclude "libcusparse.so.12"
--exclude "libnvJitLink.so.12"
EXCLUDE_ARGS=(
--exclude "libraft.so"
--exclude "libcublas.so.*"
--exclude "libcublasLt.so.*"
--exclude "libcurand.so.*"
--exclude "libcusolver.so.*"
--exclude "libcusparse.so.*"
--exclude "libnvJitLink.so.*"
)

if [[ "${package_dir}" != "python/libcuvs" ]]; then
EXCLUDE_ARGS+=(
--exclude "libcuvs_c.so"
--exclude "libcuvs.so"
)
;;
11.*)
EXCLUDE_ARGS=()
;;
esac
fi

rapids-logger "Building '${package_name}' wheel"

Expand All @@ -48,4 +50,4 @@ sccache --show-adv-stats
mkdir -p final_dist
python -m auditwheel repair -w final_dist "${EXCLUDE_ARGS[@]}" dist/*

RAPIDS_PY_WHEEL_NAME="${underscore_package_name}_${RAPIDS_PY_CUDA_SUFFIX}" rapids-upload-wheels-to-s3 python final_dist
RAPIDS_PY_WHEEL_NAME="${underscore_package_name}_${RAPIDS_PY_CUDA_SUFFIX}" rapids-upload-wheels-to-s3 ${package_type} final_dist
23 changes: 11 additions & 12 deletions ci/build_wheel_cuvs.sh
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
#!/bin/bash
# Copyright (c) 2023-2024, NVIDIA CORPORATION.
# Copyright (c) 2023-2025, NVIDIA CORPORATION.

set -euo pipefail

package_dir="python/cuvs"

case "${RAPIDS_CUDA_VERSION}" in
12.*)
EXTRA_CMAKE_ARGS=";-DUSE_CUDA_MATH_WHEELS=ON"
;;
11.*)
EXTRA_CMAKE_ARGS=";-DUSE_CUDA_MATH_WHEELS=OFF"
;;
esac
RAPIDS_PY_CUDA_SUFFIX="$(rapids-wheel-ctk-name-gen ${RAPIDS_CUDA_VERSION})"

# Set up skbuild options. Enable sccache in skbuild config options
export SKBUILD_CMAKE_ARGS="-DDETECT_CONDA_ENV=OFF;-DFIND_CUVS_CPP=OFF${EXTRA_CMAKE_ARGS}"
# Downloads libcuvs wheels from this current build,
# then ensures 'cuvs' wheel builds always use the 'libcuvs' just built in the same CI run.
#
# Using env variable PIP_CONSTRAINT is necessary to ensure the constraints
# are used when creating the isolated build environment.
RAPIDS_PY_WHEEL_NAME="libcuvs_${RAPIDS_PY_CUDA_SUFFIX}" rapids-download-wheels-from-s3 cpp /tmp/libcuvs_dist
echo "libcuvs-${RAPIDS_PY_CUDA_SUFFIX} @ file://$(echo /tmp/libcuvs_dist/libcuvs_*.whl)" > /tmp/constraints.txt
export PIP_CONSTRAINT="/tmp/constraints.txt"

ci/build_wheel.sh cuvs ${package_dir}
ci/build_wheel.sh cuvs ${package_dir} python
ci/validate_wheel.sh ${package_dir} final_dist
32 changes: 32 additions & 0 deletions ci/build_wheel_libcuvs.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/bin/bash
# Copyright (c) 2025, NVIDIA CORPORATION.

set -euo pipefail

package_name="libcuvs"
package_dir="python/libcuvs"

rapids-logger "Generating build requirements"
matrix_selectors="cuda=${RAPIDS_CUDA_VERSION%.*};arch=$(arch);py=${RAPIDS_PY_VERSION};cuda_suffixed=true"

rapids-dependency-file-generator \
--output requirements \
--file-key "py_build_${package_name}" \
--file-key "py_rapids_build_${package_name}" \
--matrix "${matrix_selectors}" \
| tee /tmp/requirements-build.txt

rapids-logger "Installing build requirements"
python -m pip install \
-v \
--prefer-binary \
-r /tmp/requirements-build.txt

# build with '--no-build-isolation', for better sccache hit rate
# 0 really means "add --no-build-isolation" (ref: https://github.com/pypa/pip/issues/5735)
export PIP_NO_BUILD_ISOLATION=0

RAPIDS_PY_CUDA_SUFFIX="$(rapids-wheel-ctk-name-gen ${RAPIDS_CUDA_VERSION})"

ci/build_wheel.sh libcuvs ${package_dir} cpp
ci/validate_wheel.sh ${package_dir} final_dist libcuvs
7 changes: 7 additions & 0 deletions ci/check_style.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,12 @@ rapids-dependency-file-generator \
rapids-mamba-retry env create --yes -f env.yaml -n checks
conda activate checks

# get config for cmake-format checks
RAPIDS_VERSION_MAJOR_MINOR="$(rapids-version-major-minor)"
FORMAT_FILE_URL="https://raw.githubusercontent.com/rapidsai/rapids-cmake/branch-${RAPIDS_VERSION_MAJOR_MINOR}/cmake-format-rapids-cmake.json"
export RAPIDS_CMAKE_FORMAT_FILE=/tmp/rapids_cmake_ci/cmake-formats-rapids-cmake.json
mkdir -p $(dirname ${RAPIDS_CMAKE_FORMAT_FILE})
wget -O ${RAPIDS_CMAKE_FORMAT_FILE} ${FORMAT_FILE_URL}

# Run pre-commit checks
pre-commit run --all-files --show-diff-on-failure
4 changes: 3 additions & 1 deletion ci/release/update-version.sh
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,10 @@ echo "${NEXT_FULL_TAG}" > VERSION
DEPENDENCIES=(
dask-cuda
cuvs
pylibraft
libcuvs
libraft
librmm
pylibraft
rmm
rapids-dask-dependency
)
Expand Down
9 changes: 6 additions & 3 deletions ci/test_wheel_cuvs.sh
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
#!/bin/bash
# Copyright (c) 2023-2024, NVIDIA CORPORATION.
# Copyright (c) 2023-2025, NVIDIA CORPORATION.

set -euo pipefail

mkdir -p ./dist
RAPIDS_PY_CUDA_SUFFIX="$(rapids-wheel-ctk-name-gen ${RAPIDS_CUDA_VERSION})"
RAPIDS_PY_WHEEL_NAME="cuvs_${RAPIDS_PY_CUDA_SUFFIX}" rapids-download-wheels-from-s3 ./dist
RAPIDS_PY_WHEEL_NAME="libcuvs_${RAPIDS_PY_CUDA_SUFFIX}" rapids-download-wheels-from-s3 cpp ./local-libcuvs-dep
RAPIDS_PY_WHEEL_NAME="cuvs_${RAPIDS_PY_CUDA_SUFFIX}" rapids-download-wheels-from-s3 python ./dist

# echo to expand wildcard before adding `[extra]` requires for pip
python -m pip install $(echo ./dist/cuvs*.whl)[test]
python -m pip install \
./local-libcuvs-dep/libcuvs*.whl \
"$(echo ./dist/cuvs*.whl)[test]"

python -m pytest ./python/cuvs/cuvs/test
12 changes: 0 additions & 12 deletions ci/validate_wheel.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,12 @@ wheel_dir_relative_path=$2

RAPIDS_CUDA_MAJOR="${RAPIDS_CUDA_VERSION%%.*}"

# some packages are much larger on CUDA 11 than on CUDA 12
if [[ "${RAPIDS_CUDA_MAJOR}" == "11" ]]; then
PYDISTCHECK_ARGS=(
--max-allowed-size-compressed '1.4G'
)
else
PYDISTCHECK_ARGS=(
--max-allowed-size-compressed '950M'
)
fi

cd "${package_dir}"

rapids-logger "validate packages with 'pydistcheck'"

pydistcheck \
--inspect \
"${PYDISTCHECK_ARGS[@]}" \
"$(echo ${wheel_dir_relative_path}/*.whl)"

rapids-logger "validate packages with 'twine'"
Expand Down
5 changes: 2 additions & 3 deletions conda/environments/all_cuda-118_arch-aarch64.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ channels:
dependencies:
- breathe>=4.35.0
- c-compiler
- clang
- clang-tools=16.0.6
- clang-tools==16.0.6
- clang==16.0.6
- cmake>=3.26.4,!=3.30.0
- cuda-nvtx=11.8
Expand All @@ -26,7 +25,7 @@ dependencies:
- gcc_linux-aarch64=11.*
- graphviz
- ipython
- libclang
- libclang==16.0.6
- libcublas-dev=11.11.3.6
- libcublas=11.11.3.6
- libcurand-dev=10.3.0.86
Expand Down
5 changes: 2 additions & 3 deletions conda/environments/all_cuda-118_arch-x86_64.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ channels:
dependencies:
- breathe>=4.35.0
- c-compiler
- clang
- clang-tools=16.0.6
- clang-tools==16.0.6
- clang==16.0.6
- cmake>=3.26.4,!=3.30.0
- cuda-nvtx=11.8
Expand All @@ -26,7 +25,7 @@ dependencies:
- gcc_linux-64=11.*
- graphviz
- ipython
- libclang
- libclang==16.0.6
- libcublas-dev=11.11.3.6
- libcublas=11.11.3.6
- libcurand-dev=10.3.0.86
Expand Down
5 changes: 2 additions & 3 deletions conda/environments/all_cuda-125_arch-aarch64.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ channels:
dependencies:
- breathe>=4.35.0
- c-compiler
- clang
- clang-tools=16.0.6
- clang-tools==16.0.6
- clang==16.0.6
- cmake>=3.26.4,!=3.30.0
- cuda-cudart-dev
Expand All @@ -27,7 +26,7 @@ dependencies:
- gcc_linux-aarch64=13.*
- graphviz
- ipython
- libclang
- libclang==16.0.6
- libcublas-dev
- libcurand-dev
- libcusolver-dev
Expand Down
5 changes: 2 additions & 3 deletions conda/environments/all_cuda-125_arch-x86_64.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ channels:
dependencies:
- breathe>=4.35.0
- c-compiler
- clang
- clang-tools=16.0.6
- clang-tools==16.0.6
- clang==16.0.6
- cmake>=3.26.4,!=3.30.0
- cuda-cudart-dev
Expand All @@ -27,7 +26,7 @@ dependencies:
- gcc_linux-64=13.*
- graphviz
- ipython
- libclang
- libclang==16.0.6
- libcublas-dev
- libcurand-dev
- libcusolver-dev
Expand Down
3 changes: 2 additions & 1 deletion conda/environments/bench_ann_cuda-118_arch-aarch64.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ channels:
dependencies:
- benchmark>=1.8.2
- c-compiler
- clang-tools=16.0.6
- clang-tools==16.0.6
- clang==16.0.6
- click
- cmake>=3.26.4,!=3.30.0
Expand All @@ -26,6 +26,7 @@ dependencies:
- gcc_linux-aarch64=11.*
- glog>=0.6.0
- h5py>=3.8.0
- libclang==16.0.6
- libcublas-dev=11.11.3.6
- libcublas=11.11.3.6
- libcurand-dev=10.3.0.86
Expand Down
3 changes: 2 additions & 1 deletion conda/environments/bench_ann_cuda-118_arch-x86_64.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ channels:
dependencies:
- benchmark>=1.8.2
- c-compiler
- clang-tools=16.0.6
- clang-tools==16.0.6
- clang==16.0.6
- click
- cmake>=3.26.4,!=3.30.0
Expand All @@ -26,6 +26,7 @@ dependencies:
- gcc_linux-64=11.*
- glog>=0.6.0
- h5py>=3.8.0
- libclang==16.0.6
- libcublas-dev=11.11.3.6
- libcublas=11.11.3.6
- libcurand-dev=10.3.0.86
Expand Down
Loading

0 comments on commit b62b11a

Please sign in to comment.