1010#include < raft/core/resource/cublaslt_handle.hpp>
1111#include < raft/core/resource/cuda_stream.hpp>
1212#include < raft/core/resource/custom_resource.hpp>
13- #include < raft/core/resource/device_properties.hpp>
1413#include < raft/core/resources.hpp>
1514#include < raft/util/cache.hpp>
1615#include < raft/util/cuda_data_type.hpp>
1918
2019#include < cublasLt.h>
2120
22- #include < array>
2321#include < type_traits>
2422
2523namespace raft {
@@ -102,21 +100,27 @@ struct matmul_key_hash {
102100};
103101
104102/* *
105- * cuBLASLt 13.6 and later may select algorithm 68 once A's physical span reaches 2^31 elements.
106- * That algorithm fails during execution for FP32, so select the next ranked heuristic instead .
103+ * cuBLASLt 13.6.0, shipped with CUDA 13.3, may select algorithm 68 once A's physical span reaches
104+ * 2^31 elements. That algorithm fails during execution for FP32.
107105 */
108- inline auto needs_cublaslt_13_6_workaround (const matmul_key_t & args,
109- std::size_t version,
110- int device_major,
111- int device_minor) noexcept -> bool
106+ inline auto needs_cublaslt_13_6_workaround (const matmul_key_t & args, std::size_t version) noexcept
107+ -> bool
112108{
113109 constexpr uint64_t max_safe_span = (uint64_t {1 } << 31 ) - 1 ;
114110 const auto a_columns = args.trans_a ? args.m : args.k ;
115- const bool is_affected_architecture =
116- (device_major == 10 && device_minor == 0 ) ||
117- (device_major == 12 && (device_minor == 0 || device_minor == 1 ));
118- return version >= 130600 && is_affected_architecture && args.lda != 0 &&
119- a_columns > max_safe_span / args.lda ;
111+ return version == 130600 && args.lda != 0 && a_columns > max_safe_span / args.lda ;
112+ }
113+
114+ /* *
115+ * Querying with a physical A leading dimension that is not 16-byte aligned suppresses algorithm 68.
116+ * The returned algorithm is then used with the real descriptors.
117+ */
118+ inline auto get_cublaslt_13_6_heuristic_args (const matmul_key_t & args) noexcept -> matmul_key_t
119+ {
120+ constexpr uint64_t fp32_elements_per_16_bytes = 4 ;
121+ auto heuristic_args = args;
122+ if (heuristic_args.lda % fp32_elements_per_16_bytes == 0 ) { ++heuristic_args.lda ; }
123+ return heuristic_args;
120124}
121125
122126inline auto get_cublaslt_algorithm_id (const cublasLtMatmulHeuristicResult_t& heuristic) -> int
@@ -199,6 +203,24 @@ struct cublastlt_matmul_desc {
199203 }
200204};
201205
206+ /* * Preference descriptor for a cublasLt matmul heuristic query. */
207+ struct cublastlt_matmul_preference {
208+ cublasLtMatmulPreference_t res{nullptr };
209+
210+ inline cublastlt_matmul_preference () { RAFT_CUBLAS_TRY (cublasLtMatmulPreferenceCreate (&res)); }
211+ inline cublastlt_matmul_preference (const cublastlt_matmul_preference&) = delete;
212+ inline auto operator =(const cublastlt_matmul_preference&)
213+ -> cublastlt_matmul_preference& = delete ;
214+
215+ inline ~cublastlt_matmul_preference () noexcept
216+ {
217+ RAFT_CUBLAS_TRY_NO_THROW (cublasLtMatmulPreferenceDestroy (res));
218+ }
219+
220+ // NOLINTNEXTLINE
221+ inline operator cublasLtMatmulPreference_t () const noexcept { return res; }
222+ };
223+
202224/* * Full description of matmul. */
203225struct matmul_desc {
204226 cublastlt_matmul_desc desc;
@@ -219,46 +241,40 @@ struct matmul_desc {
219241 bool use_cublaslt_13_6_workaround = false ;
220242 if constexpr (std::is_same_v<S, float > && std::is_same_v<A, float > &&
221243 std::is_same_v<B, float > && std::is_same_v<C, float >) {
222- const auto & device_properties = resource::get_device_properties (res);
223- use_cublaslt_13_6_workaround = needs_cublaslt_13_6_workaround (
224- args, cublasLtGetVersion (), device_properties.major , device_properties.minor );
244+ use_cublaslt_13_6_workaround = needs_cublaslt_13_6_workaround (args, cublasLtGetVersion ());
225245 }
226246
227- constexpr int workaround_heuristic_results = 2 ;
228- std::array<cublasLtMatmulHeuristicResult_t, workaround_heuristic_results> heuristic_results{};
229- const int requested_results = use_cublaslt_13_6_workaround ? workaround_heuristic_results : 1 ;
230247 int algo_count;
231- cublasLtMatmulPreference_t preference;
232- RAFT_CUBLAS_TRY (cublasLtMatmulPreferenceCreate (&preference));
233- RAFT_CUBLAS_TRY (cublasLtMatmulAlgoGetHeuristic (resource::get_cublaslt_handle (res),
234- r.desc ,
235- r.a ,
236- r.b ,
237- r.c ,
238- r.c ,
239- preference,
240- requested_results,
241- heuristic_results.data (),
242- &algo_count));
243- RAFT_CUBLAS_TRY (cublasLtMatmulPreferenceDestroy (preference));
244-
245- RAFT_EXPECTS (algo_count > 0 , " cuBLASLt did not return a matmul algorithm" );
246- if (!use_cublaslt_13_6_workaround) {
247- r.heuristics = heuristic_results.front ();
248- return r;
248+ cublastlt_matmul_preference preference;
249+ const auto query_heuristic = [&](cublasLtMatrixLayout_t a_layout,
250+ cublasLtMatrixLayout_t c_layout) {
251+ RAFT_CUBLAS_TRY (cublasLtMatmulAlgoGetHeuristic (resource::get_cublaslt_handle (res),
252+ r.desc ,
253+ a_layout,
254+ r.b ,
255+ c_layout,
256+ c_layout,
257+ preference,
258+ 1 ,
259+ &r.heuristics ,
260+ &algo_count));
261+ };
262+
263+ if (use_cublaslt_13_6_workaround) {
264+ const auto heuristic_args = get_cublaslt_13_6_heuristic_args (args);
265+ const auto heuristic_a = cublastlt_matrix_layout::for_matmul<A>(
266+ !(heuristic_args.trans_a ), heuristic_args.m , heuristic_args.k , heuristic_args.lda );
267+ query_heuristic (heuristic_a, r.c );
268+ } else {
269+ query_heuristic (r.a , r.c );
249270 }
250271
272+ RAFT_EXPECTS (algo_count > 0 , " cuBLASLt did not return a matmul algorithm" );
251273 constexpr int faulty_algorithm = 68 ;
252- for (int i = 0 ; i < algo_count; ++i) {
253- const auto & candidate = heuristic_results[i];
254- if (candidate.state == CUBLAS_STATUS_SUCCESS && candidate.workspaceSize == 0 &&
255- get_cublaslt_algorithm_id (candidate) != faulty_algorithm) {
256- r.heuristics = candidate;
257- return r;
258- }
274+ if (use_cublaslt_13_6_workaround) {
275+ RAFT_EXPECTS (get_cublaslt_algorithm_id (r.heuristics ) != faulty_algorithm,
276+ " cuBLASLt 13.6.0 returned faulty algorithm 68 for the workaround query" );
259277 }
260-
261- RAFT_FAIL (" cuBLASLt 13.6 did not return a safe algorithm for the affected large FP32 GEMM" );
262278 return r;
263279 }
264280};
0 commit comments