#pragma once #include #include "../../jit/compiler.hpp" #include "../../jit/device_runtime.hpp" #include "../../jit/kernel_runtime.hpp" #include "../../utils/exception.hpp" #include "../../utils/format.hpp" #include "../../utils/math.hpp" #include "../heuristics/sm100.hpp" #include "epilogue.hpp" #include "runtime_utils.hpp" namespace deep_gemm { class SM100FP8FP4Gemm1D1DRuntime final: public LaunchRuntime { public: struct Args { GemmDesc gemm_desc; GemmConfig gemm_config; LaunchArgs launch_args; // TODO: move into descriptor const std::optional epilogue_type; // TODO: move into descriptor int gran_k_a, gran_k_b; void* grouped_layout; CUtensorMap tensor_map_a; CUtensorMap tensor_map_b; CUtensorMap tensor_map_sfa; CUtensorMap tensor_map_sfb; CUtensorMap tensor_map_cd; }; static std::string generate_impl(const Args& args) { // TODO: rename files return fmt::format(R"( #include using namespace deep_gemm; static void __instantiate_kernel() {{ auto ptr = reinterpret_cast(&sm100_fp8_fp4_gemm_1d1d_impl< {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {} >); }}; )", to_string(args.gemm_desc.major_a), to_string(args.gemm_desc.major_b), args.gran_k_a, args.gran_k_b, get_compiled_dim(args.gemm_desc.m, 'm', args.gemm_desc.compiled_dims), get_compiled_dim(args.gemm_desc.n, 'n', args.gemm_desc.compiled_dims), get_compiled_dim(args.gemm_desc.k, 'k', args.gemm_desc.compiled_dims), args.gemm_config.layout.block_m, args.gemm_config.layout.block_n, args.gemm_config.layout.block_k, args.gemm_desc.num_groups, args.gemm_config.storage_config.swizzle_a_mode, args.gemm_config.storage_config.swizzle_b_mode, args.gemm_config.storage_config.swizzle_cd_mode, args.gemm_config.pipeline_config.num_stages, args.gemm_config.launch_config.num_non_epilogue_threads, args.gemm_config.launch_config.num_epilogue_threads, args.gemm_config.layout.get_cluster_size(), args.gemm_config.layout.cluster_n > 1, args.gemm_config.launch_config.num_sms, args.gemm_config.layout.swap_ab, to_string(args.gemm_desc.gemm_type), args.gemm_desc.with_accumulation, to_string(args.gemm_desc.a_dtype), to_string(args.gemm_desc.b_dtype), to_string(args.gemm_desc.cd_dtype), get_default_epilogue_type(args.epilogue_type)); } static void launch_impl(const KernelHandle& kernel, const LaunchConfigHandle& config, Args args) { // TODO: optimize `args` copy DG_CUDA_UNIFIED_CHECK(launch_kernel(kernel, config, args.grouped_layout, args.gemm_desc.m, args.gemm_desc.n, args.gemm_desc.k, args.tensor_map_a, args.tensor_map_b, args.tensor_map_sfa, args.tensor_map_sfb, args.tensor_map_cd)); } }; static void sm100_fp8_fp4_gemm_1d1d(const torch::Tensor& a, const torch::Tensor& sfa, const torch::Tensor& b, const torch::Tensor& sfb, const std::optional& c, const torch::Tensor& d, const int& m, const int& n, const int& k, const int& gran_k_a, const int& gran_k_b, const cute::UMMA::Major& major_a, const cute::UMMA::Major& major_b, const std::string& compiled_dims, const std::optional& epilogue_type = std::nullopt) { const auto desc = GemmDesc { .gemm_type = GemmType::Normal, .kernel_type = KernelType::Kernel1D1D, .m = m, .n = n, .k = k, .num_groups = 1, .a_dtype = a.scalar_type(), .b_dtype = b.scalar_type(), .cd_dtype = d.scalar_type(), .major_a = major_a, .major_b = major_b, .with_accumulation = c.has_value(), .num_sms = device_runtime->get_num_sms(), .tc_util = device_runtime->get_tc_util(), .compiled_dims = compiled_dims }; const auto config = get_best_config(desc); const auto cd = c.value_or(d); const auto tensor_map_a = make_tma_a_desc(major_a, a, m, k, config.storage_config.load_block_m, config.layout.block_k, static_cast(a.stride(get_non_contiguous_dim(major_a))), 1, config.storage_config.swizzle_a_mode); const auto tensor_map_b = make_tma_b_desc(major_b, b, n, k, config.storage_config.load_block_n, config.layout.block_k, static_cast(b.stride(get_non_contiguous_dim(major_b))), 1, config.storage_config.swizzle_b_mode); const auto tensor_map_cd = make_tma_cd_desc(d, m, static_cast(d.size(-1)), config.storage_config.store_block_m, config.storage_config.store_block_n, static_cast(d.stride(-2)), 1, config.storage_config.swizzle_cd_mode); const auto tensor_map_sfa = make_tma_sf_desc(cute::UMMA::Major::MN, sfa, m, k, config.layout.block_m, gran_k_a, 1, 0); const auto tensor_map_sfb = make_tma_sf_desc(cute::UMMA::Major::MN, sfb, n, k, config.layout.block_n, gran_k_b, 1, 0); // Launch const SM100FP8FP4Gemm1D1DRuntime::Args args = { .gemm_desc = desc, .gemm_config = config, .launch_args = LaunchArgs(config.launch_config.num_sms, config.launch_config.num_threads, config.pipeline_config.smem_size, config.layout.get_cluster_size()), .epilogue_type = epilogue_type, .gran_k_a = gran_k_a, .gran_k_b = gran_k_b, .grouped_layout = nullptr, .tensor_map_a = tensor_map_a, .tensor_map_b = tensor_map_b, .tensor_map_sfa = tensor_map_sfa, .tensor_map_sfb = tensor_map_sfb, .tensor_map_cd = tensor_map_cd }; const auto code = SM100FP8FP4Gemm1D1DRuntime::generate(args); const auto runtime = compiler->build("sm100_fp8_fp4_gemm_1d1d", code); SM100FP8FP4Gemm1D1DRuntime::launch(runtime, args); } static void sm100_m_grouped_fp8_fp4_gemm_contiguous_1d1d(const torch::Tensor& a, const torch::Tensor& sfa, const torch::Tensor& b, const torch::Tensor& sfb, const torch::Tensor& d, const torch::Tensor& grouped_layout, const int& num_groups, const int& m, const int& n, const int& k, const int& gran_k_a, const int& gran_k_b, const cute::UMMA::Major& major_a, const cute::UMMA::Major& major_b, const std::string& compiled_dims, const bool& use_psum_layout, const std::optional& expected_m_for_psum_layout) { const auto gemm_type = use_psum_layout ? GemmType::MGroupedContiguousWithPsumLayout : GemmType::MGroupedContiguous; // Only psum layout can use expected m if (expected_m_for_psum_layout) DG_HOST_ASSERT(use_psum_layout); // NOTES: If actual M is dynamic, estimate config via `num_groups` and `expected_m`. // Otherwise, treat the contiguous layout as a whole. const auto desc = GemmDesc { .gemm_type = gemm_type, .kernel_type = KernelType::Kernel1D1D, .m = m, .n = n, .k = k, .num_groups = num_groups, .a_dtype = a.scalar_type(), .b_dtype = b.scalar_type(), .cd_dtype = d.scalar_type(), .major_a = major_a, .major_b = major_b, .with_accumulation = false, .num_sms = device_runtime->get_num_sms(), .tc_util = device_runtime->get_tc_util(), .compiled_dims = compiled_dims, .expected_m = expected_m_for_psum_layout.value_or(m), .expected_n = n, .expected_k = k, .expected_num_groups = expected_m_for_psum_layout.has_value() ? num_groups : 1 }; const auto config = get_best_config(desc); // Create tensor descriptors const auto tensor_map_a = make_tma_a_desc(major_a, a, m, k, config.storage_config.load_block_m, config.layout.block_k, static_cast(a.stride(get_non_contiguous_dim(major_a))), 1, config.storage_config.swizzle_a_mode); const auto tensor_map_b = make_tma_b_desc(major_b, b, n, k, config.storage_config.load_block_n, config.layout.block_k, static_cast(b.stride(get_non_contiguous_dim(major_b))), num_groups, config.storage_config.swizzle_b_mode); const auto tensor_map_cd = make_tma_cd_desc(d, m, n, config.storage_config.store_block_m, config.storage_config.store_block_n, static_cast(d.stride(-2)), 1, config.storage_config.swizzle_cd_mode); const auto tensor_map_sfa = make_tma_sf_desc(cute::UMMA::Major::MN, sfa, m, k, config.layout.block_m, gran_k_a, 1, 0); const auto tensor_map_sfb = make_tma_sf_desc(cute::UMMA::Major::MN, sfb, n, k, config.layout.block_n, gran_k_b, num_groups, 0); // Launch kernel const SM100FP8FP4Gemm1D1DRuntime::Args args = { .gemm_desc = desc, .gemm_config = config, .launch_args = LaunchArgs(config.launch_config.num_sms, config.launch_config.num_threads, config.pipeline_config.smem_size, config.layout.get_cluster_size()), .epilogue_type = std::nullopt, .gran_k_a = gran_k_a, .gran_k_b = gran_k_b, .grouped_layout = grouped_layout.data_ptr(), .tensor_map_a = tensor_map_a, .tensor_map_b = tensor_map_b, .tensor_map_sfa = tensor_map_sfa, .tensor_map_sfb = tensor_map_sfb, .tensor_map_cd = tensor_map_cd }; const auto code = SM100FP8FP4Gemm1D1DRuntime::generate(args); const auto runtime = compiler->build("sm100_m_grouped_fp8_fp4_gemm_contiguous_1d1d", code); SM100FP8FP4Gemm1D1DRuntime::launch(runtime, args); } static void sm100_m_grouped_fp8_fp4_gemm_masked_1d1d(const torch::Tensor& a, const torch::Tensor& sfa, const torch::Tensor& b, const torch::Tensor& sfb, const torch::Tensor& d, const torch::Tensor& masked_m, const int& num_groups, const int& m, const int& n, const int& k, const int& expected_m, const int& gran_k_a, const int& gran_k_b, const cute::UMMA::Major& major_a, const cute::UMMA::Major& major_b, const std::string& compiled_dims) { const auto desc = GemmDesc { .gemm_type = GemmType::MGroupedMasked, .kernel_type = KernelType::Kernel1D1D, .m = m, .n = n, .k = k, .num_groups = num_groups, .a_dtype = a.scalar_type(), .b_dtype = b.scalar_type(), .cd_dtype = d.scalar_type(), .major_a = major_a, .major_b = major_b, .with_accumulation = false, .num_sms = device_runtime->get_num_sms(), .tc_util = device_runtime->get_tc_util(), .compiled_dims = compiled_dims, .expected_m = expected_m, .expected_n = n, .expected_k = k, .expected_num_groups = num_groups }; const auto config = get_best_config(desc); // Create tensor descriptors const auto tensor_map_a = make_tma_a_desc(major_a, a, m, k, config.storage_config.load_block_m, config.layout.block_k, static_cast(a.stride(get_non_contiguous_dim(major_a))), num_groups, config.storage_config.swizzle_a_mode); const auto tensor_map_b = make_tma_b_desc(major_b, b, n, k, config.storage_config.load_block_n, config.layout.block_k, static_cast(b.stride(get_non_contiguous_dim(major_b))), num_groups, config.storage_config.swizzle_b_mode); const auto tensor_map_cd = make_tma_cd_desc(d, m, n, config.storage_config.store_block_m, config.storage_config.store_block_n, static_cast(d.stride(-2)), num_groups, config.storage_config.swizzle_cd_mode); const auto tensor_map_sfa = make_tma_sf_desc(cute::UMMA::Major::MN, sfa, m, k, config.layout.block_m, gran_k_a, num_groups, 0); const auto tensor_map_sfb = make_tma_sf_desc(cute::UMMA::Major::MN, sfb, n, k, config.layout.block_n, gran_k_b, num_groups, 0); // Launch kernel const SM100FP8FP4Gemm1D1DRuntime::Args args = { .gemm_desc = desc, .gemm_config = config, .launch_args = LaunchArgs(config.launch_config.num_sms, config.launch_config.num_threads, config.pipeline_config.smem_size, config.layout.get_cluster_size()), .epilogue_type = std::nullopt, .gran_k_a = gran_k_a, .gran_k_b = gran_k_b, .grouped_layout = masked_m.data_ptr(), .tensor_map_a = tensor_map_a, .tensor_map_b = tensor_map_b, .tensor_map_sfa = tensor_map_sfa, .tensor_map_sfb = tensor_map_sfb, .tensor_map_cd = tensor_map_cd }; const auto code = SM100FP8FP4Gemm1D1DRuntime::generate(args); const auto runtime = compiler->build("sm100_m_grouped_fp8_fp4_gemm_masked_1d1d", code); SM100FP8FP4Gemm1D1DRuntime::launch(runtime, args); } static void sm100_k_grouped_fp8_gemm_1d1d(const torch::Tensor& a, const torch::Tensor& sfa, const torch::Tensor& b, const torch::Tensor& sfb, const std::optional& c, const torch::Tensor& d, const int& m, const int& n, const std::vector& ks, const torch::Tensor& ks_tensor, const int& gran_k, const cute::UMMA::Major& major_a, const cute::UMMA::Major& major_b, const std::string& compiled_dims) { DG_HOST_ASSERT(major_a == cute::UMMA::Major::MN and major_b == cute::UMMA::Major::MN); DG_HOST_ASSERT(gran_k == 32 or gran_k == 128); const int gran_k_a = gran_k; const int gran_k_b = gran_k; int sum_k = 0, sum_sf_k = 0; for (const auto k: ks) { sum_k += k, sum_sf_k += ceil_div(k, gran_k * 4); DG_HOST_ASSERT(k % gran_k == 0); } const auto num_groups = static_cast(ks.size()); // Get config using max K for better performance const auto max_k = *std::max_element(ks.begin(), ks.end()); const auto desc = GemmDesc { .gemm_type = GemmType::KGroupedContiguous, .kernel_type = KernelType::Kernel1D1D, .m = m, .n = n, .k = sum_k, .num_groups = num_groups, .a_dtype = a.scalar_type(), .b_dtype = b.scalar_type(), .cd_dtype = d.scalar_type(), .major_a = major_a, .major_b = major_b, .with_accumulation = c.has_value(), .num_sms = device_runtime->get_num_sms(), .tc_util = device_runtime->get_tc_util(), .compiled_dims = compiled_dims, .expected_m = m, .expected_n = n, .expected_k = max_k, .expected_num_groups = num_groups }; const auto config = get_best_config(desc); // Create tensor descriptors const auto tensor_map_a = make_tma_a_desc(cute::UMMA::Major::MN, a, m, sum_k, config.storage_config.load_block_m, config.layout.block_k, static_cast(a.stride(0)), 1, config.storage_config.swizzle_a_mode); const auto tensor_map_b = make_tma_b_desc(cute::UMMA::Major::MN, b, n, sum_k, config.storage_config.load_block_n, config.layout.block_k, static_cast(b.stride(0)), 1, config.storage_config.swizzle_b_mode); const auto tensor_map_cd = make_tma_cd_desc(d, m, n, config.storage_config.store_block_m, config.storage_config.store_block_n, static_cast(d.stride(1)), num_groups, config.storage_config.swizzle_cd_mode); const auto tensor_map_sfa = make_tma_sf_desc(cute::UMMA::Major::MN, sfa, m, sum_sf_k * gran_k_a * 4, config.layout.block_m, gran_k_a, 1, 0); const auto tensor_map_sfb = make_tma_sf_desc(cute::UMMA::Major::MN, sfb, n, sum_sf_k * gran_k_b * 4, config.layout.block_n, gran_k_b, 1, 0); // Launch kernel const SM100FP8FP4Gemm1D1DRuntime::Args args = { .gemm_desc = desc, .gemm_config = config, .launch_args = LaunchArgs(config.launch_config.num_sms, config.launch_config.num_threads, config.pipeline_config.smem_size, config.layout.get_cluster_size()), .epilogue_type = std::nullopt, .gran_k_a = gran_k_a, .gran_k_b = gran_k_b, .grouped_layout = ks_tensor.data_ptr(), .tensor_map_a = tensor_map_a, .tensor_map_b = tensor_map_b, .tensor_map_sfa = tensor_map_sfa, .tensor_map_sfb = tensor_map_sfb, .tensor_map_cd = tensor_map_cd }; const auto code = SM100FP8FP4Gemm1D1DRuntime::generate(args); const auto runtime = compiler->build("sm100_k_grouped_fp8_gemm_1d1d", code); SM100FP8FP4Gemm1D1DRuntime::launch(runtime, args); } static void sm100_fp8_bmm(const torch::Tensor& a, const torch::Tensor& sfa, const torch::Tensor& b, const torch::Tensor& sfb, const std::optional& c, const torch::Tensor& d, const int& batch_size, const int& m, const int& n, const int& k, const int& gran_k_a, const int& gran_k_b, const cute::UMMA::Major& major_a, const cute::UMMA::Major& major_b, const std::string& compiled_dims) { const auto desc = GemmDesc { .gemm_type = GemmType::Batched, .kernel_type = KernelType::Kernel1D1D, .m = m, .n = n, .k = k, .num_groups = batch_size, .a_dtype = a.scalar_type(), .b_dtype = b.scalar_type(), .cd_dtype = d.scalar_type(), .major_a = major_a, .major_b = major_b, .with_accumulation = c.has_value(), .num_sms = device_runtime->get_num_sms(), .tc_util = device_runtime->get_tc_util(), .compiled_dims = compiled_dims }; const auto config = get_best_config(desc); const int load_block_m = config.storage_config.load_block_m; const auto [inner_dim_a, outer_dim_a] = get_inner_outer_dims(major_a, k, m); const auto [inner_block_a, outer_block_a] = get_inner_outer_dims(major_a, config.layout.block_k, load_block_m); const auto tensor_map_a = make_tma_3d_desc(a, inner_dim_a, outer_dim_a, batch_size, inner_block_a, outer_block_a, 1, a.stride(major_a == cute::UMMA::Major::K ? 1 : 2), a.stride(0), config.storage_config.swizzle_a_mode); const int load_block_n = config.storage_config.load_block_n; const auto [inner_dim_b, outer_dim_b] = get_inner_outer_dims(major_b, k, n); const auto [inner_block_b, outer_block_b] = get_inner_outer_dims(major_b, config.layout.block_k, load_block_n); const auto tensor_map_b = make_tma_3d_desc(b, inner_dim_b, outer_dim_b, batch_size, inner_block_b, outer_block_b, 1, b.stride(major_b == cute::UMMA::Major::K ? 1 : 2), b.stride(0), config.storage_config.swizzle_b_mode); const int store_block_m = config.storage_config.store_block_m; const int store_block_n = config.storage_config.store_block_n; const auto tensor_map_cd = make_tma_3d_desc(d, n, m, batch_size, store_block_n, store_block_m, 1, d.stride(1), d.stride(0), config.storage_config.swizzle_cd_mode); const auto tensor_map_sfa = make_tma_sf_desc(cute::UMMA::Major::MN, sfa, m, k, config.layout.block_m, gran_k_a, batch_size, 0); const auto tensor_map_sfb = make_tma_sf_desc(cute::UMMA::Major::MN, sfb, n, k, config.layout.block_n, gran_k_b, batch_size, 0); // Launch const SM100FP8FP4Gemm1D1DRuntime::Args args = { .gemm_desc = desc, .gemm_config = config, .launch_args = LaunchArgs(config.launch_config.num_sms, config.launch_config.num_threads, config.pipeline_config.smem_size, config.layout.get_cluster_size()), .epilogue_type = std::nullopt, .gran_k_a = gran_k_a, .gran_k_b = gran_k_b, .grouped_layout = nullptr, .tensor_map_a = tensor_map_a, .tensor_map_b = tensor_map_b, .tensor_map_sfa = tensor_map_sfa, .tensor_map_sfb = tensor_map_sfb, .tensor_map_cd = tensor_map_cd }; const auto code = SM100FP8FP4Gemm1D1DRuntime::generate(args); const auto runtime = compiler->build("sm100_fp8_gemm_1d1d", code); SM100FP8FP4Gemm1D1DRuntime::launch(runtime, args); } } // namespace deep_gemm