Skip to content
KernelIndex
Search⌘K

submission 73354

gau.nernst · python · License unknown

Use it

Vendorable · source mirrored · license unknownView source →

No package. Vendor the mirrored source: 192 lines, June 9 Researcher Reciprocity License v1.0.

submission_ref2.py
curl "https://kernelindex.com/api/v1/implementations/kernelbot-nvfp4-gemv-73354?include=source"
interfacepython
Compatibility
measured onNVIDIA B200
declared hardwareNVIDIA B200
architecturessm_100
dtypesfp8_e4m3, nvfp4

Benchmark evidence

1 measurement across 1 GPU, fastest first.

Operation / workload
Hardware
Latency
Rank
Observed
NVFP4 GEMVsuite of 3 cases
NVIDIA B200
28.5µs
#140 of 678
2025-11-12

Reported · How evidence levels are derived →

Source and license

sourceavailable
revision digestsha256:da6d410ce0d682bea110e38ef84b284b1c5d677760808176452fdd0909cfc38f
license declaredunknown
license concludedunknown
authorsgau.nernst
imported2026-08-15

Techniques

Extracted from the mirrored source by pattern, never inferred. Each row cites its line.

clusterusing ClusterShape = Shape<_1,_1,_1>;
fp4using ElementAB = cutlass::nv_float4_t<cutlass::float_e2m1_t>;
fused-epilogueusing CollectiveEpilogue = typename cutlass::epilogue::collective::CollectiveBuilder<

Kernel source

submission_ref2.py192 lines
#!POPCORN leaderboard nvfp4_gemv

from pathlib import Path

import torch
from task import input_t, output_t
from torch.utils.cpp_extension import load_inline

