From 576946440fc67de93dac301bfa5cff7b89470bd6 Mon Sep 17 00:00:00 2001 From: ldematte Date: Tue, 19 Aug 2025 11:55:48 +0200 Subject: [PATCH 1/8] C API changes: adding method to retrieve the ID of the device associated with a resource --- cpp/include/cuvs/core/c_api.h | 11 ++++++++++- cpp/src/core/c_api.cpp | 10 ++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/cpp/include/cuvs/core/c_api.h b/cpp/include/cuvs/core/c_api.h index d7b6673990..e3cd9bd40b 100644 --- a/cpp/include/cuvs/core/c_api.h +++ b/cpp/include/cuvs/core/c_api.h @@ -86,7 +86,7 @@ cuvsError_t cuvsResourcesDestroy(cuvsResources_t res); cuvsError_t cuvsStreamSet(cuvsResources_t res, cudaStream_t stream); /** - * @brief Get the cudaStream_t from a cuvsResources_t t + * @brief Get the cudaStream_t from a cuvsResources_t * * @param[in] res cuvsResources_t opaque C handle * @param[out] stream cudaStream_t stream to queue CUDA kernels @@ -101,6 +101,15 @@ cuvsError_t cuvsStreamGet(cuvsResources_t res, cudaStream_t* stream); * @return cuvsError_t */ cuvsError_t cuvsStreamSync(cuvsResources_t res); + +/** + * @brief Get the id of the device associated with this cuvsResources_t + * + * @param[in] res cuvsResources_t opaque C handle + * @param[out] device_id int the id of the device associated with res + * @return cuvsError_t + */ +cuvsError_t cuvsDeviceIdGet(cuvsResources_t res, int* device_id); /** @} */ /** diff --git a/cpp/src/core/c_api.cpp b/cpp/src/core/c_api.cpp index 8a9116f4cb..2f66adf416 100644 --- a/cpp/src/core/c_api.cpp +++ b/cpp/src/core/c_api.cpp @@ -19,6 +19,8 @@ #include #include +#include +#include #include #include #include @@ -73,6 +75,14 @@ extern "C" cuvsError_t cuvsStreamSync(cuvsResources_t res) }); } +extern "C" cuvsError_t cuvsDeviceIdGet(cuvsResources_t res, int* device_id) +{ + return cuvs::core::translate_exceptions([=] { + auto res_ptr = reinterpret_cast(res); + *device_id = raft::resource::get_device_id(*res_ptr); + }); +} + extern "C" cuvsError_t cuvsRMMAlloc(cuvsResources_t res, void** ptr, size_t bytes) { return cuvs::core::translate_exceptions([=] { From fea987ec8b809ccffd57fdf4785d6bd5e749c0aa Mon Sep 17 00:00:00 2001 From: ldematte Date: Wed, 20 Aug 2025 08:46:43 +0200 Subject: [PATCH 2/8] Introducing GPUInfoProvider with and a first (incomplete) implementation in GPUInfoProviderImpl. --- .../java/com/nvidia/cuvs/CuVSMemoryInfo.java | 23 +++++++++ .../main/java/com/nvidia/cuvs/GPUInfo.java | 4 +- .../java/com/nvidia/cuvs/GPUInfoProvider.java | 47 +++++++++++++++++++ .../com/nvidia/cuvs/spi/CuVSProvider.java | 11 ++--- .../nvidia/cuvs/spi/UnsupportedProvider.java | 12 ++--- .../cuvs/internal/GPUInfoProviderImpl.java | 41 ++++++++++++++++ .../com/nvidia/cuvs/internal/common/Util.java | 17 ++----- .../com/nvidia/cuvs/spi/JDKProvider.java | 5 ++ 8 files changed, 130 insertions(+), 30 deletions(-) create mode 100644 java/cuvs-java/src/main/java/com/nvidia/cuvs/CuVSMemoryInfo.java create mode 100644 java/cuvs-java/src/main/java/com/nvidia/cuvs/GPUInfoProvider.java create mode 100644 java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/GPUInfoProviderImpl.java diff --git a/java/cuvs-java/src/main/java/com/nvidia/cuvs/CuVSMemoryInfo.java b/java/cuvs-java/src/main/java/com/nvidia/cuvs/CuVSMemoryInfo.java new file mode 100644 index 0000000000..da73160fa9 --- /dev/null +++ b/java/cuvs-java/src/main/java/com/nvidia/cuvs/CuVSMemoryInfo.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2025, NVIDIA CORPORATION. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.nvidia.cuvs; + +/** + * Contains memory information associated to a {@link CuVSResources} and its GPU. + * @param freeDeviceMemory free memory in bytes, as reported by the device driver + * @param freeRMMPoolMemory free memory in bytes in the RMM memory pool + */ +public record CuVSMemoryInfo(long freeDeviceMemory, long freeRMMPoolMemory) {} diff --git a/java/cuvs-java/src/main/java/com/nvidia/cuvs/GPUInfo.java b/java/cuvs-java/src/main/java/com/nvidia/cuvs/GPUInfo.java index c0ccaf99c3..bc6f3b2eab 100644 --- a/java/cuvs-java/src/main/java/com/nvidia/cuvs/GPUInfo.java +++ b/java/cuvs-java/src/main/java/com/nvidia/cuvs/GPUInfo.java @@ -20,9 +20,7 @@ * * @param gpuId id of the GPU starting from 0 * @param name ASCII string identifying device - * @param freeMemory returned free memory in bytes * @param totalMemory returned total memory in bytes * @param computeCapability the compute capability of the device */ -public record GPUInfo( - int gpuId, String name, long freeMemory, long totalMemory, float computeCapability) {} +public record GPUInfo(int gpuId, String name, long totalMemory, float computeCapability) {} diff --git a/java/cuvs-java/src/main/java/com/nvidia/cuvs/GPUInfoProvider.java b/java/cuvs-java/src/main/java/com/nvidia/cuvs/GPUInfoProvider.java new file mode 100644 index 0000000000..ad78d8e90a --- /dev/null +++ b/java/cuvs-java/src/main/java/com/nvidia/cuvs/GPUInfoProvider.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2025, NVIDIA CORPORATION. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.nvidia.cuvs; + +import java.util.List; + +public interface GPUInfoProvider { + + float MIN_COMPUTE_CAPABILITY = 7.0f; + + int MIN_DEVICE_MEMORY_IN_MB = 8192; + + /** + * Gets all the available GPUs + * + * @return a list of {@link GPUInfo} objects with GPU details + */ + List availableGPUs() throws Throwable; + + /** + * Get the list of compatible GPUs based on compute capability >= 7.0 and total + * memory >= 8GB + * + * @return a list of compatible GPUs. See {@link GPUInfo} + */ + List compatibleGPUs() throws Throwable; + + /** + * Gets memory information from pools and device associated with a {@link CuVSResources} + * @param resources from which to obtain memory information + * @return a {@link CuVSMemoryInfo} record containing the memory information + */ + CuVSMemoryInfo currentMemory(CuVSResources resources); +} diff --git a/java/cuvs-java/src/main/java/com/nvidia/cuvs/spi/CuVSProvider.java b/java/cuvs-java/src/main/java/com/nvidia/cuvs/spi/CuVSProvider.java index e528beff1a..3b2b781b6c 100644 --- a/java/cuvs-java/src/main/java/com/nvidia/cuvs/spi/CuVSProvider.java +++ b/java/cuvs-java/src/main/java/com/nvidia/cuvs/spi/CuVSProvider.java @@ -15,13 +15,7 @@ */ package com.nvidia.cuvs.spi; -import com.nvidia.cuvs.BruteForceIndex; -import com.nvidia.cuvs.CagraIndex; -import com.nvidia.cuvs.CagraMergeParams; -import com.nvidia.cuvs.CuVSMatrix; -import com.nvidia.cuvs.CuVSResources; -import com.nvidia.cuvs.HnswIndex; -import com.nvidia.cuvs.TieredIndex; +import com.nvidia.cuvs.*; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodType; import java.nio.file.Path; @@ -120,6 +114,9 @@ default CagraIndex mergeCagraIndexes(CagraIndex[] indexes, CagraMergeParams merg return mergeCagraIndexes(indexes); } + /** Returns a {@link GPUInfoProvider} to query the system for GPU related information */ + GPUInfoProvider gpuInfoProvider(); + /** Retrieves the system-wide provider. */ static CuVSProvider provider() { return CuVSServiceProvider.Holder.INSTANCE; diff --git a/java/cuvs-java/src/main/java/com/nvidia/cuvs/spi/UnsupportedProvider.java b/java/cuvs-java/src/main/java/com/nvidia/cuvs/spi/UnsupportedProvider.java index 8f65bf7068..67eff03fc9 100644 --- a/java/cuvs-java/src/main/java/com/nvidia/cuvs/spi/UnsupportedProvider.java +++ b/java/cuvs-java/src/main/java/com/nvidia/cuvs/spi/UnsupportedProvider.java @@ -15,12 +15,7 @@ */ package com.nvidia.cuvs.spi; -import com.nvidia.cuvs.BruteForceIndex; -import com.nvidia.cuvs.CagraIndex; -import com.nvidia.cuvs.CuVSMatrix; -import com.nvidia.cuvs.CuVSResources; -import com.nvidia.cuvs.HnswIndex; -import com.nvidia.cuvs.TieredIndex; +import com.nvidia.cuvs.*; import java.lang.invoke.MethodHandle; import java.nio.file.Path; @@ -59,6 +54,11 @@ public CagraIndex mergeCagraIndexes(CagraIndex[] indexes) throws Throwable { throw new UnsupportedOperationException(); } + @Override + public GPUInfoProvider gpuInfoProvider() { + throw new UnsupportedOperationException(); + } + @Override public CuVSMatrix.Builder newMatrixBuilder( int size, int dimensions, CuVSMatrix.DataType dataType) { diff --git a/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/GPUInfoProviderImpl.java b/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/GPUInfoProviderImpl.java new file mode 100644 index 0000000000..9e29779188 --- /dev/null +++ b/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/GPUInfoProviderImpl.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2025, NVIDIA CORPORATION. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.nvidia.cuvs.internal; + +import com.nvidia.cuvs.CuVSMemoryInfo; +import com.nvidia.cuvs.CuVSResources; +import com.nvidia.cuvs.GPUInfo; +import com.nvidia.cuvs.GPUInfoProvider; +import com.nvidia.cuvs.internal.common.Util; +import java.util.List; + +public class GPUInfoProviderImpl implements GPUInfoProvider { + + @Override + public List availableGPUs() throws Throwable { + return Util.availableGPUs(); + } + + @Override + public List compatibleGPUs() throws Throwable { + return Util.compatibleGPUs(MIN_COMPUTE_CAPABILITY, MIN_DEVICE_MEMORY_IN_MB); + } + + @Override + public CuVSMemoryInfo currentMemory(CuVSResources resources) { + return null; // TODO! + } +} diff --git a/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/common/Util.java b/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/common/Util.java index 8125497078..20f50a8461 100644 --- a/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/common/Util.java +++ b/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/common/Util.java @@ -134,16 +134,6 @@ static String getLastErrorText() { } } - /** - * Get the list of compatible GPUs based on compute capability >= 7.0 and total - * memory >= 8GB - * - * @return a list of compatible GPUs. See {@link GPUInfo} - */ - public static List compatibleGPUs() throws Throwable { - return compatibleGPUs(7.0, 8192); - } - /** * Get the list of compatible GPUs based on given compute capability and total * memory @@ -180,7 +170,7 @@ public static List availableGPUs() throws Throwable { int numGpuCount = numGpus.get(C_INT, 0); List gpuInfoArr = new ArrayList(); - MemorySegment free = localArena.allocate(size_t); + // MemorySegment free = localArena.allocate(size_t); MemorySegment total = localArena.allocate(size_t); MemorySegment deviceProp = cudaDeviceProp.allocate(localArena); @@ -192,8 +182,8 @@ public static List availableGPUs() throws Throwable { returnValue = cudaGetDeviceProperties_v2(deviceProp, i); checkCudaError(returnValue, "cudaGetDeviceProperties_v2"); - returnValue = cudaMemGetInfo(free, total); - checkCudaError(returnValue, "cudaMemGetInfo"); + // returnValue = cudaMemGetInfo(free, total); + // checkCudaError(returnValue, "cudaMemGetInfo"); float computeCapability = Float.parseFloat( @@ -203,7 +193,6 @@ public static List availableGPUs() throws Throwable { new GPUInfo( i, cudaDeviceProp.name(deviceProp).getString(0), - free.get(C_LONG, 0), total.get(C_LONG, 0), computeCapability); diff --git a/java/cuvs-java/src/main/java22/com/nvidia/cuvs/spi/JDKProvider.java b/java/cuvs-java/src/main/java22/com/nvidia/cuvs/spi/JDKProvider.java index 668befe236..747b6faba1 100644 --- a/java/cuvs-java/src/main/java22/com/nvidia/cuvs/spi/JDKProvider.java +++ b/java/cuvs-java/src/main/java22/com/nvidia/cuvs/spi/JDKProvider.java @@ -100,6 +100,11 @@ public CagraIndex mergeCagraIndexes(CagraIndex[] indexes, CagraMergeParams merge return CagraIndexImpl.merge(indexes, mergeParams); } + @Override + public GPUInfoProvider gpuInfoProvider() { + return new GPUInfoProviderImpl(); + } + @Override public CuVSMatrix.Builder newMatrixBuilder(int size, int dimensions, CuVSMatrix.DataType dataType) throws UnsupportedOperationException { From 2bd9217acb34ce58da280ac00b7421f71fe7095c Mon Sep 17 00:00:00 2001 From: ldematte Date: Wed, 20 Aug 2025 15:41:26 +0200 Subject: [PATCH 3/8] GPUInfoProviderImpl implementation + IT tests --- .../java/com/nvidia/cuvs/CuVSMemoryInfo.java | 8 +- .../main/java/com/nvidia/cuvs/GPUInfo.java | 4 +- .../java/com/nvidia/cuvs/GPUInfoProvider.java | 4 +- .../cuvs/internal/GPUInfoProviderImpl.java | 35 ++++++++- .../com/nvidia/cuvs/internal/common/Util.java | 16 +--- .../java/com/nvidia/cuvs/CuVSResourcesIT.java | 3 +- .../test/java/com/nvidia/cuvs/GPUInfoIT.java | 75 +++++++++++++++++++ 7 files changed, 121 insertions(+), 24 deletions(-) create mode 100644 java/cuvs-java/src/test/java/com/nvidia/cuvs/GPUInfoIT.java diff --git a/java/cuvs-java/src/main/java/com/nvidia/cuvs/CuVSMemoryInfo.java b/java/cuvs-java/src/main/java/com/nvidia/cuvs/CuVSMemoryInfo.java index da73160fa9..cc4f1d9e84 100644 --- a/java/cuvs-java/src/main/java/com/nvidia/cuvs/CuVSMemoryInfo.java +++ b/java/cuvs-java/src/main/java/com/nvidia/cuvs/CuVSMemoryInfo.java @@ -17,7 +17,9 @@ /** * Contains memory information associated to a {@link CuVSResources} and its GPU. - * @param freeDeviceMemory free memory in bytes, as reported by the device driver - * @param freeRMMPoolMemory free memory in bytes in the RMM memory pool + * Can be extended to report different types of GPU memory linked to the resources, + * e.g. the type and capacity of the underlying RMM {@code device_memory_resource} + * + * @param freeDeviceMemoryInBytes free memory in bytes, as reported by the device driver */ -public record CuVSMemoryInfo(long freeDeviceMemory, long freeRMMPoolMemory) {} +public record CuVSMemoryInfo(long freeDeviceMemoryInBytes) {} diff --git a/java/cuvs-java/src/main/java/com/nvidia/cuvs/GPUInfo.java b/java/cuvs-java/src/main/java/com/nvidia/cuvs/GPUInfo.java index bc6f3b2eab..cb95df4d85 100644 --- a/java/cuvs-java/src/main/java/com/nvidia/cuvs/GPUInfo.java +++ b/java/cuvs-java/src/main/java/com/nvidia/cuvs/GPUInfo.java @@ -20,7 +20,7 @@ * * @param gpuId id of the GPU starting from 0 * @param name ASCII string identifying device - * @param totalMemory returned total memory in bytes + * @param totalMemoryInBytes returned total memory in bytes * @param computeCapability the compute capability of the device */ -public record GPUInfo(int gpuId, String name, long totalMemory, float computeCapability) {} +public record GPUInfo(int gpuId, String name, long totalMemoryInBytes, float computeCapability) {} diff --git a/java/cuvs-java/src/main/java/com/nvidia/cuvs/GPUInfoProvider.java b/java/cuvs-java/src/main/java/com/nvidia/cuvs/GPUInfoProvider.java index ad78d8e90a..5f31cf07fb 100644 --- a/java/cuvs-java/src/main/java/com/nvidia/cuvs/GPUInfoProvider.java +++ b/java/cuvs-java/src/main/java/com/nvidia/cuvs/GPUInfoProvider.java @@ -39,9 +39,9 @@ public interface GPUInfoProvider { List compatibleGPUs() throws Throwable; /** - * Gets memory information from pools and device associated with a {@link CuVSResources} + * Gets memory information relative to a {@link CuVSResources} * @param resources from which to obtain memory information * @return a {@link CuVSMemoryInfo} record containing the memory information */ - CuVSMemoryInfo currentMemory(CuVSResources resources); + CuVSMemoryInfo getCurrentMemoryInfo(CuVSResources resources); } diff --git a/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/GPUInfoProviderImpl.java b/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/GPUInfoProviderImpl.java index 9e29779188..014f9e5441 100644 --- a/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/GPUInfoProviderImpl.java +++ b/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/GPUInfoProviderImpl.java @@ -15,11 +15,19 @@ */ package com.nvidia.cuvs.internal; +import static com.nvidia.cuvs.internal.common.Util.checkCuVSError; +import static com.nvidia.cuvs.internal.common.Util.checkCudaError; +import static com.nvidia.cuvs.internal.panama.headers_h.cudaMemGetInfo; +import static com.nvidia.cuvs.internal.panama.headers_h.cuvsDeviceIdGet; +import static com.nvidia.cuvs.internal.panama.headers_h_1.*; + import com.nvidia.cuvs.CuVSMemoryInfo; import com.nvidia.cuvs.CuVSResources; import com.nvidia.cuvs.GPUInfo; import com.nvidia.cuvs.GPUInfoProvider; import com.nvidia.cuvs.internal.common.Util; +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; import java.util.List; public class GPUInfoProviderImpl implements GPUInfoProvider { @@ -35,7 +43,30 @@ public List compatibleGPUs() throws Throwable { } @Override - public CuVSMemoryInfo currentMemory(CuVSResources resources) { - return null; // TODO! + public CuVSMemoryInfo getCurrentMemoryInfo(CuVSResources resources) { + try (var resourcesAccess = resources.access()) { + try (var localArena = Arena.ofConfined()) { + var deviceIdPtr = localArena.allocate(C_INT); + checkCudaError(cudaGetDevice(deviceIdPtr), "cudaGetDevice"); + var currentDeviceId = deviceIdPtr.get(C_INT, 0); + + checkCuVSError(cuvsDeviceIdGet(resourcesAccess.handle(), deviceIdPtr), "cuvsDeviceIdGet"); + var resourcesDeviceId = deviceIdPtr.get(C_INT, 0); + + if (resourcesDeviceId != currentDeviceId) { + checkCudaError(cudaSetDevice(resourcesDeviceId), "cudaSetDevice"); + } + + MemorySegment freeMemoryPtr = localArena.allocate(size_t); + MemorySegment totalMemoryPtr = localArena.allocate(size_t); + checkCudaError(cudaMemGetInfo(freeMemoryPtr, totalMemoryPtr), "cudaMemGetInfo"); + + if (resourcesDeviceId != currentDeviceId) { + checkCudaError(cudaSetDevice(currentDeviceId), "cudaSetDevice"); + } + + return new CuVSMemoryInfo(freeMemoryPtr.get(size_t, 0)); + } + } } } diff --git a/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/common/Util.java b/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/common/Util.java index 20f50a8461..236d5a6165 100644 --- a/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/common/Util.java +++ b/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/common/Util.java @@ -145,10 +145,10 @@ static String getLastErrorText() { public static List compatibleGPUs(double minComputeCapability, int minDeviceMemoryMB) throws Throwable { List compatibleGPUs = new ArrayList(); - double minDeviceMemoryB = Math.pow(2, 20) * minDeviceMemoryMB; + double minDeviceMemoryB = 1048576.0f * minDeviceMemoryMB; for (GPUInfo gpuInfo : availableGPUs()) { if (gpuInfo.computeCapability() >= minComputeCapability - && gpuInfo.totalMemory() >= minDeviceMemoryB) { + && gpuInfo.totalMemoryInBytes() >= minDeviceMemoryB) { compatibleGPUs.add(gpuInfo); } } @@ -170,21 +170,11 @@ public static List availableGPUs() throws Throwable { int numGpuCount = numGpus.get(C_INT, 0); List gpuInfoArr = new ArrayList(); - // MemorySegment free = localArena.allocate(size_t); - MemorySegment total = localArena.allocate(size_t); MemorySegment deviceProp = cudaDeviceProp.allocate(localArena); for (int i = 0; i < numGpuCount; i++) { - - returnValue = cudaSetDevice(i); - checkCudaError(returnValue, "cudaSetDevice"); - returnValue = cudaGetDeviceProperties_v2(deviceProp, i); checkCudaError(returnValue, "cudaGetDeviceProperties_v2"); - - // returnValue = cudaMemGetInfo(free, total); - // checkCudaError(returnValue, "cudaMemGetInfo"); - float computeCapability = Float.parseFloat( cudaDeviceProp.major(deviceProp) + "." + cudaDeviceProp.minor(deviceProp)); @@ -193,7 +183,7 @@ public static List availableGPUs() throws Throwable { new GPUInfo( i, cudaDeviceProp.name(deviceProp).getString(0), - total.get(C_LONG, 0), + cudaDeviceProp.totalGlobalMem(deviceProp), computeCapability); gpuInfoArr.add(gpuInfo); diff --git a/java/cuvs-java/src/test/java/com/nvidia/cuvs/CuVSResourcesIT.java b/java/cuvs-java/src/test/java/com/nvidia/cuvs/CuVSResourcesIT.java index e479a6ebda..bc012f6a0e 100644 --- a/java/cuvs-java/src/test/java/com/nvidia/cuvs/CuVSResourcesIT.java +++ b/java/cuvs-java/src/test/java/com/nvidia/cuvs/CuVSResourcesIT.java @@ -18,7 +18,6 @@ import static com.carrotsearch.randomizedtesting.RandomizedTest.assumeTrue; import static org.junit.Assert.*; -import java.lang.invoke.MethodHandles; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; import org.junit.Before; @@ -28,7 +27,7 @@ public class CuVSResourcesIT extends CuVSTestCase { - private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + private static final Logger log = LoggerFactory.getLogger(CuVSResourcesIT.class); @Before public void setup() { diff --git a/java/cuvs-java/src/test/java/com/nvidia/cuvs/GPUInfoIT.java b/java/cuvs-java/src/test/java/com/nvidia/cuvs/GPUInfoIT.java new file mode 100644 index 0000000000..d6a6d8a62c --- /dev/null +++ b/java/cuvs-java/src/test/java/com/nvidia/cuvs/GPUInfoIT.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2025, NVIDIA CORPORATION. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.nvidia.cuvs; + +import static com.carrotsearch.randomizedtesting.RandomizedTest.assumeTrue; +import static org.junit.Assert.*; + +import com.nvidia.cuvs.spi.CuVSProvider; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class GPUInfoIT extends CuVSTestCase { + + private static final Logger log = LoggerFactory.getLogger(GPUInfoIT.class); + + @Before + public void setup() { + assumeTrue("not supported on " + System.getProperty("os.name"), isLinuxAmd64()); + } + + @Test + public void testAvailableAndCompatibleGpus() throws Throwable { + var gpuInfoProvider = CuVSProvider.provider().gpuInfoProvider(); + var availableGpus = gpuInfoProvider.availableGPUs(); + var compatibleGpus = gpuInfoProvider.compatibleGPUs(); + assertFalse(availableGpus.isEmpty()); + assertTrue(availableGpus.get(0).gpuId() >= 0); + for (var gpuInfo : availableGpus) { + log.info( + "Available GPU with name [{}], memory [{}MB], compute [{}]", + gpuInfo.name(), + ((float) gpuInfo.totalMemoryInBytes() / 1048576.0f), + gpuInfo.computeCapability()); + } + + assertTrue(availableGpus.size() >= compatibleGpus.size()); + log.info("Compatible GPUs: " + compatibleGpus.size()); + for (var gpuInfo : compatibleGpus) { + log.info( + "Compatible GPU with name [{}], memory [{}], compute [{}]", + gpuInfo.name(), + gpuInfo.totalMemoryInBytes(), + gpuInfo.computeCapability()); + assertTrue(gpuInfo.computeCapability() >= GPUInfoProvider.MIN_COMPUTE_CAPABILITY); + assertTrue( + gpuInfo.totalMemoryInBytes() >= GPUInfoProvider.MIN_DEVICE_MEMORY_IN_MB * 1024L * 1024L); + } + } + + @Test + public void testMemoryInfo() throws Throwable { + try (var resources = CheckedCuVSResources.create()) { + var gpuInfoProvider = CuVSProvider.provider().gpuInfoProvider(); + var memoryInfo = gpuInfoProvider.getCurrentMemoryInfo(resources); + assertNotNull(memoryInfo); + log.trace("Free memory: {}", memoryInfo.freeDeviceMemoryInBytes()); + assertTrue(memoryInfo.freeDeviceMemoryInBytes() > 0); + } + } +} From 1c784a16779b816c6694eeeaf6d213aaf72eec40 Mon Sep 17 00:00:00 2001 From: ldematte Date: Wed, 20 Aug 2025 15:48:22 +0200 Subject: [PATCH 4/8] Renaming --- .../cuvs/{CuVSMemoryInfo.java => CuVSResourcesInfo.java} | 4 ++-- .../src/main/java/com/nvidia/cuvs/GPUInfoProvider.java | 4 ++-- .../com/nvidia/cuvs/internal/GPUInfoProviderImpl.java | 6 +++--- java/cuvs-java/src/test/java/com/nvidia/cuvs/GPUInfoIT.java | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) rename java/cuvs-java/src/main/java/com/nvidia/cuvs/{CuVSMemoryInfo.java => CuVSResourcesInfo.java} (84%) diff --git a/java/cuvs-java/src/main/java/com/nvidia/cuvs/CuVSMemoryInfo.java b/java/cuvs-java/src/main/java/com/nvidia/cuvs/CuVSResourcesInfo.java similarity index 84% rename from java/cuvs-java/src/main/java/com/nvidia/cuvs/CuVSMemoryInfo.java rename to java/cuvs-java/src/main/java/com/nvidia/cuvs/CuVSResourcesInfo.java index cc4f1d9e84..6cd87d12da 100644 --- a/java/cuvs-java/src/main/java/com/nvidia/cuvs/CuVSMemoryInfo.java +++ b/java/cuvs-java/src/main/java/com/nvidia/cuvs/CuVSResourcesInfo.java @@ -16,10 +16,10 @@ package com.nvidia.cuvs; /** - * Contains memory information associated to a {@link CuVSResources} and its GPU. + * Contains performance-related information associated to a {@link CuVSResources} and its GPU. * Can be extended to report different types of GPU memory linked to the resources, * e.g. the type and capacity of the underlying RMM {@code device_memory_resource} * * @param freeDeviceMemoryInBytes free memory in bytes, as reported by the device driver */ -public record CuVSMemoryInfo(long freeDeviceMemoryInBytes) {} +public record CuVSResourcesInfo(long freeDeviceMemoryInBytes) {} diff --git a/java/cuvs-java/src/main/java/com/nvidia/cuvs/GPUInfoProvider.java b/java/cuvs-java/src/main/java/com/nvidia/cuvs/GPUInfoProvider.java index 5f31cf07fb..f34070d882 100644 --- a/java/cuvs-java/src/main/java/com/nvidia/cuvs/GPUInfoProvider.java +++ b/java/cuvs-java/src/main/java/com/nvidia/cuvs/GPUInfoProvider.java @@ -41,7 +41,7 @@ public interface GPUInfoProvider { /** * Gets memory information relative to a {@link CuVSResources} * @param resources from which to obtain memory information - * @return a {@link CuVSMemoryInfo} record containing the memory information + * @return a {@link CuVSResourcesInfo} record containing the memory information */ - CuVSMemoryInfo getCurrentMemoryInfo(CuVSResources resources); + CuVSResourcesInfo getCurrentInfo(CuVSResources resources); } diff --git a/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/GPUInfoProviderImpl.java b/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/GPUInfoProviderImpl.java index 014f9e5441..ddf0fdbdd7 100644 --- a/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/GPUInfoProviderImpl.java +++ b/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/GPUInfoProviderImpl.java @@ -21,8 +21,8 @@ import static com.nvidia.cuvs.internal.panama.headers_h.cuvsDeviceIdGet; import static com.nvidia.cuvs.internal.panama.headers_h_1.*; -import com.nvidia.cuvs.CuVSMemoryInfo; import com.nvidia.cuvs.CuVSResources; +import com.nvidia.cuvs.CuVSResourcesInfo; import com.nvidia.cuvs.GPUInfo; import com.nvidia.cuvs.GPUInfoProvider; import com.nvidia.cuvs.internal.common.Util; @@ -43,7 +43,7 @@ public List compatibleGPUs() throws Throwable { } @Override - public CuVSMemoryInfo getCurrentMemoryInfo(CuVSResources resources) { + public CuVSResourcesInfo getCurrentInfo(CuVSResources resources) { try (var resourcesAccess = resources.access()) { try (var localArena = Arena.ofConfined()) { var deviceIdPtr = localArena.allocate(C_INT); @@ -65,7 +65,7 @@ public CuVSMemoryInfo getCurrentMemoryInfo(CuVSResources resources) { checkCudaError(cudaSetDevice(currentDeviceId), "cudaSetDevice"); } - return new CuVSMemoryInfo(freeMemoryPtr.get(size_t, 0)); + return new CuVSResourcesInfo(freeMemoryPtr.get(size_t, 0)); } } } diff --git a/java/cuvs-java/src/test/java/com/nvidia/cuvs/GPUInfoIT.java b/java/cuvs-java/src/test/java/com/nvidia/cuvs/GPUInfoIT.java index d6a6d8a62c..3ec6c6b340 100644 --- a/java/cuvs-java/src/test/java/com/nvidia/cuvs/GPUInfoIT.java +++ b/java/cuvs-java/src/test/java/com/nvidia/cuvs/GPUInfoIT.java @@ -66,7 +66,7 @@ public void testAvailableAndCompatibleGpus() throws Throwable { public void testMemoryInfo() throws Throwable { try (var resources = CheckedCuVSResources.create()) { var gpuInfoProvider = CuVSProvider.provider().gpuInfoProvider(); - var memoryInfo = gpuInfoProvider.getCurrentMemoryInfo(resources); + var memoryInfo = gpuInfoProvider.getCurrentInfo(resources); assertNotNull(memoryInfo); log.trace("Free memory: {}", memoryInfo.freeDeviceMemoryInBytes()); assertTrue(memoryInfo.freeDeviceMemoryInBytes() > 0); From e9f32b8a53a1cd004d620998098386ff6a0cd2ad Mon Sep 17 00:00:00 2001 From: ldematte Date: Wed, 20 Aug 2025 16:15:22 +0200 Subject: [PATCH 5/8] More renaming, exposing totalDeviceMemoryInBytes to getCurrentInfo for convenience --- .../main/java/com/nvidia/cuvs/CuVSResourcesInfo.java | 3 ++- .../src/main/java/com/nvidia/cuvs/GPUInfo.java | 11 ++++++----- .../com/nvidia/cuvs/internal/GPUInfoProviderImpl.java | 2 +- .../java22/com/nvidia/cuvs/internal/common/Util.java | 2 +- .../src/test/java/com/nvidia/cuvs/GPUInfoIT.java | 7 ++++--- 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/java/cuvs-java/src/main/java/com/nvidia/cuvs/CuVSResourcesInfo.java b/java/cuvs-java/src/main/java/com/nvidia/cuvs/CuVSResourcesInfo.java index 6cd87d12da..a100091f12 100644 --- a/java/cuvs-java/src/main/java/com/nvidia/cuvs/CuVSResourcesInfo.java +++ b/java/cuvs-java/src/main/java/com/nvidia/cuvs/CuVSResourcesInfo.java @@ -21,5 +21,6 @@ * e.g. the type and capacity of the underlying RMM {@code device_memory_resource} * * @param freeDeviceMemoryInBytes free memory in bytes, as reported by the device driver + * @param totalDeviceMemoryInBytes total device memory in bytes */ -public record CuVSResourcesInfo(long freeDeviceMemoryInBytes) {} +public record CuVSResourcesInfo(long freeDeviceMemoryInBytes, long totalDeviceMemoryInBytes) {} diff --git a/java/cuvs-java/src/main/java/com/nvidia/cuvs/GPUInfo.java b/java/cuvs-java/src/main/java/com/nvidia/cuvs/GPUInfo.java index cb95df4d85..e5754aedf7 100644 --- a/java/cuvs-java/src/main/java/com/nvidia/cuvs/GPUInfo.java +++ b/java/cuvs-java/src/main/java/com/nvidia/cuvs/GPUInfo.java @@ -18,9 +18,10 @@ /** * Contains GPU information * - * @param gpuId id of the GPU starting from 0 - * @param name ASCII string identifying device - * @param totalMemoryInBytes returned total memory in bytes - * @param computeCapability the compute capability of the device + * @param gpuId id of the GPU starting from 0 + * @param name ASCII string identifying device + * @param totalDeviceMemoryInBytes total device memory in bytes + * @param computeCapability the compute capability of the device */ -public record GPUInfo(int gpuId, String name, long totalMemoryInBytes, float computeCapability) {} +public record GPUInfo( + int gpuId, String name, long totalDeviceMemoryInBytes, float computeCapability) {} diff --git a/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/GPUInfoProviderImpl.java b/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/GPUInfoProviderImpl.java index ddf0fdbdd7..390720dde5 100644 --- a/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/GPUInfoProviderImpl.java +++ b/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/GPUInfoProviderImpl.java @@ -65,7 +65,7 @@ public CuVSResourcesInfo getCurrentInfo(CuVSResources resources) { checkCudaError(cudaSetDevice(currentDeviceId), "cudaSetDevice"); } - return new CuVSResourcesInfo(freeMemoryPtr.get(size_t, 0)); + return new CuVSResourcesInfo(freeMemoryPtr.get(size_t, 0), totalMemoryPtr.get(size_t, 0)); } } } diff --git a/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/common/Util.java b/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/common/Util.java index 236d5a6165..545fa19315 100644 --- a/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/common/Util.java +++ b/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/common/Util.java @@ -148,7 +148,7 @@ public static List compatibleGPUs(double minComputeCapability, int minD double minDeviceMemoryB = 1048576.0f * minDeviceMemoryMB; for (GPUInfo gpuInfo : availableGPUs()) { if (gpuInfo.computeCapability() >= minComputeCapability - && gpuInfo.totalMemoryInBytes() >= minDeviceMemoryB) { + && gpuInfo.totalDeviceMemoryInBytes() >= minDeviceMemoryB) { compatibleGPUs.add(gpuInfo); } } diff --git a/java/cuvs-java/src/test/java/com/nvidia/cuvs/GPUInfoIT.java b/java/cuvs-java/src/test/java/com/nvidia/cuvs/GPUInfoIT.java index 3ec6c6b340..a27e622fee 100644 --- a/java/cuvs-java/src/test/java/com/nvidia/cuvs/GPUInfoIT.java +++ b/java/cuvs-java/src/test/java/com/nvidia/cuvs/GPUInfoIT.java @@ -44,7 +44,7 @@ public void testAvailableAndCompatibleGpus() throws Throwable { log.info( "Available GPU with name [{}], memory [{}MB], compute [{}]", gpuInfo.name(), - ((float) gpuInfo.totalMemoryInBytes() / 1048576.0f), + ((float) gpuInfo.totalDeviceMemoryInBytes() / 1048576.0f), gpuInfo.computeCapability()); } @@ -54,11 +54,12 @@ public void testAvailableAndCompatibleGpus() throws Throwable { log.info( "Compatible GPU with name [{}], memory [{}], compute [{}]", gpuInfo.name(), - gpuInfo.totalMemoryInBytes(), + gpuInfo.totalDeviceMemoryInBytes(), gpuInfo.computeCapability()); assertTrue(gpuInfo.computeCapability() >= GPUInfoProvider.MIN_COMPUTE_CAPABILITY); assertTrue( - gpuInfo.totalMemoryInBytes() >= GPUInfoProvider.MIN_DEVICE_MEMORY_IN_MB * 1024L * 1024L); + gpuInfo.totalDeviceMemoryInBytes() + >= GPUInfoProvider.MIN_DEVICE_MEMORY_IN_MB * 1024L * 1024L); } } From 02e578857d026a2bdaf5ddcd10b4bc81ae581338 Mon Sep 17 00:00:00 2001 From: ldematte Date: Thu, 21 Aug 2025 10:45:36 +0200 Subject: [PATCH 6/8] Separate major/minor, add more GPUInfo stats, adjust IT test logging --- .../main/java/com/nvidia/cuvs/GPUInfo.java | 21 +++++++++++---- .../java/com/nvidia/cuvs/GPUInfoProvider.java | 3 ++- .../cuvs/internal/GPUInfoProviderImpl.java | 3 ++- .../com/nvidia/cuvs/internal/common/Util.java | 27 ++++++++++++------- .../test/java/com/nvidia/cuvs/GPUInfoIT.java | 22 ++++++++------- 5 files changed, 49 insertions(+), 27 deletions(-) diff --git a/java/cuvs-java/src/main/java/com/nvidia/cuvs/GPUInfo.java b/java/cuvs-java/src/main/java/com/nvidia/cuvs/GPUInfo.java index e5754aedf7..8d24df9aae 100644 --- a/java/cuvs-java/src/main/java/com/nvidia/cuvs/GPUInfo.java +++ b/java/cuvs-java/src/main/java/com/nvidia/cuvs/GPUInfo.java @@ -18,10 +18,21 @@ /** * Contains GPU information * - * @param gpuId id of the GPU starting from 0 - * @param name ASCII string identifying device - * @param totalDeviceMemoryInBytes total device memory in bytes - * @param computeCapability the compute capability of the device + * @param gpuId id of the GPU starting from 0 + * @param name ASCII string identifying device + * @param totalDeviceMemoryInBytes total device memory in bytes + * @param computeCapabilityMajor the compute capability of the device (major) + * @param computeCapabilityMinor the compute capability of the device (minor) + * @param supportsConcurrentCopy whether the device can concurrently copy memory between host and device while + * executing a kernel + * @param supportsConcurrentKernels whether the device supports executing multiple kernels within the same context + * simultaneously */ public record GPUInfo( - int gpuId, String name, long totalDeviceMemoryInBytes, float computeCapability) {} + int gpuId, + String name, + long totalDeviceMemoryInBytes, + int computeCapabilityMajor, + int computeCapabilityMinor, + boolean supportsConcurrentCopy, + boolean supportsConcurrentKernels) {} diff --git a/java/cuvs-java/src/main/java/com/nvidia/cuvs/GPUInfoProvider.java b/java/cuvs-java/src/main/java/com/nvidia/cuvs/GPUInfoProvider.java index f34070d882..e5568bc879 100644 --- a/java/cuvs-java/src/main/java/com/nvidia/cuvs/GPUInfoProvider.java +++ b/java/cuvs-java/src/main/java/com/nvidia/cuvs/GPUInfoProvider.java @@ -19,7 +19,8 @@ public interface GPUInfoProvider { - float MIN_COMPUTE_CAPABILITY = 7.0f; + int MIN_COMPUTE_CAPABILITY_MAJOR = 7; + int MIN_COMPUTE_CAPABILITY_MINOR = 0; int MIN_DEVICE_MEMORY_IN_MB = 8192; diff --git a/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/GPUInfoProviderImpl.java b/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/GPUInfoProviderImpl.java index 390720dde5..2ed3c79674 100644 --- a/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/GPUInfoProviderImpl.java +++ b/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/GPUInfoProviderImpl.java @@ -39,7 +39,8 @@ public List availableGPUs() throws Throwable { @Override public List compatibleGPUs() throws Throwable { - return Util.compatibleGPUs(MIN_COMPUTE_CAPABILITY, MIN_DEVICE_MEMORY_IN_MB); + return Util.compatibleGPUs( + MIN_COMPUTE_CAPABILITY_MAJOR, MIN_COMPUTE_CAPABILITY_MINOR, MIN_DEVICE_MEMORY_IN_MB); } @Override diff --git a/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/common/Util.java b/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/common/Util.java index 545fa19315..37fcd42c1f 100644 --- a/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/common/Util.java +++ b/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/common/Util.java @@ -138,23 +138,30 @@ static String getLastErrorText() { * Get the list of compatible GPUs based on given compute capability and total * memory * - * @param minComputeCapability the minimum compute capability - * @param minDeviceMemoryMB the minimum total available memory in MB + * @param minComputeCapabilityMajor the minimum compute capability (major) + * @param minComputeCapabilityMinor the minimum compute capability (minor) + * @param minDeviceMemoryMB the minimum total available memory in MB * @return a list of compatible GPUs. See {@link GPUInfo} */ - public static List compatibleGPUs(double minComputeCapability, int minDeviceMemoryMB) + public static List compatibleGPUs( + int minComputeCapabilityMajor, int minComputeCapabilityMinor, int minDeviceMemoryMB) throws Throwable { List compatibleGPUs = new ArrayList(); - double minDeviceMemoryB = 1048576.0f * minDeviceMemoryMB; + long minDeviceMemoryInBytes = 1024L * 1024L * minDeviceMemoryMB; for (GPUInfo gpuInfo : availableGPUs()) { - if (gpuInfo.computeCapability() >= minComputeCapability - && gpuInfo.totalDeviceMemoryInBytes() >= minDeviceMemoryB) { + if (hasMinimumCapability(minComputeCapabilityMajor, minComputeCapabilityMinor, gpuInfo) + && gpuInfo.totalDeviceMemoryInBytes() >= minDeviceMemoryInBytes) { compatibleGPUs.add(gpuInfo); } } return compatibleGPUs; } + private static boolean hasMinimumCapability(int major, int minor, GPUInfo gpuInfo) { + return gpuInfo.computeCapabilityMajor() > major + || (gpuInfo.computeCapabilityMajor() == major && gpuInfo.computeCapabilityMinor() >= minor); + } + /** * Gets all the available GPUs * @@ -175,16 +182,16 @@ public static List availableGPUs() throws Throwable { for (int i = 0; i < numGpuCount; i++) { returnValue = cudaGetDeviceProperties_v2(deviceProp, i); checkCudaError(returnValue, "cudaGetDeviceProperties_v2"); - float computeCapability = - Float.parseFloat( - cudaDeviceProp.major(deviceProp) + "." + cudaDeviceProp.minor(deviceProp)); GPUInfo gpuInfo = new GPUInfo( i, cudaDeviceProp.name(deviceProp).getString(0), cudaDeviceProp.totalGlobalMem(deviceProp), - computeCapability); + cudaDeviceProp.major(deviceProp), + cudaDeviceProp.minor(deviceProp), + cudaDeviceProp.asyncEngineCount(deviceProp) > 0, + cudaDeviceProp.concurrentKernels(deviceProp) > 0); gpuInfoArr.add(gpuInfo); } diff --git a/java/cuvs-java/src/test/java/com/nvidia/cuvs/GPUInfoIT.java b/java/cuvs-java/src/test/java/com/nvidia/cuvs/GPUInfoIT.java index a27e622fee..1284df2d31 100644 --- a/java/cuvs-java/src/test/java/com/nvidia/cuvs/GPUInfoIT.java +++ b/java/cuvs-java/src/test/java/com/nvidia/cuvs/GPUInfoIT.java @@ -41,22 +41,24 @@ public void testAvailableAndCompatibleGpus() throws Throwable { assertFalse(availableGpus.isEmpty()); assertTrue(availableGpus.get(0).gpuId() >= 0); for (var gpuInfo : availableGpus) { - log.info( - "Available GPU with name [{}], memory [{}MB], compute [{}]", + log.trace( + "Available GPU with name [{}], memory [{}MB], compute [{}.{}]", gpuInfo.name(), - ((float) gpuInfo.totalDeviceMemoryInBytes() / 1048576.0f), - gpuInfo.computeCapability()); + gpuInfo.totalDeviceMemoryInBytes() / (1024L * 1024L), + gpuInfo.computeCapabilityMajor(), + gpuInfo.computeCapabilityMinor()); } assertTrue(availableGpus.size() >= compatibleGpus.size()); - log.info("Compatible GPUs: " + compatibleGpus.size()); + log.trace("Compatible GPUs: [{}]", compatibleGpus.size()); for (var gpuInfo : compatibleGpus) { - log.info( - "Compatible GPU with name [{}], memory [{}], compute [{}]", + log.trace( + "Compatible GPU with name [{}], memory [{}MB], compute [{}.{}]", gpuInfo.name(), - gpuInfo.totalDeviceMemoryInBytes(), - gpuInfo.computeCapability()); - assertTrue(gpuInfo.computeCapability() >= GPUInfoProvider.MIN_COMPUTE_CAPABILITY); + gpuInfo.totalDeviceMemoryInBytes() / (1024L * 1024L), + gpuInfo.computeCapabilityMajor(), + gpuInfo.computeCapabilityMinor()); + assertTrue(gpuInfo.computeCapabilityMajor() >= GPUInfoProvider.MIN_COMPUTE_CAPABILITY_MAJOR); assertTrue( gpuInfo.totalDeviceMemoryInBytes() >= GPUInfoProvider.MIN_DEVICE_MEMORY_IN_MB * 1024L * 1024L); From d6ac665277159e5f288997f9cd1610e74f721fa2 Mon Sep 17 00:00:00 2001 From: ldematte Date: Thu, 21 Aug 2025 12:37:45 +0200 Subject: [PATCH 7/8] Moved deviceId to CuVSResources --- .../java/com/nvidia/cuvs/CuVSResources.java | 7 ++++ .../cuvs/SynchronizedCuVSResources.java | 5 +++ .../cuvs/internal/CuVSResourcesImpl.java | 17 ++++++--- .../cuvs/internal/GPUInfoProviderImpl.java | 35 ++++++++----------- .../com/nvidia/cuvs/CheckedCuVSResources.java | 5 +++ 5 files changed, 43 insertions(+), 26 deletions(-) diff --git a/java/cuvs-java/src/main/java/com/nvidia/cuvs/CuVSResources.java b/java/cuvs-java/src/main/java/com/nvidia/cuvs/CuVSResources.java index 2d362b6c4c..b44e50e890 100644 --- a/java/cuvs-java/src/main/java/com/nvidia/cuvs/CuVSResources.java +++ b/java/cuvs-java/src/main/java/com/nvidia/cuvs/CuVSResources.java @@ -49,6 +49,13 @@ interface ScopedAccess extends AutoCloseable { */ ScopedAccess access(); + /** + * Get the logical id of the device associated with this resources object. + * Information about the device id is immutable, so it is safe to expose it without getting {@link ScopedAccess} + * to the enclosing resources. + */ + int deviceId(); + /** * Closes this CuVSResources object and releases any resources associated with it. */ diff --git a/java/cuvs-java/src/main/java/com/nvidia/cuvs/SynchronizedCuVSResources.java b/java/cuvs-java/src/main/java/com/nvidia/cuvs/SynchronizedCuVSResources.java index bbba262bb0..6f17d27317 100644 --- a/java/cuvs-java/src/main/java/com/nvidia/cuvs/SynchronizedCuVSResources.java +++ b/java/cuvs-java/src/main/java/com/nvidia/cuvs/SynchronizedCuVSResources.java @@ -51,6 +51,11 @@ public void close() { }; } + @Override + public int deviceId() { + return inner.deviceId(); + } + @Override public void close() { inner.close(); diff --git a/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/CuVSResourcesImpl.java b/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/CuVSResourcesImpl.java index 8f9e1d94d0..ef1b9cdab7 100644 --- a/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/CuVSResourcesImpl.java +++ b/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/CuVSResourcesImpl.java @@ -16,9 +16,8 @@ package com.nvidia.cuvs.internal; import static com.nvidia.cuvs.internal.common.Util.checkCuVSError; -import static com.nvidia.cuvs.internal.panama.headers_h.cuvsResourcesCreate; -import static com.nvidia.cuvs.internal.panama.headers_h.cuvsResourcesDestroy; -import static com.nvidia.cuvs.internal.panama.headers_h.cuvsResources_t; +import static com.nvidia.cuvs.internal.panama.headers_h.*; +import static com.nvidia.cuvs.internal.panama.headers_h_1.C_INT; import com.nvidia.cuvs.CuVSResources; import java.lang.foreign.Arena; @@ -34,6 +33,7 @@ public class CuVSResourcesImpl implements CuVSResources { private final Path tempDirectory; private final long resourceHandle; private final ScopedAccess access; + private final int deviceId; /** * Constructor that allocates the resources needed for cuVS @@ -43,9 +43,11 @@ public CuVSResourcesImpl(Path tempDirectory) { this.tempDirectory = tempDirectory; try (var localArena = Arena.ofConfined()) { var resourcesMemorySegment = localArena.allocate(cuvsResources_t); - int returnValue = cuvsResourcesCreate(resourcesMemorySegment); - checkCuVSError(returnValue, "cuvsResourcesCreate"); + checkCuVSError(cuvsResourcesCreate(resourcesMemorySegment), "cuvsResourcesCreate"); this.resourceHandle = resourcesMemorySegment.get(cuvsResources_t, 0); + var deviceIdPtr = localArena.allocate(C_INT); + checkCuVSError(cuvsDeviceIdGet(resourceHandle, deviceIdPtr), "cuvsDeviceIdGet"); + this.deviceId = deviceIdPtr.get(C_INT, 0); this.access = new ScopedAccess() { @Override @@ -64,6 +66,11 @@ public ScopedAccess access() { return this.access; } + @Override + public int deviceId() { + return this.deviceId; + } + @Override public void close() { synchronized (this) { diff --git a/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/GPUInfoProviderImpl.java b/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/GPUInfoProviderImpl.java index 2ed3c79674..a11c3af73c 100644 --- a/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/GPUInfoProviderImpl.java +++ b/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/GPUInfoProviderImpl.java @@ -15,10 +15,8 @@ */ package com.nvidia.cuvs.internal; -import static com.nvidia.cuvs.internal.common.Util.checkCuVSError; import static com.nvidia.cuvs.internal.common.Util.checkCudaError; import static com.nvidia.cuvs.internal.panama.headers_h.cudaMemGetInfo; -import static com.nvidia.cuvs.internal.panama.headers_h.cuvsDeviceIdGet; import static com.nvidia.cuvs.internal.panama.headers_h_1.*; import com.nvidia.cuvs.CuVSResources; @@ -45,29 +43,24 @@ public List compatibleGPUs() throws Throwable { @Override public CuVSResourcesInfo getCurrentInfo(CuVSResources resources) { - try (var resourcesAccess = resources.access()) { - try (var localArena = Arena.ofConfined()) { - var deviceIdPtr = localArena.allocate(C_INT); - checkCudaError(cudaGetDevice(deviceIdPtr), "cudaGetDevice"); - var currentDeviceId = deviceIdPtr.get(C_INT, 0); + try (var localArena = Arena.ofConfined()) { + var deviceIdPtr = localArena.allocate(C_INT); + checkCudaError(cudaGetDevice(deviceIdPtr), "cudaGetDevice"); + var currentDeviceId = deviceIdPtr.get(C_INT, 0); - checkCuVSError(cuvsDeviceIdGet(resourcesAccess.handle(), deviceIdPtr), "cuvsDeviceIdGet"); - var resourcesDeviceId = deviceIdPtr.get(C_INT, 0); - - if (resourcesDeviceId != currentDeviceId) { - checkCudaError(cudaSetDevice(resourcesDeviceId), "cudaSetDevice"); - } - - MemorySegment freeMemoryPtr = localArena.allocate(size_t); - MemorySegment totalMemoryPtr = localArena.allocate(size_t); - checkCudaError(cudaMemGetInfo(freeMemoryPtr, totalMemoryPtr), "cudaMemGetInfo"); + if (resources.deviceId() != currentDeviceId) { + checkCudaError(cudaSetDevice(resources.deviceId()), "cudaSetDevice"); + } - if (resourcesDeviceId != currentDeviceId) { - checkCudaError(cudaSetDevice(currentDeviceId), "cudaSetDevice"); - } + MemorySegment freeMemoryPtr = localArena.allocate(size_t); + MemorySegment totalMemoryPtr = localArena.allocate(size_t); + checkCudaError(cudaMemGetInfo(freeMemoryPtr, totalMemoryPtr), "cudaMemGetInfo"); - return new CuVSResourcesInfo(freeMemoryPtr.get(size_t, 0), totalMemoryPtr.get(size_t, 0)); + if (resources.deviceId() != currentDeviceId) { + checkCudaError(cudaSetDevice(currentDeviceId), "cudaSetDevice"); } + + return new CuVSResourcesInfo(freeMemoryPtr.get(size_t, 0), totalMemoryPtr.get(size_t, 0)); } } } diff --git a/java/cuvs-java/src/test/java/com/nvidia/cuvs/CheckedCuVSResources.java b/java/cuvs-java/src/test/java/com/nvidia/cuvs/CheckedCuVSResources.java index a58d9c04e7..581e29973c 100644 --- a/java/cuvs-java/src/test/java/com/nvidia/cuvs/CheckedCuVSResources.java +++ b/java/cuvs-java/src/test/java/com/nvidia/cuvs/CheckedCuVSResources.java @@ -61,6 +61,11 @@ public void close() { }; } + @Override + public int deviceId() { + return inner.deviceId(); + } + @Override public void close() { destroyed = true; From da0b79bab610aea0a5f06cdd30e3b30ee551c4f0 Mon Sep 17 00:00:00 2001 From: ldematte Date: Tue, 26 Aug 2025 10:21:10 +0200 Subject: [PATCH 8/8] Review: cache GPUInfo --- .../java/com/nvidia/cuvs/GPUInfoProvider.java | 4 +- .../cuvs/internal/GPUInfoProviderImpl.java | 67 ++++++++++++++++-- .../com/nvidia/cuvs/internal/common/Util.java | 69 ------------------- 3 files changed, 63 insertions(+), 77 deletions(-) diff --git a/java/cuvs-java/src/main/java/com/nvidia/cuvs/GPUInfoProvider.java b/java/cuvs-java/src/main/java/com/nvidia/cuvs/GPUInfoProvider.java index e5568bc879..fe03934df0 100644 --- a/java/cuvs-java/src/main/java/com/nvidia/cuvs/GPUInfoProvider.java +++ b/java/cuvs-java/src/main/java/com/nvidia/cuvs/GPUInfoProvider.java @@ -29,7 +29,7 @@ public interface GPUInfoProvider { * * @return a list of {@link GPUInfo} objects with GPU details */ - List availableGPUs() throws Throwable; + List availableGPUs(); /** * Get the list of compatible GPUs based on compute capability >= 7.0 and total @@ -37,7 +37,7 @@ public interface GPUInfoProvider { * * @return a list of compatible GPUs. See {@link GPUInfo} */ - List compatibleGPUs() throws Throwable; + List compatibleGPUs(); /** * Gets memory information relative to a {@link CuVSResources} diff --git a/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/GPUInfoProviderImpl.java b/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/GPUInfoProviderImpl.java index a11c3af73c..c2422318ac 100644 --- a/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/GPUInfoProviderImpl.java +++ b/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/GPUInfoProviderImpl.java @@ -15,6 +15,7 @@ */ package com.nvidia.cuvs.internal; +import static com.nvidia.cuvs.internal.common.LinkerHelper.C_INT; import static com.nvidia.cuvs.internal.common.Util.checkCudaError; import static com.nvidia.cuvs.internal.panama.headers_h.cudaMemGetInfo; import static com.nvidia.cuvs.internal.panama.headers_h_1.*; @@ -23,22 +24,76 @@ import com.nvidia.cuvs.CuVSResourcesInfo; import com.nvidia.cuvs.GPUInfo; import com.nvidia.cuvs.GPUInfoProvider; -import com.nvidia.cuvs.internal.common.Util; +import com.nvidia.cuvs.internal.panama.cudaDeviceProp; import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; +import java.util.ArrayList; import java.util.List; public class GPUInfoProviderImpl implements GPUInfoProvider { + // Lazy initialization for list of available GPUs. + private static class AvailableGpuInitializer { + + // Available GPUs are initialized only once when first accessed. + // This is assumed to be invariant for the lifetime of the program. + static final List AVAILABLE_GPUS = getAvailableGpusInfo(); + + private static List getAvailableGpusInfo() { + try (var localArena = Arena.ofConfined()) { + + MemorySegment numGpus = localArena.allocate(C_INT); + int returnValue = cudaGetDeviceCount(numGpus); + checkCudaError(returnValue, "cudaGetDeviceCount"); + + int numGpuCount = numGpus.get(C_INT, 0); + List gpuInfoArr = new ArrayList(); + + MemorySegment deviceProp = cudaDeviceProp.allocate(localArena); + + for (int i = 0; i < numGpuCount; i++) { + returnValue = cudaGetDeviceProperties_v2(deviceProp, i); + checkCudaError(returnValue, "cudaGetDeviceProperties_v2"); + + GPUInfo gpuInfo = + new GPUInfo( + i, + cudaDeviceProp.name(deviceProp).getString(0), + cudaDeviceProp.totalGlobalMem(deviceProp), + cudaDeviceProp.major(deviceProp), + cudaDeviceProp.minor(deviceProp), + cudaDeviceProp.asyncEngineCount(deviceProp) > 0, + cudaDeviceProp.concurrentKernels(deviceProp) > 0); + + gpuInfoArr.add(gpuInfo); + } + return gpuInfoArr; + } + } + } + + private static boolean hasMinimumCapability(GPUInfo gpuInfo) { + return gpuInfo.computeCapabilityMajor() > GPUInfoProvider.MIN_COMPUTE_CAPABILITY_MAJOR + || (gpuInfo.computeCapabilityMajor() == GPUInfoProvider.MIN_COMPUTE_CAPABILITY_MAJOR + && gpuInfo.computeCapabilityMinor() >= GPUInfoProvider.MIN_COMPUTE_CAPABILITY_MINOR); + } + @Override - public List availableGPUs() throws Throwable { - return Util.availableGPUs(); + public List availableGPUs() { + return AvailableGpuInitializer.AVAILABLE_GPUS; } @Override - public List compatibleGPUs() throws Throwable { - return Util.compatibleGPUs( - MIN_COMPUTE_CAPABILITY_MAJOR, MIN_COMPUTE_CAPABILITY_MINOR, MIN_DEVICE_MEMORY_IN_MB); + public List compatibleGPUs() { + List compatibleGPUs = new ArrayList<>(); + long minDeviceMemoryInBytes = 1024L * 1024L * GPUInfoProvider.MIN_DEVICE_MEMORY_IN_MB; + for (GPUInfo gpuInfo : AvailableGpuInitializer.AVAILABLE_GPUS) { + if (hasMinimumCapability(gpuInfo) + && gpuInfo.totalDeviceMemoryInBytes() >= minDeviceMemoryInBytes) { + compatibleGPUs.add(gpuInfo); + } + } + return compatibleGPUs; } @Override diff --git a/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/common/Util.java b/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/common/Util.java index 939d6bbdb4..09adf59309 100644 --- a/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/common/Util.java +++ b/java/cuvs-java/src/main/java22/com/nvidia/cuvs/internal/common/Util.java @@ -23,12 +23,10 @@ import static com.nvidia.cuvs.internal.panama.headers_h_1.cudaStream_t; import com.nvidia.cuvs.CuVSResources; -import com.nvidia.cuvs.GPUInfo; import com.nvidia.cuvs.internal.panama.DLDataType; import com.nvidia.cuvs.internal.panama.DLDevice; import com.nvidia.cuvs.internal.panama.DLManagedTensor; import com.nvidia.cuvs.internal.panama.DLTensor; -import com.nvidia.cuvs.internal.panama.cudaDeviceProp; import com.nvidia.cuvs.internal.panama.headers_h; import java.lang.foreign.Arena; import java.lang.foreign.Linker; @@ -37,9 +35,7 @@ import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandle; import java.lang.invoke.VarHandle; -import java.util.ArrayList; import java.util.BitSet; -import java.util.List; public class Util { @@ -187,71 +183,6 @@ static String getLastErrorText() { } } - /** - * Get the list of compatible GPUs based on given compute capability and total - * memory - * - * @param minComputeCapabilityMajor the minimum compute capability (major) - * @param minComputeCapabilityMinor the minimum compute capability (minor) - * @param minDeviceMemoryMB the minimum total available memory in MB - * @return a list of compatible GPUs. See {@link GPUInfo} - */ - public static List compatibleGPUs( - int minComputeCapabilityMajor, int minComputeCapabilityMinor, int minDeviceMemoryMB) - throws Throwable { - List compatibleGPUs = new ArrayList(); - long minDeviceMemoryInBytes = 1024L * 1024L * minDeviceMemoryMB; - for (GPUInfo gpuInfo : availableGPUs()) { - if (hasMinimumCapability(minComputeCapabilityMajor, minComputeCapabilityMinor, gpuInfo) - && gpuInfo.totalDeviceMemoryInBytes() >= minDeviceMemoryInBytes) { - compatibleGPUs.add(gpuInfo); - } - } - return compatibleGPUs; - } - - private static boolean hasMinimumCapability(int major, int minor, GPUInfo gpuInfo) { - return gpuInfo.computeCapabilityMajor() > major - || (gpuInfo.computeCapabilityMajor() == major && gpuInfo.computeCapabilityMinor() >= minor); - } - - /** - * Gets all the available GPUs - * - * @return a list of {@link GPUInfo} objects with GPU details - */ - public static List availableGPUs() throws Throwable { - try (var localArena = Arena.ofConfined()) { - - MemorySegment numGpus = localArena.allocate(C_INT); - int returnValue = cudaGetDeviceCount(numGpus); - checkCudaError(returnValue, "cudaGetDeviceCount"); - - int numGpuCount = numGpus.get(C_INT, 0); - List gpuInfoArr = new ArrayList(); - - MemorySegment deviceProp = cudaDeviceProp.allocate(localArena); - - for (int i = 0; i < numGpuCount; i++) { - returnValue = cudaGetDeviceProperties_v2(deviceProp, i); - checkCudaError(returnValue, "cudaGetDeviceProperties_v2"); - - GPUInfo gpuInfo = - new GPUInfo( - i, - cudaDeviceProp.name(deviceProp).getString(0), - cudaDeviceProp.totalGlobalMem(deviceProp), - cudaDeviceProp.major(deviceProp), - cudaDeviceProp.minor(deviceProp), - cudaDeviceProp.asyncEngineCount(deviceProp) > 0, - cudaDeviceProp.concurrentKernels(deviceProp) > 0); - - gpuInfoArr.add(gpuInfo); - } - return gpuInfoArr; - } - } - /** * A utility method for getting an instance of {@link MemorySegment} for a * {@link String}.