diff --git a/AGENTS.md b/AGENTS.md index cf51ad1..a2c1dd0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -133,11 +133,13 @@ Key files: - `extensions/cuda.bzl`: module extension entrypoint - `cuda/cuda_redist_versions.json`: supported CUDA version pins - `cudnn/cudnn_redist_versions.json`: supported cuDNN version pins +- `cusparselt/cusparselt_redist_versions.json`: supported cuSPARSELt version pins - `nvshmem/nvshmem_redist_versions.json`: supported NVSHMEM version pins - `nccl/nccl_redist_versions.json`: generated NCCL archive metadata - `nccl/update_redists.py`: NCCL catalog updater and archive verifier, run through `//tools/nccl:update_redists` - `cuda/cuda_redist_build_defs.bzl`: CUDA component registry and template selection - `cudnn/cudnn_redist_build_defs.bzl`: cuDNN component registry and template selection +- `cusparselt/cusparselt_redist_build_defs.bzl`: cuSPARSELt component registry and template selection - `nvshmem/nvshmem_redist_build_defs.bzl`: NVSHMEM component registry and template selection - `nccl/nccl_redist_build_defs.bzl`: NCCL component registry and template selection - `cuda/redist_proxy_targets.bzl`: stable public target catalog diff --git a/README.md b/README.md index 616c34f..2089aff 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ Supported versions are defined in: - `cuda/cuda_redist_versions.json` - `cudnn/cudnn_redist_versions.json` - `nvshmem/nvshmem_redist_versions.json` +- `cusparselt/cusparselt_redist_versions.json` - `nccl/nccl_redist_versions.json` (generated from NVIDIA's official NCCL archive index with `bazel run //tools/nccl:update_redists`) ## Supported platforms @@ -52,6 +53,7 @@ cuda_ext.redist( cudnn_version = "8.9.7", nvshmem_version = "3.3.24", nccl_version = "2.30.7", + cusparselt_version = "0.8.1", ) use_repo(cuda_ext, "cuda") @@ -61,9 +63,10 @@ use_repo(cuda_ext, "cuda") - CUDA versions are registered explicitly with `cuda_ext.redist(...)`. - `cuda_ext.configure(...)` can set the global proxy repository's `name` and optionally apply `default_package_metadata` to every generated repository through `REPO.bazel`. -- cuDNN, NVSHMEM, and NCCL versions, when used, are pinned on the same `cuda_ext.redist(...)` tag. +- cuDNN, NVSHMEM, NCCL, and cuSPARSELt versions, when used, are pinned on the same `cuda_ext.redist(...)` tag. - The generated NCCL catalog includes every official release from 2.25.1 onward that publishes an archive for a registered CUDA minor version. - NCCL archives record their exact build CUDA version and an explicit list of compatible registered CUDA minor versions; unsupported NCCL/CUDA pairs fail during module extension evaluation. +- cuSPARSELt manifests from 0.8.0 onward publish one archive per CUDA major (`cuda_variant`); the archive matching the registered CUDA major is selected, and requesting a cuSPARSELt version with no archive for the registered CUDA major fails during module extension evaluation. - CUDA packages under `@cuda//` are platform-resolving proxies. The selected concrete redistribution is chosen from the current Bazel configuration platform (including exec config). - CUDA libraries backed by `*_shared_library` imports also expose `*_interface_library` imports and public diff --git a/cuda/redist_proxy_targets.bzl b/cuda/redist_proxy_targets.bzl index 8fcb2a8..e006fd9 100644 --- a/cuda/redist_proxy_targets.bzl +++ b/cuda/redist_proxy_targets.bzl @@ -85,6 +85,17 @@ REPO_PUBLIC_TARGETS = { "cuda_curand": ["curand_shared_library", "curand_interface_library", "curand", "curand_system", "curand_static", "header_list", "headers", "shared_library_files"], "cuda_cusolver": ["cusolver_shared_library", "cusolver_interface_library", "cusolver", "cusolver_system", "cusolverMg_shared_library", "cusolverMg_interface_library", "cusolverMg", "cusolverMg_system", "cusolver_static", "cusolver_lapack_static", "cusolver_metis_static", "metis_static", "header_list", "headers", "shared_library_files"], "cuda_cusparse": ["cusparse_shared_library", "cusparse_interface_library", "cusparse", "cusparse_system", "cusparse_static", "header_list", "headers", "shared_library_files"], + "cuda_cusparselt": [ + "cusparselt_shared_library", + "cusparselt_interface_library", + "cusparselt_static_library", + "cusparselt", + "cusparselt_system", + "cusparselt_static", + "header_list", + "headers", + "shared_library_files", + ], "cuda_driver": [ "driver_shared_library", "driver_interface_library", diff --git a/cusparselt/BUILD.bazel b/cusparselt/BUILD.bazel new file mode 100644 index 0000000..b7943a4 --- /dev/null +++ b/cusparselt/BUILD.bazel @@ -0,0 +1,7 @@ +load("@bazel_lib//:bzl_library.bzl", "bzl_library") + +bzl_library( + name = "cusparselt_redist_build_defs", + srcs = ["cusparselt_redist_build_defs.bzl"], + visibility = ["//visibility:public"], +) diff --git a/cusparselt/build_defs/BUILD.bazel b/cusparselt/build_defs/BUILD.bazel new file mode 100644 index 0000000..50bdb0b --- /dev/null +++ b/cusparselt/build_defs/BUILD.bazel @@ -0,0 +1 @@ +exports_files(["cusparselt.BUILD.bazel"]) diff --git a/cusparselt/build_defs/cusparselt.BUILD.bazel b/cusparselt/build_defs/cusparselt.BUILD.bazel new file mode 100644 index 0000000..103bc89 --- /dev/null +++ b/cusparselt/build_defs/cusparselt.BUILD.bazel @@ -0,0 +1,97 @@ +"""BUILD definitions for cusparselt package""" + +load("@rules_cc//cc:cc_import.bzl", "cc_import") +load("@rules_cc//cc:cc_library.bzl", "cc_library") +load("//:version.bzl", "LIB_VERSIONS") + +cc_import( + name = "cusparselt_shared_library", + deps = [":headers"], + shared_library = "lib/libcusparseLt.so." + LIB_VERSIONS["libcusparselt"], + visibility = ["//visibility:public"], +) + +# cuSPARSELt archives ship no lib/stubs/ directory, so the unversioned +# libcusparseLt.so symlink is the link interface. +cc_import( + name = "cusparselt_interface_library", + deps = [":headers"], + interface_library = "lib/libcusparseLt.so", + system_provided = True, + visibility = ["//visibility:public"], +) + +cc_import( + name = "cusparselt_static_library", + deps = [":headers"], + static_library = "lib/libcusparseLt_static.a", + visibility = ["//visibility:public"], +) + +cc_library( + name = "cusparselt", + deps = [ + ":cusparselt_shared_library", + ":headers", + ], + visibility = ["//visibility:public"], +) + +cc_library( + name = "cusparselt_system", + deps = [":cusparselt_interface_library"], + visibility = ["//visibility:public"], +) + +# libcusparseLt_static.a leaves CUDA runtime symbols undefined (the shared +# library embeds the runtime statically; the static archive does not). +cc_library( + name = "cusparselt_static", + deps = [ + ":cusparselt_static_library", + "@{cuda_redist_repo}//cudart:static", + ], + linkopts = [ + "-lpthread", + "-lrt", + "-ldl", + ], + visibility = ["//visibility:public"], +) + +# The SONAME (libcusparseLt.so.0) is a truncation of the fully versioned +# file name, so consumers can derive the runtime symlink; only the fully +# versioned file needs to be staged. +filegroup( + name = "shared_library_files", + srcs = [ + "lib/libcusparseLt.so." + LIB_VERSIONS["libcusparselt"], + ], + visibility = ["//visibility:public"], +) + +filegroup( + name = "header_list", + srcs = glob( + [ + "include/*.h", + "include/**/*.h", + ], + allow_empty = True, + ), + visibility = ["//visibility:public"], +) + +cc_library( + name = "headers", + hdrs = [":header_list"], + deps = [ + # cusparseLt.h includes cusparse.h, driver_types.h and + # library_types.h. + "@{cuda_redist_repo}//cudart:headers", + "@{cuda_redist_repo}//cusparse:headers", + ], + includes = ["include"], + strip_include_prefix = "include", + visibility = ["//visibility:public"], +) diff --git a/cusparselt/cusparselt_redist_build_defs.bzl b/cusparselt/cusparselt_redist_build_defs.bzl new file mode 100644 index 0000000..d213980 --- /dev/null +++ b/cusparselt/cusparselt_redist_build_defs.bzl @@ -0,0 +1,14 @@ +"""Hermetic cuSPARSELt redistribution utilities.""" + +CUSPARSELT_REDIST_PATH_PREFIX = "https://developer.download.nvidia.com/compute/cusparselt/redist/" + +CUSPARSELT_VERSION_TO_TEMPLATE = { + "0": "//cusparselt/build_defs:cusparselt.BUILD.bazel", +} + +CUSPARSELT_COMPONENTS_REGISTRY = { + "libcusparse_lt": { + "repo_name": "cuda_cusparselt", + "version_to_template": CUSPARSELT_VERSION_TO_TEMPLATE, + }, +} diff --git a/cusparselt/cusparselt_redist_versions.json b/cusparselt/cusparselt_redist_versions.json new file mode 100644 index 0000000..7c9144a --- /dev/null +++ b/cusparselt/cusparselt_redist_versions.json @@ -0,0 +1,17 @@ +{ + "0.3.0": ["https://developer.download.nvidia.com/compute/cusparselt/redist/redistrib_0.3.0.json", "76fb0b1a93d3d3e6e69171030b7c0cb2db3fb05e66b1c367a653dff39a5820a8"], + "0.4.0": ["https://developer.download.nvidia.com/compute/cusparselt/redist/redistrib_0.4.0.json", "c4bb48812ff57b99baad0cc2b68c28061e929c126282b8de98bf98235ae8d97f"], + "0.5.0": ["https://developer.download.nvidia.com/compute/cusparselt/redist/redistrib_0.5.0.json", "c74823b2db62969d9a5dcb47cd927c51e2f36a82d4e2ffd2790c16f5e85d78b2"], + "0.5.1": ["https://developer.download.nvidia.com/compute/cusparselt/redist/redistrib_0.5.1.json", "03fee9e956b5989a0f96a86f5e63d1b5a1efdd8606884b93c8e5cdc42c3a3ca8"], + "0.5.2": ["https://developer.download.nvidia.com/compute/cusparselt/redist/redistrib_0.5.2.json", "40c8dd058f65789a430d28f583a0ab136794d4736bbf8f68ff531fed07c2f8f6"], + "0.6.0": ["https://developer.download.nvidia.com/compute/cusparselt/redist/redistrib_0.6.0.json", "3807127864d86f76051272e19b5380e1cb709cef6dd70ab7b9dd7e4bbceb3894"], + "0.6.1": ["https://developer.download.nvidia.com/compute/cusparselt/redist/redistrib_0.6.1.json", "4aca6331afc2d9fcdd64786faa2d2344c28e7c29061f877f46fafa612c466dd0"], + "0.6.2": ["https://developer.download.nvidia.com/compute/cusparselt/redist/redistrib_0.6.2.json", "9d0011a3ca95de5b1e6fff207e106a93618635ccb7e00235e563ef506464a77c"], + "0.6.3": ["https://developer.download.nvidia.com/compute/cusparselt/redist/redistrib_0.6.3.json", "ddecc44476df5ce7b41d518ea13f023606919883fa610b0c64f6268fe19f61ba"], + "0.7.0": ["https://developer.download.nvidia.com/compute/cusparselt/redist/redistrib_0.7.0.json", "630ea0595bde72982d670c639e1277e12e0bc84bda4d4380556b6952253fdfe7"], + "0.7.1": ["https://developer.download.nvidia.com/compute/cusparselt/redist/redistrib_0.7.1.json", "a6bb3fb44f0ecae0d87950127ec47de59486143c5c968c06447b6689d661d2bb"], + "0.8.0": ["https://developer.download.nvidia.com/compute/cusparselt/redist/redistrib_0.8.0.json", "f1905214275cef3c6057ad3064254d2b679bf32e4c42e8a87637b4d46bcef8c3"], + "0.8.1": ["https://developer.download.nvidia.com/compute/cusparselt/redist/redistrib_0.8.1.json", "d8ce601cd345630af9bb95bf2a40cca317c5f8256ebc4c5bd87af72e5f90d945"], + "0.9.0": ["https://developer.download.nvidia.com/compute/cusparselt/redist/redistrib_0.9.0.json", "ea4a0c3e452f9cc57c10b57c33f94e5065703b4afeb554464a38fdb0a4014bc0"], + "0.9.1": ["https://developer.download.nvidia.com/compute/cusparselt/redist/redistrib_0.9.1.json", "beb23c66efdced33b66fd076730a34f5158892b8617f277a6e2db7e8ce47b662"] +} diff --git a/docs/cuda.md b/docs/cuda.md index 21badcb..194e804 100755 --- a/docs/cuda.md +++ b/docs/cuda.md @@ -9,7 +9,7 @@ Unified CUDA module extension.
 cuda = use_extension("@cuda_toolkit//extensions:cuda.bzl", "cuda")
 cuda.configure(name, default_package_metadata)
-cuda.redist(name, cudnn_version, nccl_version, nvshmem_version, version)
+cuda.redist(name, cudnn_version, cusparselt_version, nccl_version, nvshmem_version, version)
 
@@ -38,6 +38,7 @@ Configures settings shared by all generated CUDA repositories. | :------------- | :------------- | :------------- | :------------- | :------------- | | name | - | Name | required | | | cudnn_version | - | String | optional | `""` | +| cusparselt_version | - | String | optional | `""` | | nccl_version | - | String | optional | `""` | | nvshmem_version | - | String | optional | `""` | | version | - | String | required | | diff --git a/e2e/BUILD.bazel b/e2e/BUILD.bazel index 6faa1b9..f3abac4 100644 --- a/e2e/BUILD.bazel +++ b/e2e/BUILD.bazel @@ -177,6 +177,35 @@ cc_binary( ], ) +cc_binary( + name = "cusparselt_smoke", + srcs = ["cusparselt_smoke.cc"], + deps = [ + ":smoke_test_common", + "@cuda//cusparselt:cusparselt", + ], +) + +cc_binary( + name = "cusparselt_system_smoke", + srcs = ["cusparselt_smoke.cc"], + deps = [ + ":smoke_test_common", + "@cuda//cusparselt:cusparselt_system", + ], +) + +cc_binary( + name = "cusparselt_static_smoke", + srcs = ["cusparselt_smoke.cc"], + # static archives use libstdc++ abi. + tags = ["manual"], + deps = [ + ":smoke_test_common", + "@cuda//cusparselt:cusparselt_static", + ], +) + cc_library( name = "smoke_test_common", hdrs = ["smoke_test_common.h"], diff --git a/e2e/MODULE.bazel b/e2e/MODULE.bazel index 7d9affc..670c7c3 100644 --- a/e2e/MODULE.bazel +++ b/e2e/MODULE.bazel @@ -24,12 +24,16 @@ cuda_ext.configure( # NCCL selections exercise archives built with both older and newer CUDA minors # across each explicitly compatible CUDA major family. +# cuSPARSELt selections exercise both manifest shapes: releases up to 0.7.1 +# publish one archive per platform, while 0.8.0+ publish per-CUDA-major +# cuda_variant archives. cuda_ext.redist( name = "cuda_12_8_1", version = "12.8.1", cudnn_version = "8.9.7", nvshmem_version = "3.3.24", nccl_version = "2.31.2", + cusparselt_version = "0.7.1", ) cuda_ext.redist( name = "cuda_12_9_1", @@ -37,6 +41,7 @@ cuda_ext.redist( cudnn_version = "8.9.7", nvshmem_version = "3.3.24", nccl_version = "2.25.1", + cusparselt_version = "0.8.1", ) cuda_ext.redist( name = "cuda_13_0_2", @@ -44,6 +49,7 @@ cuda_ext.redist( cudnn_version = "9.20.0", nvshmem_version = "3.5.19", nccl_version = "2.31.2", + cusparselt_version = "0.8.0", ) cuda_ext.redist( name = "cuda_13_1_1", @@ -51,6 +57,7 @@ cuda_ext.redist( cudnn_version = "9.20.0", nvshmem_version = "3.5.19", nccl_version = "2.27.7", + cusparselt_version = "0.8.1", ) cuda_ext.redist( name = "cuda_13_2_1", @@ -58,6 +65,7 @@ cuda_ext.redist( cudnn_version = "9.20.0", nvshmem_version = "3.5.19", nccl_version = "2.30.7", + cusparselt_version = "0.9.0", ) cuda_ext.redist( name = "cuda_13_3_1", @@ -65,6 +73,7 @@ cuda_ext.redist( cudnn_version = "9.20.0", nvshmem_version = "3.5.19", nccl_version = "2.29.3", + cusparselt_version = "0.9.1", ) use_repo( diff --git a/e2e/cusparselt_smoke.cc b/e2e/cusparselt_smoke.cc new file mode 100644 index 0000000..46c8a9c --- /dev/null +++ b/e2e/cusparselt_smoke.cc @@ -0,0 +1,18 @@ +#include + +#include "smoke_test_common.h" + +int ExerciseCusparseLtGetVersion() { + cusparseLtHandle_t handle; + if (cusparseLtInit(&handle) != CUSPARSE_STATUS_SUCCESS) { + return 1; + } + int version = 0; + cusparseStatus_t status = cusparseLtGetVersion(&handle, &version); + cusparseLtDestroy(&handle); + return status == CUSPARSE_STATUS_SUCCESS && version > 0 ? 0 : 1; +} + +int main(int argc, char**) { + return ShouldRunSmokeExample(argc) ? ExerciseCusparseLtGetVersion() : 0; +} diff --git a/extensions/BUILD.bazel b/extensions/BUILD.bazel index 0c9fa19..43b9008 100644 --- a/extensions/BUILD.bazel +++ b/extensions/BUILD.bazel @@ -11,6 +11,7 @@ bzl_library( "//cuda:cuda_component_proxy", "//cuda:cuda_compat_repository", "//cudnn:cudnn_redist_build_defs", + "//cusparselt:cusparselt_redist_build_defs", "//nccl:nccl_redist_build_defs", "//nvshmem:nvshmem_redist_build_defs", ], diff --git a/extensions/cuda.bzl b/extensions/cuda.bzl index f8892ac..9d4677a 100644 --- a/extensions/cuda.bzl +++ b/extensions/cuda.bzl @@ -9,6 +9,11 @@ load( "CUDNN_COMPONENTS_REGISTRY", "CUDNN_REDIST_PATH_PREFIX", ) +load( + "//cusparselt:cusparselt_redist_build_defs.bzl", + "CUSPARSELT_COMPONENTS_REGISTRY", + "CUSPARSELT_REDIST_PATH_PREFIX", +) load( "//nccl:nccl_redist_build_defs.bzl", "NCCL_COMPONENTS_REGISTRY", @@ -23,6 +28,7 @@ load( _CUDA_REDIST_VERSIONS_JSON = Label("//cuda:cuda_redist_versions.json") _CUDNN_REDIST_VERSIONS_JSON = Label("//cudnn:cudnn_redist_versions.json") +_CUSPARSELT_REDIST_VERSIONS_JSON = Label("//cusparselt:cusparselt_redist_versions.json") _NCCL_REDIST_VERSIONS_JSON = Label("//nccl:nccl_redist_versions.json") _NVSHMEM_REDIST_VERSIONS_JSON = Label("//nvshmem:nvshmem_redist_versions.json") @@ -98,6 +104,7 @@ def _read_downloaded_json(mctx, pending_download): def _cuda_impl(mctx): cuda_version_map = json.decode(mctx.read(_CUDA_REDIST_VERSIONS_JSON)) cudnn_version_map = json.decode(mctx.read(_CUDNN_REDIST_VERSIONS_JSON)) + cusparselt_version_map = json.decode(mctx.read(_CUSPARSELT_REDIST_VERSIONS_JSON)) nccl_version_map = json.decode(mctx.read(_NCCL_REDIST_VERSIONS_JSON)) nvshmem_version_map = json.decode(mctx.read(_NVSHMEM_REDIST_VERSIONS_JSON)) @@ -127,6 +134,9 @@ def _cuda_impl(mctx): pending_nvshmem_redistributions_by_version = {} nvshmem_versions_to_fetch = [] nvshmem_redistributions_by_version = {} + pending_cusparselt_redistributions_by_version = {} + cusparselt_versions_to_fetch = [] + cusparselt_redistributions_by_version = {} for tag in tags: if tag.name == configuration.name: fail("redist name '{}' is reserved for the global aggregated CUDA repository".format(configuration.name)) @@ -178,6 +188,20 @@ def _cuda_impl(mctx): ) nvshmem_versions_to_fetch.append(tag.nvshmem_version) + if tag.cusparselt_version and tag.cusparselt_version not in pending_cusparselt_redistributions_by_version: + (cusparselt_redist_url, cusparselt_redist_sha256) = _get_url_sha_from_version_map( + version = tag.cusparselt_version, + version_to_url_sha = cusparselt_version_map, + toolkit_name = "cuSPARSELt", + ) + pending_cusparselt_redistributions_by_version[tag.cusparselt_version] = _json_from_url_future( + mctx = mctx, + url = cusparselt_redist_url, + sha256 = cusparselt_redist_sha256, + output_path = "redistrib_cusparselt_%s.json" % tag.cusparselt_version, + ) + cusparselt_versions_to_fetch.append(tag.cusparselt_version) + for version in versions_to_fetch: redistributions_by_version[version] = _read_downloaded_json( mctx, @@ -196,6 +220,12 @@ def _cuda_impl(mctx): pending_nvshmem_redistributions_by_version[version], ) + for version in cusparselt_versions_to_fetch: + cusparselt_redistributions_by_version[version] = _read_downloaded_json( + mctx, + pending_cusparselt_redistributions_by_version[version], + ) + for tag in tags: generated_repos = cuda_redist_repositories( redist = redistributions_by_version[tag.version], @@ -273,6 +303,34 @@ def _cuda_impl(mctx): component_proxy_specs[repo_name] = spec spec["platform_repo_mappings"][generated["config_setting"]] = generated["concrete_repo_name"] + if tag.cusparselt_version: + cusparselt_redist = cusparselt_redistributions_by_version[tag.cusparselt_version] + if "libcusparse_lt" not in cusparselt_redist: + fail("cuSPARSELt manifest '{}' does not contain a 'libcusparse_lt' package".format(tag.cusparselt_version)) + + generated_cusparselt_repos = cuda_redist_repositories( + redist = {"libcusparse_lt": cusparselt_redist["libcusparse_lt"]}, + cuda_repo_name = tag.name, + cuda_version = tag.version, + cuda_redist_path_prefix = CUSPARSELT_REDIST_PATH_PREFIX, + components_registry = CUSPARSELT_COMPONENTS_REGISTRY, + default_package_metadata = default_package_metadata, + ) + if not generated_cusparselt_repos: + fail("cuSPARSELt version '{}' did not generate any repositories for CUDA {}".format(tag.cusparselt_version, tag.version)) + + for generated in generated_cusparselt_repos: + repo_name = generated["component_repo_name"] + spec = component_proxy_specs.get(repo_name) + if not spec: + spec = { + "version": generated["version"], + "targets": generated["targets"], + "platform_repo_mappings": {}, + } + component_proxy_specs[repo_name] = spec + spec["platform_repo_mappings"][generated["config_setting"]] = generated["concrete_repo_name"] + if tag.nccl_version: nccl_redist = nccl_redistributions_by_tag_name[tag.name] @@ -357,6 +415,7 @@ _redist = tag_class( "cudnn_version": attr.string(), "nvshmem_version": attr.string(), "nccl_version": attr.string(), + "cusparselt_version": attr.string(), }, )