# https://github.com/NVIDIA/cutlass/blob/v4.2.1/examples/72_blackwell_narrow_precision_gemm/72b_blackwell_nvfp4_nvfp4_gemm.cu
CUDA_SRC = r"""
#include "cutlass/cutlass.h"

#include "cute/tensor.hpp"
#include "cutlass/tensor_ref.h"
#include "cutlass/epilogue/thread/linear_combination.h"
#include "cutlass/gemm/dispatch_policy.hpp"
#include "cutlass/gemm/collective/collective_builder.hpp"
#include "cutlass/epilogue/collective/collective_builder.hpp"
#include "cutlass/detail/sm100_blockscaled_layout.hpp"
#include "cutlass/gemm/device/gemm_universal_adapter.h"
#include "cutlass/gemm/kernel/gemm_universal.hpp"
#include "cutlass/gemm/kernel/tile_scheduler_params.h"

#include "cutlass/util/packed_stride.hpp"

#include <torch/library.h>
#include <ATen/ATen.h>
#include <ATen/core/Tensor.h>
#include <ATen/cuda/CUDAUtils.h>
#include <ATen/cuda/CUDAContext.h>

#define STRINGIFY(x) #x
#define CUTLASS_CHECK(call) \
  do {                      \
    auto status = call;     \
    TORCH_CHECK(status == cutlass::Status::kSuccess, STRINGIFY(call), ": ", status, " - ", cutlassGetStatusString(status)); \
  } while (0)

using namespace cute;

using ElementAB  = cutlass::nv_float4_t<cutlass::float_e2m1_t>;
using ElementC   = cutlass::half_t;
using ElementAcc = float;

constexpr int AlignmentAB = 128 / 4;  // 32
constexpr int AlignmentC  = 128 / cutlass::sizeof_bits<ElementC>::value;  // 8

using LayoutATag = cutlass::layout::RowMajor;
using LayoutBTag = cutlass::layout::ColumnMajor;
using LayoutCTag = cutlass::layout::RowMajor;

using ArchTag       = cutlass::arch::Sm100;
using OperatorClass = cutlass::arch::OpClassBlockScaledTensorOp;

// Kernel Perf config
using MmaTileShape = Shape<_128,_128,_256>;
using ClusterShape = Shape<_1,_1,_1>;

using CollectiveEpilogue = typename cutlass::epilogue::collective::CollectiveBuilder<
  ArchTag, OperatorClass,
  MmaTileShape, ClusterShape,
  cutlass::epilogue::collective::EpilogueTileAuto,
  ElementAcc, ElementAcc,
  ElementC, LayoutCTag, AlignmentC,
  ElementC, LayoutCTag, AlignmentC,
  cutlass::epilogue::collective::EpilogueScheduleAuto
>::CollectiveOp;

using CollectiveMainloop = typename cutlass::gemm::collective::CollectiveBuilder<
  ArchTag, OperatorClass,
  ElementAB, LayoutATag, AlignmentAB,
  ElementAB, LayoutBTag, AlignmentAB,
  ElementAcc,
  MmaTileShape, ClusterShape,
  cutlass::gemm::collective::StageCountAutoCarveout<static_cast<int>(sizeof(typename CollectiveEpilogue::SharedStorage))>,
  cutlass::gemm::collective::KernelScheduleAuto
>::CollectiveOp;

using GemmKernel = cutlass::gemm::kernel::GemmUniversal<
  Shape<int, int, int, int>,
  CollectiveMainloop,
  CollectiveEpilogue,
  void>;

using Gemm = cutlass::gemm::device::GemmUniversalAdapter<GemmKernel>;

void gemv(
  const at::Tensor& A,
  const at::Tensor& B,
  const at::Tensor& SFA,
  const at::Tensor& SFB,
        at::Tensor& C
) {
  const int M = A.size(0);
  const int N = 128;
  const int K = A.size(1) * 2;
  const int L = A.size(2);

  using ABType = typename ElementAB::DataType;
  using SFType = typename ElementAB::ScaleFactorType;

  auto stride_A = cutlass::make_cute_packed_stride(typename GemmKernel::StrideA{}, {M, K, L});
  auto stride_B = cutlass::make_cute_packed_stride(typename GemmKernel::StrideB{}, {N, K, L});
  auto stride_C = cutlass::make_cute_packed_stride(typename GemmKernel::StrideC{}, {M, N, L});

  using Sm1xxBlkScaledConfig = typename Gemm::GemmKernel::CollectiveMainloop::Sm1xxBlkScaledConfig;
  auto layout_SFA = Sm1xxBlkScaledConfig::tile_atom_to_shape_SFA(cute::make_shape(M, N, K, L));
  auto layout_SFB = Sm1xxBlkScaledConfig::tile_atom_to_shape_SFB(cute::make_shape(M, N, K, L));

  auto *A_ptr   = reinterpret_cast<const ABType *>(A.data_ptr());
  auto *B_ptr   = reinterpret_cast<const ABType *>(B.data_ptr());
  auto *SFA_ptr = reinterpret_cast<const SFType *>(SFA.data_ptr());
  auto *SFB_ptr = reinterpret_cast<const SFType *>(SFB.data_ptr());
  auto *C_ptr   = reinterpret_cast<ElementC *>(C.data_ptr());

  typename Gemm::Arguments arguments{
    cutlass::gemm::GemmUniversalMode::kGemm,
    {M, N, K, L},
    {
      A_ptr, stride_A,
      B_ptr, stride_B,
      SFA_ptr, layout_SFA,
      SFB_ptr, layout_SFB,
    },
    {
      {1.0f, 0.0f},  // alpha and beta
      C_ptr, stride_C,
      C_ptr, stride_C,
    }
  };

  Gemm gemm;
  //CUTLASS_CHECK(gemm.can_implement(arguments));

  //long workspace_size = Gemm::get_workspace_size(arguments);
  //at::Tensor workspace = at::empty({workspace_size}, A.options().dtype(at::kByte));
  auto stream = at::cuda::getCurrentCUDAStream();

  //CUTLASS_CHECK(gemm.initialize(arguments, workspace.data_ptr(), stream));
  CUTLASS_CHECK(gemm.initialize(arguments, 0, stream));
  CUTLASS_CHECK(gemm.run(stream));
}

TORCH_LIBRARY(my_module, m) {
  m.def("gemv(Tensor A, Tensor B, Tensor SFA, Tensor SFB, Tensor(a!) C) -> ()");
  m.impl("gemv", &gemv);
}
"""

