Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 17 additions & 36 deletions source/MRCuda/MRCudaBasic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,58 +13,39 @@ namespace MR
namespace Cuda
{

bool isCudaAvailable( int* driverVersionOut, int* runtimeVersionOut, int* computeMajorOut, int* computeMinorOut )
Expected<RuntimeInfo> getRuntimeInfo()
{
int n;
cudaError_t err = cudaGetDeviceCount( &n );
if ( err != cudaSuccess )
return false;
CUDA_RETURN_UNEXPECTED( cudaGetDeviceCount( &n ) );
if ( n <= 0 )
return false;
int driverVersion{ 0 };
int runtimeVersion{ 0 };
err = cudaDriverGetVersion( &driverVersion );
if ( err != cudaSuccess )
return false;

err = cudaRuntimeGetVersion( &runtimeVersion );
if ( err != cudaSuccess )
return false;

int computeMajor{ 0 };
int computeMinor{ 0 };
err = cudaDeviceGetAttribute( &computeMajor, cudaDevAttrComputeCapabilityMajor, 0 );
if ( err != cudaSuccess )
return false;
err = cudaDeviceGetAttribute( &computeMinor, cudaDevAttrComputeCapabilityMinor, 0 );
if ( err != cudaSuccess )
return false;

if ( driverVersionOut )
*driverVersionOut = driverVersion;
if ( runtimeVersionOut )
*runtimeVersionOut = runtimeVersion;
if ( computeMajorOut )
*computeMajorOut = computeMajor;
if ( computeMinorOut )
*computeMinorOut = computeMinor;
return MR::unexpected( "NVIDIA GPU error: no single device" );

RuntimeInfo res;
CUDA_RETURN_UNEXPECTED( cudaDriverGetVersion( &res.driverVersion ) );
CUDA_RETURN_UNEXPECTED( cudaRuntimeGetVersion( &res.runtimeVersion ) );
CUDA_RETURN_UNEXPECTED( cudaDeviceGetAttribute( &res.computeMajor, cudaDevAttrComputeCapabilityMajor, 0 ) );
CUDA_RETURN_UNEXPECTED( cudaDeviceGetAttribute( &res.computeMinor, cudaDevAttrComputeCapabilityMinor, 0 ) );
return res;
}

bool RuntimeInfo::fitForComputations() const
{
// according to https://en.wikipedia.org/wiki/CUDA Compute Capability (CUDA SDK support vs. Microarchitecture) table
if ( runtimeVersion / 1000 >= 12 && computeMajor < 5 )
return false;
else if ( runtimeVersion / 1000 > 10 && ( computeMajor < 3 || ( computeMajor == 3 && computeMinor < 5 ) ) )
if ( runtimeVersion / 1000 > 10 && ( computeMajor < 3 || ( computeMajor == 3 && computeMinor < 5 ) ) )
return false;

return runtimeVersion <= driverVersion;
}

size_t getCudaAvailableMemory()
{
if ( !isCudaAvailable() )
if ( CUDA_EXEC( cudaSetDevice( 0 ) ) != cudaSuccess )
return 0;
CUDA_EXEC( cudaSetDevice( 0 ) );
size_t memFree = 0, memTot = 0;
CUDA_EXEC( cudaMemGetInfo( &memFree, &memTot ) );
if ( CUDA_EXEC( cudaMemGetInfo( &memFree, &memTot ) ) )
return 0;
// minus extra 128 MB
return memFree - 128 * 1024 * 1024;
}
Expand Down
37 changes: 26 additions & 11 deletions source/MRCuda/MRCudaBasic.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,46 @@
#include "exports.h"

#include "MRMesh/MRMeshFwd.h"
#include "MRMesh/MRExpected.h"

namespace MR
{

namespace Cuda
{

// Returns true if Cuda is present on this GPU
// optional out maximum driver supported version
// optional out current runtime version
// optional out compute capability major version
// optional out compute capability minor version
MRCUDA_API bool isCudaAvailable( int* driverVersion = nullptr, int* runtimeVersion = nullptr, int* computeMajor = nullptr, int* computeMinor = nullptr );
struct RuntimeInfo
{
/// maximum driver supported version
int driverVersion = 0;

/// current runtime version
int runtimeVersion = 0;

/// compute capability major version
int computeMajor = 0;

/// compute capability minor version
int computeMinor = 0;

/// returns true if all versions pass the checks
[[nodiscard]] MRCUDA_API bool fitForComputations() const;
};

/// Returns an error if CUDA is not available
MRCUDA_API Expected<RuntimeInfo> getRuntimeInfo();

// Returns available GPU memory in bytes
/// Returns available GPU memory in bytes
MRCUDA_API size_t getCudaAvailableMemory();

// Returns maximum safe amount of free GPU memory that will be used for dynamic-sized buffers
/// Returns maximum safe amount of free GPU memory that will be used for dynamic-sized buffers
MRCUDA_API size_t getCudaSafeMemoryLimit();

// Returns maximum buffer size in elements that can be allocated with given memory limit
/// Returns maximum buffer size in elements that can be allocated with given memory limit
MRCUDA_API size_t maxBufferSize( size_t availableBytes, size_t elementCount, size_t elementBytes );

// Returns maximum buffer size in elements that can be allocated with given memory limit
// The size is aligned to the block dimensions
/// Returns maximum buffer size in elements that can be allocated with given memory limit
/// The size is aligned to the block dimensions
MRCUDA_API size_t maxBufferSizeAlignedByBlock( size_t availableBytes, const Vector2i& blockDims, size_t elementBytes );
MRCUDA_API size_t maxBufferSizeAlignedByBlock( size_t availableBytes, const Vector3i& blockDims, size_t elementBytes );

Expand Down
17 changes: 11 additions & 6 deletions source/MRTestCuda/MRTestCuda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,20 @@ int main( int argc, char** argv )
{
MR::setupLoggerByDefault();

int driverVersion, runtimeVersion, computeMajor, computeMinor;
if ( !MR::Cuda::isCudaAvailable( &driverVersion, &runtimeVersion, &computeMajor, &computeMinor ) )
auto info = MR::Cuda::getRuntimeInfo();
if ( !info )
{
spdlog::critical( "No CUDA-capable device found" );
spdlog::critical( "CUDA error: {}", info.error() );
return EXIT_FAILURE;
}
spdlog::info( "Driver version: {}.{}", info->driverVersion / 1000, ( info->driverVersion % 1000 ) / 10 );
spdlog::info( "Runtime version: {}.{}", info->runtimeVersion / 1000, ( info->runtimeVersion % 1000 ) / 10 );
spdlog::info( "Compute version: {}.{}", info->computeMajor, info->computeMinor );
if ( !info->fitForComputations() )
{
spdlog::critical( "CUDA does not fit for computations" );
return EXIT_FAILURE;
}
spdlog::info( "Driver version: {}.{}", driverVersion / 1000, ( driverVersion % 1000 ) / 10 );
spdlog::info( "Runtime version: {}.{}", runtimeVersion / 1000, ( runtimeVersion % 1000 ) / 10 );
spdlog::info( "Compute version: {}.{}", computeMajor, computeMinor );

testing::InitGoogleTest( &argc, argv );
return RUN_ALL_TESTS();
Expand Down
Loading