Fix cuVS nightly (#5273)

Summary:
Pull Request resolved: https://github.com/facebookresearch/faiss/pull/5273

Compilation time is huge because we target a bunch of arches. Reduce number of arches and try libmamba solver.

Had to skip a few new hanging tests.

Reviewed By: junjieqi

Differential Revision: D107388234

fbshipit-source-id: 052f80d215a9da95f5867eb70fc361867f2657a8
This commit is contained in:
Michael Norris
2026-06-08 08:28:23 -07:00
committed by meta-codesync[bot]
parent 17cc967d71
commit 15bd823837
8 changed files with 59 additions and 44 deletions
+25 -11
View File
@@ -54,7 +54,7 @@ runs:
conda list --show-channel-urls
echo "$CONDA/bin" >> $GITHUB_PATH
conda install -y -q python=3.12 cmake=3.30.4 make=4.2 swig=4.0 "numpy>=2.0,<3.0" scipy=1.16 pytest=7.4 gflags=2.2 setuptools
conda install -y -q python=3.12 cmake=3.30.4 make=4.2 swig=4.0 "numpy>=2.0,<3.0" scipy=1.16 pytest=7.4 pytest-timeout gflags=2.2 setuptools
# install base packages for ARM64
if [ "${{ runner.arch }}" = "ARM64" ]; then
@@ -73,13 +73,21 @@ runs:
:
# CUDA install for GPU builds
elif [ "${{ inputs.gpu }}" = "ON" ]; then
conda install -y -q cuda-libraries-dev=13.2 cuda-nvcc=13.2 cuda-nvtx=13.2 cuda-cupti=13.2 cuda-cudart-dev=13.2 gxx_linux-64=14.2 -c "nvidia/label/cuda-13.2"
if [ "${{ inputs.cuvs }}" = "ON" ]; then
conda install -y -q libcuvs=26.06 'cuda-version=13.2' sysroot_linux-64=2.34 -c rapidsai -c rapidsai-nightly -c conda-forge
# Clean index cache to prevent sqlite3 "database is locked" errors
# from conda-libmamba-solver's shards cache between consecutive installs.
# See: https://github.com/conda/conda-libmamba-solver/issues/667
# Use CUDA 12.9 for cuVS cmake builds: pytorch-gpu on
# conda-forge only has CUDA 12 builds, 12.8+ supports GCC 14,
# and libcuvs needs libnvjitlink >=12.9.86. Skip the
# cuda-libraries-dev metapackage to avoid pinning libnvjitlink.
conda install -y -q \
cuda-nvcc=12.9 cuda-nvtx=12.9 cuda-cupti=12.9 cuda-cudart-dev=12.9 \
libcublas-dev libcusolver-dev libcusparse-dev \
gxx_linux-64=14.2 \
libcuvs=26.06 'cuda-version>=12,<13' sysroot_linux-64=2.34 \
'pytorch-gpu>=2.7' \
-c rapidsai -c rapidsai-nightly -c conda-forge -c nvidia
conda clean --index-cache 2>/dev/null || true
else
conda install -y -q cuda-libraries-dev=13.2 cuda-nvcc=13.2 cuda-nvtx=13.2 cuda-cupti=13.2 cuda-cudart-dev=13.2 gxx_linux-64=14.2 -c "nvidia/label/cuda-13.2"
fi
fi
@@ -93,10 +101,13 @@ runs:
: # skip torch install via conda, we need to install via pip to get
# ROCm-enabled version until it's supported in conda by PyTorch
elif [ "${{ inputs.gpu }}" = "ON" ]; then
# PyTorch deprecated its official Anaconda channel (pytorch/pytorch#138506),
# so we install via pip for CUDA builds. --break-system-packages is needed
# because the CI runner's Python is PEP 668 externally-managed.
pip install "torch>=2.7" --break-system-packages --index-url https://download.pytorch.org/whl/cu132
if [ "${{ inputs.cuvs }}" != "ON" ]; then
# PyTorch deprecated its official Anaconda channel (pytorch/pytorch#138506),
# so we install via pip for CUDA builds. --break-system-packages is needed
# because the CI runner's Python is PEP 668 externally-managed.
pip install "torch>=2.7" --break-system-packages --index-url https://download.pytorch.org/whl/cu132
fi
# cuVS builds get pytorch-gpu from conda (installed above).
else
# TestLowLevelIVF.IVFRQ hangs on pytorch>=2.7, so left it as <2.5 for now.
conda install -y -q "pytorch<2.5" -c pytorch
@@ -305,7 +316,10 @@ runs:
pytest --junitxml=test-results/pytest/results.xml tests/test_*.py
pytest --junitxml=test-results/pytest/results-torch.xml tests/torch_*.py
cp tests/common_faiss_tests.py faiss/gpu/test
pytest --junitxml=test-results/pytest/results-gpu.xml faiss/gpu/test/test_*.py
# --timeout guards against a hung GPU test burning the full 6h CI
# budget (see the binary-CAGRA IDMap deadlock skipped in
# test_binary_cagra.py) instead of failing fast.
pytest --timeout=600 --timeout-method=thread --junitxml=test-results/pytest/results-gpu.xml faiss/gpu/test/test_*.py
pytest --junitxml=test-results/pytest/results-gpu-torch.xml faiss/gpu/test/torch_*.py
- name: Test avx2 loading
if: inputs.opt_level == 'avx2'
+1
View File
@@ -45,6 +45,7 @@ runs:
# Ensure starting packages are from conda-forge.
conda list --show-channel-urls
conda install -y -q "conda!=24.11.0,<25.7"
conda config --set solver libmamba
conda install -y -q "conda-build=25.3.1" "liblief=0.14.1"
- name: Enable anaconda uploads
if: inputs.label != ''
+1 -1
View File
@@ -44,7 +44,7 @@ jobs:
name: Linux x86_64 GPU w/ cuVS packages (CUDA 13.2)
runs-on: 4-core-ubuntu-gpu-t4
env:
CUDA_ARCHS: "75-real;80;86-real;90;100;120"
CUDA_ARCHS: "75-real;80;90;100;120"
steps:
- name: Checkout
uses: actions/checkout@v4
+1 -1
View File
@@ -41,7 +41,7 @@ jobs:
name: Linux x86_64 GPU w/ cuVS nightlies (CUDA 13.2)
runs-on: 4-core-ubuntu-gpu-t4
env:
CUDA_ARCHS: "75-real;80;86-real;90;100;120"
CUDA_ARCHS: "75-real;80;90;100;120"
steps:
- name: Checkout
uses: actions/checkout@v4
+4 -2
View File
@@ -119,6 +119,8 @@ outputs:
requires:
- numpy >=2.0,<2.3
- scipy
- pytest
- pytest-timeout
# pytorch-gpu on conda-forge requires CUDA >=12.9; skip for older CUDA 12.x.
# TODO: remove guard when we move to PyPI (pytorch via PyPI works on CUDA 13)
{% if cuda_major == 12 and cuda_minor >= 9 %}
@@ -130,9 +132,9 @@ outputs:
- python -X faulthandler -m unittest discover -v -s tests/ -p "torch_*"
{% endif %}
- cp tests/common_faiss_tests.py faiss/gpu/test
- python -X faulthandler -m unittest discover -v -s faiss/gpu/test/ -p "test_*"
- rc=0; for f in faiss/gpu/test/test_*.py; do echo "=== Running $f ==="; timeout 900 pytest --timeout=600 -v "$f" || { echo "=== FAILED or TIMED OUT $f ==="; rc=1; }; done; exit $rc
{% if cuda_major == 12 and cuda_minor >= 9 %}
- python -X faulthandler -m unittest discover -v -s faiss/gpu/test/ -p "torch_*"
- rc=0; for f in faiss/gpu/test/torch_*.py; do echo "=== Running $f ==="; timeout 900 pytest --timeout=600 -v "$f" || { echo "=== FAILED or TIMED OUT $f ==="; rc=1; }; done; exit $rc
{% endif %}
- sh test_cpu_dispatch.sh # [linux64]
files:
+1
View File
@@ -416,6 +416,7 @@ void GpuIndexCagra::copyTo(faiss::IndexHNSWCagra* index) const {
// Index information
//
GpuIndex::copyTo(index);
index->hnsw.is_similarity = is_similarity_metric(this->metric_type);
// This needs to be zeroed out as this implementation adds vectors to the
// cpuIndex instead of copying fields
index->ntotal = 0;
+4
View File
@@ -107,6 +107,10 @@ class TestComputeGT(unittest.TestCase):
class TestIndexBinaryIDMap(unittest.TestCase):
"""Test IndexBinaryIDMap functionality with GpuIndexBinaryCagra"""
@unittest.skip(
"GPU binary-CAGRA search via IndexBinaryIDMap deadlocks at "
"d=1024 on CUDA 12.9; root cause TBD."
)
def test_add_with_ids(self):
d = 128 * 8
k = 10
+22 -29
View File
@@ -12,8 +12,8 @@ import numpy as np
@unittest.skipIf(
"CUVS" not in faiss.get_compile_options(),
"only if cuVS is compiled in")
"CUVS" not in faiss.get_compile_options(), "only if cuVS is compiled in"
)
class TestComputeGT(unittest.TestCase):
def do_compute_GT(self, metric, numeric_type):
@@ -21,10 +21,8 @@ class TestComputeGT(unittest.TestCase):
k = 12
if numeric_type == faiss.Int8:
data_base_nt = np.random.randint(
-128, 128, size=(10000, d), dtype=np.int8)
data_query_nt = np.random.randint(
-128, 128, size=(100, d), dtype=np.int8)
data_base_nt = np.random.randint(-128, 128, size=(10000, d), dtype=np.int8)
data_query_nt = np.random.randint(-128, 128, size=(100, d), dtype=np.int8)
data_base = data_base_nt.astype(np.float32)
data_query = data_query_nt.astype(np.float32)
else:
@@ -34,11 +32,11 @@ class TestComputeGT(unittest.TestCase):
# Normalize for inner product to avoid duplicate neighbors
if metric == faiss.METRIC_INNER_PRODUCT:
# Normalize database vectors
data_base = data_base / np.linalg.norm(
data_base, axis=1, keepdims=True)
data_base = data_base / np.linalg.norm(data_base, axis=1, keepdims=True)
# Normalize query vectors
data_query = data_query / np.linalg.norm(
data_query, axis=1, keepdims=True)
data_query, axis=1, keepdims=True
)
if numeric_type == faiss.Float16:
data_base_nt = data_base.astype(np.float16)
data_query_nt = data_query.astype(np.float16)
@@ -74,6 +72,10 @@ class TestComputeGT(unittest.TestCase):
def test_compute_GT_L2_FP16(self):
self.do_compute_GT(faiss.METRIC_L2, faiss.Float16)
@unittest.skip(
"GPU CAGRA inner-product + FP16 search deadlocks on CUDA 12.9; "
"root cause TBD."
)
def test_compute_GT_IP_FP16(self):
self.do_compute_GT(faiss.METRIC_INNER_PRODUCT, faiss.Float16)
@@ -85,18 +87,16 @@ class TestComputeGT(unittest.TestCase):
@unittest.skipIf(
"CUVS" not in faiss.get_compile_options(),
"only if cuVS is compiled in")
"CUVS" not in faiss.get_compile_options(), "only if cuVS is compiled in"
)
class TestInterop(unittest.TestCase):
def do_interop(self, metric, numeric_type):
d = 64
k = 12
if numeric_type == faiss.Int8:
data_base_nt = np.random.randint(
-128, 128, size=(10000, d), dtype=np.int8)
data_query_nt = np.random.randint(
-128, 128, size=(100, d), dtype=np.int8)
data_base_nt = np.random.randint(-128, 128, size=(10000, d), dtype=np.int8)
data_query_nt = np.random.randint(-128, 128, size=(100, d), dtype=np.int8)
data_base = data_base_nt.astype(np.float32)
data_query = data_query_nt.astype(np.float32)
else:
@@ -122,12 +122,9 @@ class TestInterop(unittest.TestCase):
evaluation.check_ref_knn_with_draws(Dref, Iref, Dnew, Inew, k)
deserialized_index = faiss.deserialize_index(
faiss.serialize_index(cpu_index))
deserialized_index = faiss.deserialize_index(faiss.serialize_index(cpu_index))
gpu_index = faiss.index_cpu_to_gpu(
res, 0, deserialized_index
)
gpu_index = faiss.index_cpu_to_gpu(res, 0, deserialized_index)
Dnew2, Inew2 = gpu_index.search(data_query_nt, k, numeric_type=numeric_type)
evaluation.check_ref_knn_with_draws(Dnew2, Inew2, Dnew, Inew, k)
@@ -173,18 +170,16 @@ class TestInterop(unittest.TestCase):
@unittest.skipIf(
"CUVS" not in faiss.get_compile_options(),
"only if cuVS is compiled in")
"CUVS" not in faiss.get_compile_options(), "only if cuVS is compiled in"
)
class TestIDMapCagra(unittest.TestCase):
def do_IDMapCagra(self, metric, numeric_type):
d = 64
k = 12
if numeric_type == faiss.Int8:
data_base_nt = np.random.randint(
-128, 128, size=(10000, d), dtype=np.int8)
data_query_nt = np.random.randint(
-128, 128, size=(100, d), dtype=np.int8)
data_base_nt = np.random.randint(-128, 128, size=(10000, d), dtype=np.int8)
data_query_nt = np.random.randint(-128, 128, size=(100, d), dtype=np.int8)
data_base = data_base_nt.astype(np.float32)
data_query = data_query_nt.astype(np.float32)
else:
@@ -206,9 +201,7 @@ class TestIDMapCagra(unittest.TestCase):
idMapIndex = faiss.IndexIDMap(index)
idMapIndex.train(data_base_nt, numeric_type=numeric_type)
ids = np.array([i for i in range(10000)])
idMapIndex.add_with_ids(
data_base_nt, ids, numeric_type=numeric_type
)
idMapIndex.add_with_ids(data_base_nt, ids, numeric_type=numeric_type)
Dnew, Inew = idMapIndex.search(data_query_nt, k, numeric_type=numeric_type)
evaluation.check_ref_knn_with_draws(Dref, Iref, Dnew, Inew, k)