load_inline(
    "gemv_c0",
    cpp_sources="",
    cuda_sources=CUDA_SRC,
    verbose=True,
    is_python_module=False,
    no_implicit_headers=True,
    extra_cuda_cflags=[
        "-O3",
        "-gencode=arch=compute_100a,code=sm_100a",
    ],
)


def custom_kernel(data: input_t) -> output_t:
    # a:   [  M, K, L],                   natural shape [L,   M, K]
    # b:   [128, K, L],                   natural shape [L, 128, K] - only the 1st row is used
    # sfa: [32, 4, rest_m, 4, rest_k, L], natural shape [L, rest_m, rest_k, 32, 4, 4]
    # sfb: [32, 4,      1, 4, rest_k, L], natural shape [L,      1, rest_k, 32, 4, 4]
    # c:   [  M, 1, L],                   natural shape [L, M, 1]
    a, b, _, _, sfa, sfb, c_ref = data

    M = a.shape[0]
    N = 128
    K = a.shape[1] * 2
    L = a.shape[2]

    big_c = c_ref.new_empty(L, M, N)
    torch.ops.my_module.gemv(a, b, sfa, sfb, big_c)

    if False:
        path = Path(f"profile_data/{M=}_{K=}_{L=}.json.gz")
        if not path.exists():
            a.new_zeros(int(1e8), dtype=torch.uint8)  # 100 MB

            with torch.profiler.profile() as prof:
                torch.ops.my_module.gemv(a, b, sfa, sfb, big_c)

            path.parent.mkdir(exist_ok=True)
            prof.export_chrome_trace(str(path))

    return big_c[..., :1].permute(1, 2, 0)  # convert to [M, 1, L]
scrolls · 192 lines total

Source code from GPU Mode and the KernelBot dataset · June 9 Researcher Reciprocity License v1.0

Changes from previous submission

Against this author's previous submission submission 69323.

