diff --git a/mlx/backend/cuda/conv.cpp b/mlx/backend/cuda/conv.cpp index c5b3c33f..9e471d23 100644 --- a/mlx/backend/cuda/conv.cpp +++ b/mlx/backend/cuda/conv.cpp @@ -39,7 +39,7 @@ struct ConvCacheKey { }; auto& conv_cache() { - static LRUBytesKeyCache< + static thread_local LRUBytesKeyCache< ConvCacheKey, std::pair>> cache("MLX_CUDA_CONV_CACHE_SIZE", /* default_capacity */ 128); @@ -103,7 +103,7 @@ std::optional build_conv_graph( const std::vector& dilation) { auto compute_dtype = (dtype == float16 || dtype == bfloat16) ? float32 : dtype; - DnnGraph graph(encoder.device().get_cudnn_handle(), dtype, compute_dtype); + DnnGraph graph(get_cudnn_handle(encoder.device()), dtype, compute_dtype); auto x_ = graph.tensor_nchw("X", 'x', x); auto w_ = graph.tensor_nchw("W", 'w', w); @@ -139,7 +139,7 @@ std::optional build_conv_graph( if (dtype == float32 && !env::enable_tf32()) { graph.deselect_numeric_notes({fe::NumericalNote_t::TENSOR_CORE}); } - CHECK_CUDNN_FE_ERROR(graph.build()); + CHECK_CUDNN_ERROR(graph.build()); return graph; } @@ -252,6 +252,10 @@ void register_args( } // namespace +void init_cudnn_conv_cache() { + conv_cache(); +} + void Convolution::eval_gpu(const std::vector& inputs, array& out_) { nvtx3::scoped_range r("Convolution::eval_gpu"); if (out_.size() == 0) { @@ -289,7 +293,7 @@ void Convolution::eval_gpu(const std::vector& inputs, array& out_) { std::tie(in, wt, out) = prepare_args(encoder, backend_type, in, wt, out, groups_, s); register_args(encoder, backend_type, in, wt, out, out_); - CHECK_CUDNN_FE_ERROR(graph->encode_capturing( + CHECK_CUDNN_ERROR(graph->encode_capturing( encoder, { {'x', gpu_ptr(in)}, @@ -371,7 +375,7 @@ void Convolution::eval_gpu(const std::vector& inputs, array& out_) { if (graph) { register_args(encoder, backend_type, in, wt, out, out_); - CHECK_CUDNN_FE_ERROR(graph->encode_capturing( + CHECK_CUDNN_ERROR(graph->encode_capturing( encoder, { {'x', gpu_ptr(in)}, diff --git a/mlx/backend/cuda/cublas_utils.cpp b/mlx/backend/cuda/cublas_utils.cpp index b214a37e..8a03eccd 100644 --- a/mlx/backend/cuda/cublas_utils.cpp +++ b/mlx/backend/cuda/cublas_utils.cpp @@ -2,44 +2,13 @@ #include "mlx/backend/cuda/cublas_utils.h" #include "mlx/backend/cuda/cuda.h" +#include "mlx/backend/gpu/device_info.h" #include "mlx/utils.h" namespace mlx::core { + namespace cublas_utils { -namespace { - -struct CublasPreference { - CublasPreference(cu::Device& device) { - // The recommended cublas workspace size is 4 MiB for pre-Hopper and 32 MiB - // for Hopper+: - // https://docs.nvidia.com/cuda/cublas/#cublassetworkspace - uint64_t MiB = 1024 * 1024; - uint64_t workspace_size = - device.compute_capability_major() >= 9 ? 32 * MiB : 4 * MiB; - - CHECK_CUBLAS_ERROR(cublasLtMatmulPreferenceCreate(&pref_)); - CHECK_CUBLAS_ERROR(cublasLtMatmulPreferenceSetAttribute( - pref_, - CUBLASLT_MATMUL_PREF_MAX_WORKSPACE_BYTES, - &workspace_size, - sizeof(uint64_t))); - } - - ~CublasPreference() { - CHECK_CUBLAS_ERROR(cublasLtMatmulPreferenceDestroy(pref_)); - } - - cublasLtMatmulPreference_t pref_{nullptr}; -}; - -} // namespace - -cublasLtMatmulPreference_t get_preference(cu::Device& device) { - static CublasPreference pref(device); - return pref.pref_; -} - cublasLtMatrixLayout_t create_matrix_layout( cudaDataType_t type, uint64_t rows, @@ -70,6 +39,59 @@ cublasLtMatrixLayout_t create_matrix_layout( } // namespace cublas_utils +namespace { + +auto& cublas_handles_cache() { + struct CublasHandles { + ~CublasHandles() { + if (handle) { + CHECK_CUBLAS_ERROR(cublasLtDestroy(handle)); + CHECK_CUBLAS_ERROR(cublasLtMatmulPreferenceDestroy(pref)); + } + } + cublasLtHandle_t handle{nullptr}; + cublasLtMatmulPreference_t pref{nullptr}; + }; + static thread_local std::vector cache(gpu::device_count()); + return cache; +} + +auto get_cublas_handles(cu::Device& device) { + auto& storage = cublas_handles_cache().at(device.cuda_device()); + if (!storage.handle) { + // Create cublasLt handle. + device.make_current(); + CHECK_CUBLAS_ERROR(cublasLtCreate(&storage.handle)); + // The recommended cublas workspace size is 4 MiB for pre-Hopper and 32 + // MiB for Hopper+: + // https://docs.nvidia.com/cuda/cublas/#cublassetworkspace + uint64_t MiB = 1024 * 1024; + uint64_t workspace_size = + device.compute_capability_major() >= 9 ? 32 * MiB : 4 * MiB; + CHECK_CUBLAS_ERROR(cublasLtMatmulPreferenceCreate(&storage.pref)); + CHECK_CUBLAS_ERROR(cublasLtMatmulPreferenceSetAttribute( + storage.pref, + CUBLASLT_MATMUL_PREF_MAX_WORKSPACE_BYTES, + &workspace_size, + sizeof(uint64_t))); + } + return std::make_tuple(storage.handle, storage.pref); +} + +} // namespace + +void check_cublas_error(const char* name, cublasStatus_t err) { + if (err != CUBLAS_STATUS_SUCCESS) { + // TODO: Use cublasGetStatusString when it is widely available. + throw std::runtime_error( + fmt::format("{} failed with code: {}.", name, static_cast(err))); + } +} + +void init_cublas_handles_cache() { + cublas_handles_cache(); +} + CublasMatmulBase::~CublasMatmulBase() { CHECK_CUBLAS_ERROR(cublasLtMatrixLayoutDestroy(a_desc_)); CHECK_CUBLAS_ERROR(cublasLtMatrixLayoutDestroy(b_desc_)); @@ -98,8 +120,7 @@ void CublasMatmulBase::init_base( M_ = a_rows; N_ = b_cols; scale_type_ = scale_type; - handle_ = device.get_cublaslt_handle(); - pref_ = cublas_utils::get_preference(device); + std::tie(handle_, pref_) = get_cublas_handles(device); heuristic_.state = CUBLAS_STATUS_NOT_INITIALIZED; CHECK_CUBLAS_ERROR( diff --git a/mlx/backend/cuda/cublas_utils.h b/mlx/backend/cuda/cublas_utils.h index 56702b12..053fa6b0 100644 --- a/mlx/backend/cuda/cublas_utils.h +++ b/mlx/backend/cuda/cublas_utils.h @@ -1,17 +1,15 @@ // Copyright © 2025 Apple Inc. #pragma once -#include #include "mlx/array.h" #include "mlx/backend/cuda/device.h" #include "mlx/dtype_utils.h" +#include + namespace mlx::core { namespace cublas_utils { -// Get the shared cublas preference for a device -cublasLtMatmulPreference_t get_preference(cu::Device& device); - cublasLtMatrixLayout_t create_matrix_layout( cudaDataType_t type, uint64_t rows, @@ -42,6 +40,12 @@ inline cudaDataType_t dtype_to_cublas_type(Dtype dtype, std::string_view tag) { } // namespace cublas_utils +void check_cublas_error(const char* name, cublasStatus_t err); + +#define CHECK_CUBLAS_ERROR(cmd) check_cublas_error(#cmd, (cmd)) + +void init_cublas_handles_cache(); + class CublasMatmulBase { public: virtual ~CublasMatmulBase(); diff --git a/mlx/backend/cuda/cuda_utils.h b/mlx/backend/cuda/cuda_utils.h index 4c60fec2..7bae911d 100644 --- a/mlx/backend/cuda/cuda_utils.h +++ b/mlx/backend/cuda/cuda_utils.h @@ -2,23 +2,17 @@ #pragma once -#include #include #include -#include namespace mlx::core { // Throw exception if the cuda API does not succeed. -void check_cublas_error(const char* name, cublasStatus_t err); void check_cuda_error(const char* name, cudaError_t err); void check_cuda_error(const char* name, CUresult err); -void check_cudnn_error(const char* name, cudnnStatus_t err); // The macro version that prints the command that failed. -#define CHECK_CUBLAS_ERROR(cmd) check_cublas_error(#cmd, (cmd)) #define CHECK_CUDA_ERROR(cmd) check_cuda_error(#cmd, (cmd)) -#define CHECK_CUDNN_ERROR(cmd) check_cudnn_error(#cmd, (cmd)) // Base class for RAII managed CUDA resources. template diff --git a/mlx/backend/cuda/cudnn_utils.cpp b/mlx/backend/cuda/cudnn_utils.cpp index 1a3f5833..eee33068 100644 --- a/mlx/backend/cuda/cudnn_utils.cpp +++ b/mlx/backend/cuda/cudnn_utils.cpp @@ -2,6 +2,7 @@ #include "mlx/backend/cuda/cudnn_utils.h" #include "mlx/backend/cuda/device.h" +#include "mlx/backend/gpu/device_info.h" namespace mlx::core { @@ -47,8 +48,48 @@ inline auto nhwc_to_nchw(const array& x) { return std::make_tuple(std::move(shape), std::move(strides)); } +auto& cudnn_handles_cache() { + struct CudnnHandle { + ~CudnnHandle() { + if (handle) { + CHECK_CUDNN_ERROR(cudnnDestroy(handle)); + } + } + cudnnHandle_t handle{nullptr}; + }; + static thread_local std::vector cache(gpu::device_count()); + return cache; +} + } // namespace +void check_cudnn_error(const char* name, cudnnStatus_t err) { + if (err != CUDNN_STATUS_SUCCESS) { + throw std::runtime_error( + fmt::format("{} failed: {}.", name, cudnnGetErrorString(err))); + } +} + +void check_cudnn_error(const char* name, fe::error_t err) { + if (!err.is_good()) { + throw std::runtime_error( + fmt::format("{} failed: {}.", name, err.get_message())); + } +} + +cudnnHandle_t get_cudnn_handle(cu::Device& device) { + auto& storage = cudnn_handles_cache().at(device.cuda_device()); + if (!storage.handle) { + device.make_current(); + CHECK_CUDNN_ERROR(cudnnCreate(&storage.handle)); + } + return storage.handle; +} + +void init_cudnn_handles_cache() { + cudnn_handles_cache(); +} + fe::error_t DnnGraph::prepare() { RETURN_IF_ERROR(validate()); try { @@ -109,7 +150,7 @@ fe::error_t DnnGraph::encode_capturing( void* DnnGraph::prepare_workspace(cu::CommandEncoder& encoder) { int64_t workspace_size = 0; - CHECK_CUDNN_FE_ERROR(get_workspace_size(workspace_size)); + CHECK_CUDNN_ERROR(get_workspace_size(workspace_size)); return allocate_workspace(encoder, workspace_size); } diff --git a/mlx/backend/cuda/cudnn_utils.h b/mlx/backend/cuda/cudnn_utils.h index aefeffbc..40820e59 100644 --- a/mlx/backend/cuda/cudnn_utils.h +++ b/mlx/backend/cuda/cudnn_utils.h @@ -21,14 +21,16 @@ class CommandEncoder; namespace fe = cudnn_frontend; -#define CHECK_CUDNN_FE_ERROR(cmd) \ - do { \ - auto error = cmd; \ - if (!error.is_good()) { \ - throw std::runtime_error( \ - fmt::format("{} failed: {}.", #cmd, error.get_message())); \ - } \ - } while (0) +void check_cudnn_error(const char* name, cudnnStatus_t err); +void check_cudnn_error(const char* name, fe::error_t err); + +#define CHECK_CUDNN_ERROR(cmd) check_cudnn_error(#cmd, (cmd)) + +cudnnHandle_t get_cudnn_handle(cu::Device& device); + +void init_cudnn_handles_cache(); +void init_cudnn_conv_cache(); +void init_cudnn_sdpa_cache(); // Return pointer alignment of |x|'s data. inline uint8_t get_alignment(const array& x) { diff --git a/mlx/backend/cuda/device.cpp b/mlx/backend/cuda/device.cpp index 73be4cad..5122567b 100644 --- a/mlx/backend/cuda/device.cpp +++ b/mlx/backend/cuda/device.cpp @@ -1,7 +1,6 @@ // Copyright © 2025 Apple Inc. #include "mlx/backend/cuda/device.h" -#include "mlx/backend/cuda/jit_module.h" #include "mlx/backend/cuda/worker.h" #include "mlx/backend/gpu/device_info.h" #include "mlx/utils.h" @@ -55,14 +54,7 @@ Device::Device(int device) : device_(device) { &memory_pools_, cudaDevAttrMemoryPoolsSupported, device_)); } -Device::~Device() { - if (cudnn_handle_) { - CHECK_CUDNN_ERROR(cudnnDestroy(cudnn_handle_)); - } - if (cublaslt_handle_) { - CHECK_CUBLAS_ERROR(cublasLtDestroy(cublaslt_handle_)); - } -} +Device::~Device() = default; void Device::make_current() { // We need to set/get current CUDA device very frequently, cache it to reduce @@ -76,30 +68,6 @@ void Device::make_current() { } } -CommandEncoder& Device::get_command_encoder(Stream s) { - auto it = encoders_.find(s.index); - if (it == encoders_.end()) { - it = encoders_.try_emplace(s.index, *this).first; - } - return it->second; -} - -cublasLtHandle_t Device::get_cublaslt_handle() { - if (!cublaslt_handle_) { - make_current(); - CHECK_CUBLAS_ERROR(cublasLtCreate(&cublaslt_handle_)); - } - return cublaslt_handle_; -} - -cudnnHandle_t Device::get_cudnn_handle() { - if (!cudnn_handle_) { - make_current(); - CHECK_CUDNN_ERROR(cudnnCreate(&cudnn_handle_)); - } - return cudnn_handle_; -} - CommandEncoder::CaptureContext::CaptureContext(CommandEncoder& enc) : enc(enc) { enc.device().make_current(); if (!use_cuda_graphs()) { @@ -243,6 +211,10 @@ CommandEncoder::CommandEncoder(Device& d) std::tie(max_ops_per_graph_, max_mb_per_graph_) = get_graph_limits(d); } +CommandEncoder::~CommandEncoder() { + synchronize(); +} + void CommandEncoder::add_completed_handler(std::function task) { worker_.add_task(std::move(task)); } @@ -571,18 +543,17 @@ void CommandEncoder::synchronize() { } Device& device(int cuda_device) { - static auto devices = []() { - std::vector devices; + // The devices are leak intentionally as user code may still be accessing + // device after main thread teardown. + static auto* devices = []() { + auto* devices = new std::vector; int device_count = gpu::device_count(); for (int i = 0; i < device_count; ++i) { - devices.emplace_back(i); + devices->emplace_back(i); } - // Initialize the jit module cache here ensures it is not unloaded before - // any evaluation is done. - get_jit_module_cache(); return devices; }(); - return devices.at(cuda_device); + return devices->at(cuda_device); } Device& device(mlx::core::Device d) { @@ -590,7 +561,18 @@ Device& device(mlx::core::Device d) { } CommandEncoder& get_command_encoder(Stream s) { - return device(s.device).get_command_encoder(s); + auto& encoders = get_command_encoders(); + auto it = encoders.find(s.index); + if (it == encoders.end()) { + throw std::runtime_error( + fmt::format("There is no Stream(gpu, {}) in current thread.", s.index)); + } + return it->second; +} + +std::unordered_map& get_command_encoders() { + static thread_local std::unordered_map encoders; + return encoders; } } // namespace mlx::core::cu diff --git a/mlx/backend/cuda/device.h b/mlx/backend/cuda/device.h index d79f3e0e..bb60fc89 100644 --- a/mlx/backend/cuda/device.h +++ b/mlx/backend/cuda/device.h @@ -8,10 +8,6 @@ #include "mlx/backend/cuda/worker.h" #include "mlx/stream.h" -#include -#include -#include - #include namespace mlx::core::cu { @@ -35,6 +31,7 @@ class CommandEncoder { }; explicit CommandEncoder(Device& d); + ~CommandEncoder(); CommandEncoder(const CommandEncoder&) = delete; CommandEncoder& operator=(const CommandEncoder&) = delete; @@ -170,10 +167,6 @@ class Device { // Make this device the current cuda device, this method is thread-safe. void make_current(); - CommandEncoder& get_command_encoder(Stream s); - cublasLtHandle_t get_cublaslt_handle(); - cudnnHandle_t get_cudnn_handle(); - int cuda_device() const { return device_; } @@ -205,13 +198,12 @@ class Device { int managed_memory_; int memory_pools_; std::string device_name_; - cublasLtHandle_t cublaslt_handle_{nullptr}; - cudnnHandle_t cudnn_handle_{nullptr}; - std::unordered_map encoders_; }; -Device& device(int cuda_device); -Device& device(mlx::core::Device d); -CommandEncoder& get_command_encoder(Stream s); +MLX_API Device& device(int cuda_device); +MLX_API Device& device(mlx::core::Device d); +MLX_API CommandEncoder& get_command_encoder(Stream s); + +std::unordered_map& get_command_encoders(); } // namespace mlx::core::cu diff --git a/mlx/backend/cuda/eval.cpp b/mlx/backend/cuda/eval.cpp index 8b8bf598..87ce213c 100644 --- a/mlx/backend/cuda/eval.cpp +++ b/mlx/backend/cuda/eval.cpp @@ -2,6 +2,8 @@ #include "mlx/backend/gpu/eval.h" #include "mlx/backend/cuda/allocator.h" +#include "mlx/backend/cuda/cublas_utils.h" +#include "mlx/backend/cuda/cudnn_utils.h" #include "mlx/backend/cuda/device.h" #include "mlx/primitives.h" #include "mlx/scheduler.h" @@ -18,7 +20,16 @@ void init() { } void new_stream(Stream s) { - cu::get_command_encoder(s); + // Make sure the handles get destroyed after CommandEncoder. + init_cublas_handles_cache(); + init_cudnn_handles_cache(); + init_cudnn_conv_cache(); + init_cudnn_sdpa_cache(); + // Create CommandEncoder. + assert(s.device == Device::gpu); + auto& encoders = cu::get_command_encoders(); + auto& d = cu::device(s.device); + encoders.try_emplace(s.index, d); } void eval(array& arr) { diff --git a/mlx/backend/cuda/jit_module.cpp b/mlx/backend/cuda/jit_module.cpp index d4f1b491..43371254 100644 --- a/mlx/backend/cuda/jit_module.cpp +++ b/mlx/backend/cuda/jit_module.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -439,20 +440,28 @@ CUfunction JitModule::get_kernel( return get_kernel_and_dims(kernel_name, std::move(configure_kernel)).first; } -std::unordered_map& get_jit_module_cache() { - static std::unordered_map map; - return map; -} - JitModule& get_jit_module( const mlx::core::Device& device, const std::string& name, const KernelBuilder& builder, - bool cache) { - auto& map = get_jit_module_cache(); - auto it = map.find(name); - if (it == map.end()) { - it = map.try_emplace(name, cu::device(device), name, builder, cache).first; + bool use_disk_cache) { + // The cache are leak intentionally as user code may still be running JIT + // compiled code after main thread teardown. + static auto* cache = new std::unordered_map; + static auto* mtx = new std::shared_mutex; + + { + std::shared_lock rlock(*mtx); + if (auto it = cache->find(name); it != cache->end()) { + return it->second; + } + } + + std::unique_lock wlock(*mtx); + auto it = cache->find(name); + if (it == cache->end()) { + auto& d = cu::device(device); + it = cache->try_emplace(name, d, name, builder, use_disk_cache).first; } return it->second; } diff --git a/mlx/backend/cuda/jit_module.h b/mlx/backend/cuda/jit_module.h index 3849d8d0..4a779cc3 100644 --- a/mlx/backend/cuda/jit_module.h +++ b/mlx/backend/cuda/jit_module.h @@ -91,11 +91,12 @@ class JitModule { Device& device, const std::string& module_name, const KernelBuilder& builder, - bool cache); + bool use_disk_cache); ~JitModule(); JitModule(const JitModule&) = delete; JitModule& operator=(const JitModule&) = delete; + CUfunction get_kernel( const std::string& kernel_name, std::function configure_kernel = nullptr); @@ -109,8 +110,6 @@ class JitModule { kernels_; }; -std::unordered_map& get_jit_module_cache(); - JitModule& get_jit_module( const mlx::core::Device& device, const std::string& name, diff --git a/mlx/backend/cuda/scaled_dot_product_attention.cpp b/mlx/backend/cuda/scaled_dot_product_attention.cpp index 93f310f5..ca411e91 100644 --- a/mlx/backend/cuda/scaled_dot_product_attention.cpp +++ b/mlx/backend/cuda/scaled_dot_product_attention.cpp @@ -176,13 +176,13 @@ inline BytesKey build_sdpa_cache_key( } auto& sdpa_cache() { - static LRUBytesKeyCache cache( + static thread_local LRUBytesKeyCache cache( "MLX_CUDA_SDPA_CACHE_SIZE", /* default_capacity */ 256); return cache; } auto& sdpa_backward_cache() { - static LRUBytesKeyCache cache( + static thread_local LRUBytesKeyCache cache( "MLX_CUDA_SDPA_BACKWARD_CACHE_SIZE", /* default_capacity */ 64); return cache; } @@ -249,10 +249,10 @@ DnnGraph build_sdpa_graph( graph.tensor(stats_, STATS, *stats)->set_output(true); } - CHECK_CUDNN_FE_ERROR(graph.prepare()); + CHECK_CUDNN_ERROR(graph.prepare()); graph.select_behavior_notes( {fe::BehaviorNote_t::SUPPORTS_CUDA_GRAPH_NATIVE_API}); - CHECK_CUDNN_FE_ERROR(graph.build()); + CHECK_CUDNN_ERROR(graph.build()); return graph; } @@ -298,15 +298,20 @@ DnnGraph build_sdpa_backward_graph( graph.tensor(d_k_, D_K, d_k)->set_output(true); graph.tensor(d_v_, D_V, d_v)->set_output(true); - CHECK_CUDNN_FE_ERROR(graph.prepare()); + CHECK_CUDNN_ERROR(graph.prepare()); graph.select_behavior_notes( {fe::BehaviorNote_t::SUPPORTS_CUDA_GRAPH_NATIVE_API}); - CHECK_CUDNN_FE_ERROR(graph.build()); + CHECK_CUDNN_ERROR(graph.build()); return graph; } } // namespace +void init_cudnn_sdpa_cache() { + sdpa_cache(); + sdpa_backward_cache(); +} + bool supports_sdpa_cudnn( const array& q, const array& k, @@ -357,7 +362,7 @@ void sdpa_cudnn( bool output_logsumexp, Stream s) { auto& encoder = cu::get_command_encoder(s); - auto handle = encoder.device().get_cudnn_handle(); + auto handle = get_cudnn_handle(encoder.device()); malloc_with_same_layout(encoder, o, q); @@ -440,7 +445,7 @@ void sdpa_cudnn( variant_pack[STATS] = gpu_ptr(*stats); } - CHECK_CUDNN_FE_ERROR(graph.encode_graph(encoder, std::move(variant_pack))); + CHECK_CUDNN_ERROR(graph.encode_graph(encoder, std::move(variant_pack))); } void sdpa_backward_cudnn( @@ -459,7 +464,7 @@ void sdpa_backward_cudnn( array& d_v, Stream s) { auto& encoder = cu::get_command_encoder(s); - auto handle = encoder.device().get_cudnn_handle(); + auto handle = get_cudnn_handle(encoder.device()); malloc_with_same_layout(encoder, d_q, q); malloc_with_same_layout(encoder, d_k, k); @@ -522,7 +527,7 @@ void sdpa_backward_cudnn( variant_pack[SINKS] = gpu_ptr(*sinks); } - CHECK_CUDNN_FE_ERROR(graph.encode_graph(encoder, std::move(variant_pack))); + CHECK_CUDNN_ERROR(graph.encode_graph(encoder, std::move(variant_pack))); } // Defined in scaled_dot_product_attention.cu file. diff --git a/mlx/backend/cuda/utils.cpp b/mlx/backend/cuda/utils.cpp index 08f0f3d4..82272b74 100644 --- a/mlx/backend/cuda/utils.cpp +++ b/mlx/backend/cuda/utils.cpp @@ -10,14 +10,6 @@ namespace mlx::core { -void check_cublas_error(const char* name, cublasStatus_t err) { - if (err != CUBLAS_STATUS_SUCCESS) { - // TODO: Use cublasGetStatusString when it is widely available. - throw std::runtime_error( - fmt::format("{} failed with code: {}.", name, static_cast(err))); - } -} - void check_cuda_error(const char* name, cudaError_t err) { if (err != cudaSuccess) { throw std::runtime_error( @@ -33,13 +25,6 @@ void check_cuda_error(const char* name, CUresult err) { } } -void check_cudnn_error(const char* name, cudnnStatus_t err) { - if (err != CUDNN_STATUS_SUCCESS) { - throw std::runtime_error( - fmt::format("{} failed: {}.", name, cudnnGetErrorString(err))); - } -} - const char* dtype_to_cuda_type(const Dtype& dtype) { switch (dtype) { case bool_: diff --git a/tests/scheduler_tests.cpp b/tests/scheduler_tests.cpp index 3a8400f5..94f2758e 100644 --- a/tests/scheduler_tests.cpp +++ b/tests/scheduler_tests.cpp @@ -66,7 +66,7 @@ TEST_CASE("test default stream in threads") { } TEST_CASE("test access stream in other thread") { - if (!metal::is_available()) { + if (!gpu::is_available()) { return; }