#!POPCORN leaderboard nvfp4_gemv
+ from pathlib import Path
+
import torch
from task import input_t, output_t
+ from torch.utils.cpp_extension import load_inline
+ # https://github.com/NVIDIA/cutlass/blob/v4.2.1/examples/72_blackwell_narrow_precision_gemm/72b_blackwell_nvfp4_nvfp4_gemm.cu
+ CUDA_SRC = r"""
+ #include "cutlass/cutlass.h"
+ #include "cute/tensor.hpp"
+ #include "cutlass/tensor_ref.h"
+ #include "cutlass/epilogue/thread/linear_combination.h"
+ #include "cutlass/gemm/dispatch_policy.hpp"
+ #include "cutlass/gemm/collective/collective_builder.hpp"
+ #include "cutlass/epilogue/collective/collective_builder.hpp"
+ #include "cutlass/detail/sm100_blockscaled_layout.hpp"
+ #include "cutlass/gemm/device/gemm_universal_adapter.h"
+ #include "cutlass/gemm/kernel/gemm_universal.hpp"
+ #include "cutlass/gemm/kernel/tile_scheduler_params.h"
+
+ #include "cutlass/util/packed_stride.hpp"
+
+ #include <torch/library.h>
+ #include <ATen/ATen.h>
+ #include <ATen/core/Tensor.h>
+ #include <ATen/cuda/CUDAUtils.h>
+ #include <ATen/cuda/CUDAContext.h>
+
+ #define STRINGIFY(x) #x
+ #define CUTLASS_CHECK(call) \
+ do { \
+ auto status = call; \
+ TORCH_CHECK(status == cutlass::Status::kSuccess, STRINGIFY(call), ": ", status, " - ", cutlassGetStatusString(status)); \
+ } while (0)
+
+ using namespace cute;
+
+ using ElementAB = cutlass::nv_float4_t<cutlass::float_e2m1_t>;
+ using ElementC = cutlass::half_t;
+ using ElementAcc = float;
+
+ constexpr int AlignmentAB = 128 / 4; // 32
+ constexpr int AlignmentC = 128 / cutlass::sizeof_bits<ElementC>::value; // 8
+
+ using LayoutATag = cutlass::layout::RowMajor;
+ using LayoutBTag = cutlass::layout::ColumnMajor;
+ using LayoutCTag = cutlass::layout::RowMajor;
+
+ using ArchTag = cutlass::arch::Sm100;
+ using OperatorClass = cutlass::arch::OpClassBlockScaledTensorOp;
+
+ // Kernel Perf config
+ using MmaTileShape = Shape<_128,_128,_256>;
+ using ClusterShape = Shape<_1,_1,_1>;
+
+ using CollectiveEpilogue = typename cutlass::epilogue::collective::CollectiveBuilder<
+ ArchTag, OperatorClass,
+ MmaTileShape, ClusterShape,
+ cutlass::epilogue::collective::EpilogueTileAuto,
+ ElementAcc, ElementAcc,
+ ElementC, LayoutCTag, AlignmentC,
+ ElementC, LayoutCTag, AlignmentC,
+ cutlass::epilogue::collective::EpilogueScheduleAuto
+ >::CollectiveOp;
+
+ using CollectiveMainloop = typename cutlass::gemm::collective::CollectiveBuilder<
+ ArchTag, OperatorClass,
+ ElementAB, LayoutATag, AlignmentAB,
+ ElementAB, LayoutBTag, AlignmentAB,
+ ElementAcc,
+ MmaTileShape, ClusterShape,
+ cutlass::gemm::collective::StageCountAutoCarveout<static_cast<int>(sizeof(typename CollectiveEpilogue::SharedStorage))>,
+ cutlass::gemm::collective::KernelScheduleAuto
+ >::CollectiveOp;
+
+ using GemmKernel = cutlass::gemm::kernel::GemmUniversal<
+ Shape<int, int, int, int>,
+ CollectiveMainloop,
+ CollectiveEpilogue,
+ void>;
+
+ using Gemm = cutlass::gemm::device::GemmUniversalAdapter<GemmKernel>;
+
+ void gemv(
+ const at::Tensor& A,
+ const at::Tensor& B,
+ const at::Tensor& SFA,
+ const at::Tensor& SFB,
+ at::Tensor& C
+ ) {
+ const int M = A.size(0);
+ const int N = 128;
+ const int K = A.size(1) * 2;
+ const int L = A.size(2);
+
+ using ABType = typename ElementAB::DataType;
+ using SFType = typename ElementAB::ScaleFactorType;
+
+ auto stride_A = cutlass::make_cute_packed_stride(typename GemmKernel::StrideA{}, {M, K, L});
+ auto stride_B = cutlass::make_cute_packed_stride(typename GemmKernel::StrideB{}, {N, K, L});
+ auto stride_C = cutlass::make_cute_packed_stride(typename GemmKernel::StrideC{}, {M, N, L});
+
+ using Sm1xxBlkScaledConfig = typename Gemm::GemmKernel::CollectiveMainloop::Sm1xxBlkScaledConfig;
+ auto layout_SFA = Sm1xxBlkScaledConfig::tile_atom_to_shape_SFA(cute::make_shape(M, N, K, L));
+ auto layout_SFB = Sm1xxBlkScaledConfig::tile_atom_to_shape_SFB(cute::make_shape(M, N, K, L));
+
+ auto *A_ptr = reinterpret_cast<const ABType *>(A.data_ptr());
+ auto *B_ptr = reinterpret_cast<const ABType *>(B.data_ptr());
+ auto *SFA_ptr = reinterpret_cast<const SFType *>(SFA.data_ptr());
+ auto *SFB_ptr = reinterpret_cast<const SFType *>(SFB.data_ptr());
+ auto *C_ptr = reinterpret_cast<ElementC *>(C.data_ptr());
+
+ typename Gemm::Arguments arguments{
+ cutlass::gemm::GemmUniversalMode::kGemm,
+ {M, N, K, L},
+ {
+ A_ptr, stride_A,
+ B_ptr, stride_B,
+ SFA_ptr, layout_SFA,
+ SFB_ptr, layout_SFB,
+ },
+ {
+ {1.0f, 0.0f}, // alpha and beta
+ C_ptr, stride_C,
+ C_ptr, stride_C,
+ }
+ };
+
+ Gemm gemm;
+ //CUTLASS_CHECK(gemm.can_implement(arguments));
+
+ //long workspace_size = Gemm::get_workspace_size(arguments);
+ //at::Tensor workspace = at::empty({workspace_size}, A.options().dtype(at::kByte));
+ auto stream = at::cuda::getCurrentCUDAStream();
+
+ //CUTLASS_CHECK(gemm.initialize(arguments, workspace.data_ptr(), stream));
+ CUTLASS_CHECK(gemm.initialize(arguments, 0, stream));
+ CUTLASS_CHECK(gemm.run(stream));
+ }
+
+ TORCH_LIBRARY(my_module, m) {
+ m.def("gemv(Tensor A, Tensor B, Tensor SFA, Tensor SFB, Tensor(a!) C) -> ()");
+ m.impl("gemv", &gemv);
+ }
+ """
+
+ load_inline(
+ "gemv_c0",
+ cpp_sources="",
+ cuda_sources=CUDA_SRC,
+ verbose=True,
+ is_python_module=False,
+ no_implicit_headers=True,
+ extra_cuda_cflags=[
+ "-O3",
+ "-gencode=arch=compute_100a,code=sm_100a",
+ ],
+ )
+
+
def custom_kernel(data: input_t) -> output_t:
# a: [ M, K, L], natural shape [L, M, K]
# b: [128, K, L], natural shape [L, 128, K] - only the 1st row is used
⋯ 1 unchanged lines
# sfb: [32, 4, 1, 4, rest_k, L], natural shape [L, 1, rest_k, 32, 4, 4]
# c: [ M, 1, L], natural shape [L, M, 1]
a, b, _, _, sfa, sfb, c_ref = data
- M, _, L = c_ref.shape
- a = a.permute(2, 0, 1) # [L, M, K/2]
- b = b.permute(2, 0, 1) # [L, 128, K/2]
- sfa = sfa.permute(5, 2, 4, 0, 1, 3).view(L, M, -1)
- sfb = sfb.permute(5, 2, 4, 0, 1, 3).view(L, 128, -1)
+ M = a.shape[0]
+ N = 128
+ K = a.shape[1] * 2
+ L = a.shape[2]
- big_c = c_ref.new_empty(L, 128, M).transpose(1, 2) # (L, M, 128), M-major
+ big_c = c_ref.new_empty(L, M, N)
+ torch.ops.my_module.gemv(a, b, sfa, sfb, big_c)
- for l_idx in range(L):
- torch._scaled_mm(
- a[l_idx],
- b[l_idx].transpose(0, 1),
- sfa[l_idx],
- sfb[l_idx],
- out_dtype=torch.float16,
- out=big_c[l_idx],
- )
+ if False:
+ path = Path(f"profile_data/{M=}_{K=}_{L=}.json.gz")
+ if not path.exists():
+ a.new_zeros(int(1e8), dtype=torch.uint8) # 100 MB
- return big_c[..., :1].permute(1, 2, 0) # convert to [L, M, 1]
+ with torch.profiler.profile() as prof:
+ torch.ops.my_module.gemv(a, b, sfa, sfb, big_c)
+
+ path.parent.mkdir(exist_ok=True)
+ prof.export_chrome_trace(str(path))
+
+ return big_c[..., :1].permute(1, 2, 0) # convert to [M, 1, L]
scrolls · 207 diff lines total

Best evidence level for this revision: reported

JSON