gpt-5.5-priority · original · l12_default_gpt
correct 59_Matmul_Swish_Scaling.py
model
gpt-5.5-priority
turns / max
10 / 10
tool calls
10
tokens (total)
0
wall clock
—
truncated
no
backend
cuda fp32
variant
original
runtime
5.28 μs
ref runtime
5.34 μs
speedup
1.01x
started
2026-05-02T18:24:48Z
timingkernelbench.timing
kernel runtime
5.28 μs
ref runtime
5.34 μs
speedup
1.01x
kernel mean / median / std
5.28 / — / 0.01 μs
ref mean / median / std
5.34 / — / 0.06 μs
numerical precisioneval_kernel_against_ref
max abs error
4.77e-07
mean abs error
2.06e-09
max rel error
3.50e-07
mean rel error
6.30e-09
gpu memoryextended_metrics.measure_memory
kernel peak
8257.25 MB
ref peak
8289.25 MB
kernel / ref
1.00x
kernel launches / fusiontorch.profiler
kernel launches
1
ref launches
8
fusion ratio (ref / kernel)
8.00x
total cuda time
20 μs
energyNVML (pynvml)
kernel mJ / run
464.60
ref mJ / run
696.62
ratio (ref / kernel)
1.50x
avg power
84.91 W
ref avg power
123.75 W
SOL (speed-of-light)nsight_hardware_counters
SOL score (0–1)
0.974
dram util %
72.0%
compute util %
97.4%
bottleneck
compute-bound
dominant pipe
FP32
arithmetic intensity
—
ridge point
20.00
roofline / occupancynsight_hardware_counters
dram bandwidth
2412.06 GB/s
dram util %
72.0%
fp32 tflops
—
fp32 util %
—
fp16 tflops
—
occupancy %
90.5%
bottleneck
compute-bound
dominant pipe %
97.4%
arithmetic intensity
—
ridge point
20.00
L1 hit %
—
L2 hit %
122.2%
ld sectors / req
20.00
st sectors / req
—
regs / thread
276
smem / block
35840 B
block size
384
peak bw
3350.00 GB/s
peak fp32 tflops
67.00
peak fp16 tflops
1979.00
warp stalls (top 5)nsight
long_scoreboard
2416.8%
short_scoreboard
281.3%
mio_throttle
182.5%
reference PyTorch source (the prompt the agent sees)
import torch
import torch.nn as nn

class Model(nn.Module):
    """
    Simple model that performs a matrix multiplication, applies Swish activation, and scales the result.
    """
    def __init__(self, in_features, out_features, scaling_factor):
        super(Model, self).__init__()
        self.matmul = nn.Linear(in_features, out_features)
        self.scaling_factor = scaling_factor

    def forward(self, x):
        x = self.matmul(x)
        x = x * torch.sigmoid(x)  # Swish activation
        x = x * self.scaling_factor
        return x

batch_size = 128
in_features = 32768
out_features = 32768
scaling_factor = 2.0

def get_inputs():
    return [torch.rand(batch_size, in_features)]

def get_init_inputs():
    return [in_features, out_features, scaling_factor]
turn 09.6s turn · 9.6s LLM · 0.0s tools
reasoning
**Exploring CUDA options** I'm contemplating implementing forward calls with torch.ops, but I wonder if I really need a fallback. Maybe torch.nn.Linear could help me maintain speed. I’m looking into cuBLASLt for possible optimizations, but it seems it doesn't fully support activation functions like swish. I’m considering how to fuse kernels or exploit randomness in inputs and weights to check for correctness. It might be useful to inspect GPU specs before moving forward.
call → get_gpu_specs
callget_gpu_specs {}
result ← get_gpu_specs (ok)
okget_gpu_specs GPU specs for NVIDIA H100 80GB HBM3: total memory (runtime): 79.1 GB spec entry: H100 GPU Architecture: Hopper GPU Memory: 80GB Memory Bandwidth: 3.35 TB/s FP64 TFLOPS: 34 FP64 Tensor Core TFLOPS: 67 FP32 TFLOPS: 67 TF32 Tensor Core TFLOPS: 989 with sparsity BFLOAT16 Tensore Core TFLOPS: 1979 with sparsity FP16 Tensor Core TFLOPS: 1979 with sparsity FP8 Tensor Core TFLOPS: 3958 with sparsity INT8 Tensor Core TOPS: 3958 with sparsity Register File Size: 64K 32-bit registers per SM Maximum number of registers per thread: 255 Maximum number of thread blocks per SM: 32 Shared memory capacity per SM: 228 KB Maximum shared memory per thread block: 227 KB
turn 1 · 1 tool call(s) · 28.2s turn · 28.2s LLM · 8,898 chars (click to expand)
turn 128.2s turn · 28.2s LLM · 0.0s tools
reasoning
**Exploring PyTorch optimizations** I’m delving into how PyTorch’s linear operations might use TF32 by default for fp32 matmul, considering tolerances around 1e-4. It looks like the torch.rand function could also apply, and I'm pondering if nn.Linear indeed defaults to TF32. Since I'm messing with custom calls to cuBLAS for high performance, combining with activation kernels could be useful. There's a thought on whether to use cuBLAS instead of creating my own implementation which might have less overhead. **Calculating GEMM performance** GEMM operations run around 0.14 TFLOP, while the H100 hits around 1000 TFLOPS with TF32, suggesting it takes about 0.14 ms. But memory weights at 4GB indicate it could take more than 1.2 ms because activation elements are around 4 million, which seems negligible. I’m considering managing weight layouts, especially with nn.Linear using row-major storage. I might need to use a custom kernel with cublasSgemm and apply a row-major trick while keeping track of memory dimensions correctly. **Testing PyTorch parameters** I'm considering how PyTorch’s use of TF32 might lead to different algorithms having discrepancies greater than 1e-4. However, the reference tolerance relies on fp32 at 1e-4. I wonder if a custom matrix multiplication function with a torch-like setup using TF32 could still pass tests if it’s relative. It feels like I should compile and run some tests to see how these differences play out!
call → compile_kernel
callcompile_kernel { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <cuda_runtime.h>\n#include <cublas_v2.h>\n#include <mutex>\n\nstatic cublasHandle_t get_handle() {\n static cublasHandle_t handle = nullptr;\n static std::once_flag flag;\n std::call_once(flag, [](){\n cublasCreate(&handle);\n cublasSetMathMode(handle, CUBLAS_TF32_TENSOR_OP_MATH);\n });\n return handle;\n}\n\n__global__ void bias_swish_scale_kernel(float* __restrict__ y, const float* __restrict__ bias, int total, int N, float scale) {\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n int stride = blockDim.x * gridDim.x;\n for (int t = idx; t < total; t += stride) {\n int j = t % N;\n float v = y[t] + bias[j];\n float s = 1.0f / (1.0f + expf(-v));\n y[t] = v * s * scale;\n }\n}\n\ntorch::Tensor linear_swish_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double scale_d) {\n TORCH_CHECK(x.is_cuda() && weight.is_cuda() && bias.is_cuda(), \"tensors must be CUDA\");\n TORCH_CHECK(x.dtype() == torch::kFloat32 && weight.dtype() == torch::kFloat32 && bias.dtype() == torch::kFloat32, \"float32 only\");\n TORCH_CHECK(x.is_contiguous() && weight.is_contiguous() && bias.is_contiguous(), \"contiguous only\");\n int64_t M64 = x.size(0);\n int64_t K64 = x.size(1);\n int64_t N64 = weight.size(0);\n TORCH_CHECK(weight.size(1) == K64 && bias.size(0) == N64, \"shape mismatch\");\n auto y = torch::empty({M64, N64}, x.options());\n int M = (int)M64, N = (int)N64, K = (int)K64;\n float alpha = 1.0f, beta = 0.0f;\n cublasHandle_t handle = get_handle();\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n cublasSetStream(handle, stream);\n // Row-major y[M,N] as column-major y_col[N,M] = op(weight_col[K,N])^T * x_col[K,M]\n cublasStatus_t st = cublasSgemm(handle, CUBLAS_OP_T, CUBLAS_OP_N,\n N, M, K,\n &alpha,\n weight.data_ptr<float>(), K,\n x.data_ptr<float>(), K,\n &beta,\n y.data_ptr<float>(), N);\n TORCH_CHECK(st == CUBLAS_STATUS_SUCCESS, \"cublasSgemm failed\");\n int total = M * N;\n int threads = 256;\n int blocks = (total + threads - 1) / threads;\n if (blocks > 65535) blocks = 65535;\n bias_swish_scale_kernel<<<blocks, threads, 0, stream>>>(y.data_ptr<float>(), bias.data_ptr<float>(), total, N, (float)scale_d);\n C10_CUDA_KERNEL_LAUNCH_CHECK();\n return y;\n}\n'''\n\n_ext = load_inline(name='linear_swish_ext_v1', cpp_sources='', cuda_sources=_cuda_src,\n functions=['linear_swish_forward'], extra_cuda_cflags=['-O3'],\n extra_ldflags=['-lcublas'], verbose=False)\n\nclass ModelNew(nn.Module):\n def __init__(self, in_features, out_features, scaling_factor):\n super(ModelNew, self).__init__()\n self.matmul = nn.Linear(in_features, out_features)\n self.scaling_factor = scaling_factor\n def forward(self, x):\n return _ext.linear_swish_forward(x.contiguous(), self.matmul.weight, self.matmul.bias, float(self.scaling_factor))\n" }
result ← compile_kernel (fail)
failcompile_kernel compile_kernel FAILED: RuntimeError. RuntimeError: Error building extension 'linear_swish_ext_v1': [1/3] /opt/conda/bin/x86_64-conda-linux-gnu-c++ -MMD -MF main.o.d -DTORCH_EXTENSION_NAME=linear_swish_ext_v1 -DTORCH_API_INCLUDE_EXTENSION_H -isystem /scratch/tejas/PopcornBench/.venv/lib/python3.10/site-packages/torch/include -isystem /scratch/tejas/PopcornBench/.venv/lib/python3.10/site-packages/torch/include/torch/csrc/api/include -isystem /usr/local/cuda/include -isystem /home/prabhune/.local/share/uv/python/cpython-3.10-linux-x86_64-gnu/include/python3.10 -fPIC -std=c++17 -c /scratch/tejas/PopcornBench/runs/l12_default/original/gpt-5.5-priority/level_2_problem_59_cache/k_c0354e7eb8f3/linear_swish_ext_v1/main.cpp -o main.o FAILED: [code=1] main.o /opt/conda/bin/x86_64-conda-linux-gnu-c++ -MMD -MF main.o.d -DTORCH_EXTENSION_NAME=linear_swish_ext_v1 -DTORCH_API_INCLUDE_EXTENSION_H -isystem /scratch/tejas/PopcornBench/.venv/lib/python3.10/site-packages/torch/include -isystem /scratch/tejas/PopcornBench/.venv/lib/python3.10/site-packages/torch/include/torch/csrc/api/include -isystem /usr/local/cuda/include -isystem /home/prabhune/.local/share/uv/python/cpython-3.10-linux-x86_64-gnu/include/python3.10 -fPIC -std=c++17 -c /scratch/tejas/PopcornBench/runs/l12_default/original/gpt-5.5-priority/level_2_problem_59_cache/k_c0354e7eb8f3/linear_swish_ext_v1/main.cpp -o main.o /scratch/tejas/PopcornBench/runs/l12_default/original/gpt-5.5-priority/level_2_problem_59_cache/k_c0354e7eb8f3/linear_swish_ext_v1/main.cpp: In function 'void pybind11_init_linear_swish_ext_v1(pybind11::module_&)': /scratch/tejas/PopcornBench/runs/l12_default/original/gpt-5.5-priority/level_2_problem_59_cache/k_c0354e7eb8f3/linear_swish_ext_v1/main.cpp:4:59: error: 'linear_swish_forward' was not declared in this scope 4 | m.def("linear_swish_forward", torch::wrap_pybind_function(linear_swish_forward), "linear_swish_forward"); | ^~~~~~~~~~~~~~~~~~~~ [2/3] /usr/local/cuda/bin/nvcc -MD -MF cuda.cuda.o.d -ccbin /opt/conda/bin/x86_64-conda-linux-gnu-cc -DTORCH_EXTENSION_NAME=linear_swish_ext_v1 -DTORCH_API_INCLUDE_EXTENSION_H -isystem /scratch/tejas/PopcornBench/.venv/lib/python3.10/site-packages/torch/include -isystem /scratch/tejas/PopcornBench/.venv/lib/python3.10/site-packages/torch/include/torch/csrc/api/include -isystem /usr/local/cuda/include -isystem /home/prabhune/.local/share/uv/python/cpython-3.10-linux-x86_64-gnu/include/python3.10 -D__CUDA_NO_HALF_OPERATORS__ -D__CUDA_NO_HALF_CONVERSIONS__ -D__CUDA_NO_BFLOAT16_CONVERSIONS__ -D__CUDA_NO_HALF2_OPERATORS__ --expt-relaxed-constexpr -gencode=arch=compute_90,code=compute_90 -gencode=arch=compute_90,code=sm_90 --compiler-options '-fPIC' -O3 -std=c++17 -c /scratch/tejas/PopcornBench/runs/l12_default/original/gpt-5.5-priority/level_2_problem_59_cache/k_c0354e7eb8f3/linear_swish_ext_v1/cuda.cu -o cuda.cuda.o nvcc warning : incompatible redefinition for option 'compiler-bindir', the last value of this option was used ninja: build stopped: subcommand failed.
turn 27.9s turn · 7.9s LLM · 0.0s tools
reasoning
**Resolving C++ function declaration** I need to declare a C++ function since the auto-generated `main.cpp` isn't recognizing the CUDA function. It seems that if the function in `cuda_sources` isn't included in the main file, it won't work. To fix this, I should include a declaration for `torch::Tensor linear_swish_forward(...);` in the `cpp_sources`. This will help ensure that the function is recognized properly. Let's enhance this code now!
call → compile_kernel
callcompile_kernel { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n_cpp_src = r'''\n#include <torch/extension.h>\ntorch::Tensor linear_swish_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double scale_d);\n'''\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <cuda_runtime.h>\n#include <cublas_v2.h>\n#include <mutex>\n\nstatic cublasHandle_t get_handle() {\n static cublasHandle_t handle = nullptr;\n static std::once_flag flag;\n std::call_once(flag, [](){\n cublasCreate(&handle);\n cublasSetMathMode(handle, CUBLAS_TF32_TENSOR_OP_MATH);\n });\n return handle;\n}\n\n__global__ void bias_swish_scale_kernel(float* __restrict__ y, const float* __restrict__ bias, int total, int N, float scale) {\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n int stride = blockDim.x * gridDim.x;\n for (int t = idx; t < total; t += stride) {\n int j = t % N;\n float v = y[t] + bias[j];\n float s = 1.0f / (1.0f + expf(-v));\n y[t] = v * s * scale;\n }\n}\n\ntorch::Tensor linear_swish_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double scale_d) {\n TORCH_CHECK(x.is_cuda() && weight.is_cuda() && bias.is_cuda(), \"tensors must be CUDA\");\n TORCH_CHECK(x.dtype() == torch::kFloat32 && weight.dtype() == torch::kFloat32 && bias.dtype() == torch::kFloat32, \"float32 only\");\n TORCH_CHECK(x.is_contiguous() && weight.is_contiguous() && bias.is_contiguous(), \"contiguous only\");\n int64_t M64 = x.size(0);\n int64_t K64 = x.size(1);\n int64_t N64 = weight.size(0);\n TORCH_CHECK(weight.size(1) == K64 && bias.size(0) == N64, \"shape mismatch\");\n auto y = torch::empty({M64, N64}, x.options());\n int M = (int)M64, N = (int)N64, K = (int)K64;\n float alpha = 1.0f, beta = 0.0f;\n cublasHandle_t handle = get_handle();\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n cublasSetStream(handle, stream);\n cublasStatus_t st = cublasSgemm(handle, CUBLAS_OP_T, CUBLAS_OP_N,\n N, M, K,\n &alpha,\n weight.data_ptr<float>(), K,\n x.data_ptr<float>(), K,\n &beta,\n y.data_ptr<float>(), N);\n TORCH_CHECK(st == CUBLAS_STATUS_SUCCESS, \"cublasSgemm failed\");\n int total = M * N;\n int threads = 256;\n int blocks = (total + threads - 1) / threads;\n if (blocks > 65535) blocks = 65535;\n bias_swish_scale_kernel<<<blocks, threads, 0, stream>>>(y.data_ptr<float>(), bias.data_ptr<float>(), total, N, (float)scale_d);\n C10_CUDA_KERNEL_LAUNCH_CHECK();\n return y;\n}\n'''\n\n_ext = load_inline(name='linear_swish_ext_v2', cpp_sources=_cpp_src, cuda_sources=_cuda_src,\n functions=['linear_swish_forward'], extra_cuda_cflags=['-O3'],\n extra_ldflags=['-lcublas'], verbose=False)\n\nclass ModelNew(nn.Module):\n def __init__(self, in_features, out_features, scaling_factor):\n super(ModelNew, self).__init__()\n self.matmul = nn.Linear(in_features, out_features)\n self.scaling_factor = scaling_factor\n def forward(self, x):\n return _ext.linear_swish_forward(x.contiguous(), self.matmul.weight, self.matmul.bias, float(self.scaling_factor))\n" }
result ← compile_kernel (ok)
okcompile_kernel compile_kernel PASSED: kernel compiled without errors.
turn 37.2s turn · 7.2s LLM · 0.0s tools
call → run_correctness
callrun_correctness { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n_cpp_src = r'''\n#include <torch/extension.h>\ntorch::Tensor linear_swish_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double scale_d);\n'''\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <cuda_runtime.h>\n#include <cublas_v2.h>\n#include <mutex>\n\nstatic cublasHandle_t get_handle() {\n static cublasHandle_t handle = nullptr;\n static std::once_flag flag;\n std::call_once(flag, [](){\n cublasCreate(&handle);\n cublasSetMathMode(handle, CUBLAS_TF32_TENSOR_OP_MATH);\n });\n return handle;\n}\n\n__global__ void bias_swish_scale_kernel(float* __restrict__ y, const float* __restrict__ bias, int total, int N, float scale) {\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n int stride = blockDim.x * gridDim.x;\n for (int t = idx; t < total; t += stride) {\n int j = t % N;\n float v = y[t] + bias[j];\n float s = 1.0f / (1.0f + expf(-v));\n y[t] = v * s * scale;\n }\n}\n\ntorch::Tensor linear_swish_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double scale_d) {\n TORCH_CHECK(x.is_cuda() && weight.is_cuda() && bias.is_cuda(), \"tensors must be CUDA\");\n TORCH_CHECK(x.dtype() == torch::kFloat32 && weight.dtype() == torch::kFloat32 && bias.dtype() == torch::kFloat32, \"float32 only\");\n TORCH_CHECK(x.is_contiguous() && weight.is_contiguous() && bias.is_contiguous(), \"contiguous only\");\n int64_t M64 = x.size(0);\n int64_t K64 = x.size(1);\n int64_t N64 = weight.size(0);\n TORCH_CHECK(weight.size(1) == K64 && bias.size(0) == N64, \"shape mismatch\");\n auto y = torch::empty({M64, N64}, x.options());\n int M = (int)M64, N = (int)N64, K = (int)K64;\n float alpha = 1.0f, beta = 0.0f;\n cublasHandle_t handle = get_handle();\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n cublasSetStream(handle, stream);\n cublasStatus_t st = cublasSgemm(handle, CUBLAS_OP_T, CUBLAS_OP_N,\n N, M, K,\n &alpha,\n weight.data_ptr<float>(), K,\n x.data_ptr<float>(), K,\n &beta,\n y.data_ptr<float>(), N);\n TORCH_CHECK(st == CUBLAS_STATUS_SUCCESS, \"cublasSgemm failed\");\n int total = M * N;\n int threads = 256;\n int blocks = (total + threads - 1) / threads;\n if (blocks > 65535) blocks = 65535;\n bias_swish_scale_kernel<<<blocks, threads, 0, stream>>>(y.data_ptr<float>(), bias.data_ptr<float>(), total, N, (float)scale_d);\n C10_CUDA_KERNEL_LAUNCH_CHECK();\n return y;\n}\n'''\n\n_ext = load_inline(name='linear_swish_ext_v2', cpp_sources=_cpp_src, cuda_sources=_cuda_src,\n functions=['linear_swish_forward'], extra_cuda_cflags=['-O3'],\n extra_ldflags=['-lcublas'], verbose=False)\n\nclass ModelNew(nn.Module):\n def __init__(self, in_features, out_features, scaling_factor):\n super(ModelNew, self).__init__()\n self.matmul = nn.Linear(in_features, out_features)\n self.scaling_factor = scaling_factor\n def forward(self, x):\n return _ext.linear_swish_forward(x.contiguous(), self.matmul.weight, self.matmul.bias, float(self.scaling_factor))\n" }
result ← run_correctness (fail)
failrun_correctness run_correctness FAILED: (0 / 5) trials did not all match. correctness_issue: Output mismatch max_difference: ['0.000784', '0.000800', '0.000779', '0.000872', '0.000878'] avg_difference: ['0.000078', '0.000078', '0.000078', '0.000078', '0.000078']
turn 47.0s turn · 7.0s LLM · 0.0s tools
reasoning
**Diagnosing TF32 issues** I'm encountering a mismatch due to the TF32 algorithm. I think I need to match the reference properly to see what's going on. It looks like PyTorch might be using full FP32 instead. I'm suspecting that using cublasSgemm with TF32 is causing the error. I should set CUBLAS_DEFAULT_MATH to avoid using TF32. Then I guess I'll need to investigate the differences further and run a test to confirm my suspicions.
call → run_correctness
callrun_correctness { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n_cpp_src = r'''\n#include <torch/extension.h>\ntorch::Tensor linear_swish_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double scale_d);\n'''\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <cuda_runtime.h>\n#include <cublas_v2.h>\n#include <mutex>\nstatic cublasHandle_t get_handle() { static cublasHandle_t handle=nullptr; static std::once_flag flag; std::call_once(flag, [](){ cublasCreate(&handle); cublasSetMathMode(handle, CUBLAS_DEFAULT_MATH); }); return handle; }\n__global__ void bias_swish_scale_kernel(float* __restrict__ y, const float* __restrict__ bias, int total, int N, float scale) { int idx=blockIdx.x*blockDim.x+threadIdx.x; int stride=blockDim.x*gridDim.x; for(int t=idx;t<total;t+=stride){ float v=y[t]+bias[t%N]; float s=1.0f/(1.0f+expf(-v)); y[t]=v*s*scale; } }\ntorch::Tensor linear_swish_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double scale_d) { int64_t M64=x.size(0), K64=x.size(1), N64=weight.size(0); auto y=torch::empty({M64,N64}, x.options()); int M=(int)M64,N=(int)N64,K=(int)K64; float alpha=1.0f,beta=0.0f; cublasHandle_t handle=get_handle(); cudaStream_t stream=at::cuda::getCurrentCUDAStream(); cublasSetStream(handle, stream); cublasSetMathMode(handle, CUBLAS_DEFAULT_MATH); cublasStatus_t st=cublasSgemm(handle,CUBLAS_OP_T,CUBLAS_OP_N,N,M,K,&alpha,weight.data_ptr<float>(),K,x.data_ptr<float>(),K,&beta,y.data_ptr<float>(),N); TORCH_CHECK(st==CUBLAS_STATUS_SUCCESS,\"cublasSgemm failed\"); int total=M*N; int threads=256; int blocks=(total+threads-1)/threads; if(blocks>65535) blocks=65535; bias_swish_scale_kernel<<<blocks,threads,0,stream>>>(y.data_ptr<float>(),bias.data_ptr<float>(),total,N,(float)scale_d); C10_CUDA_KERNEL_LAUNCH_CHECK(); return y; }\n'''\n_ext=load_inline(name='linear_swish_ext_v3', cpp_sources=_cpp_src, cuda_sources=_cuda_src, functions=['linear_swish_forward'], extra_cuda_cflags=['-O3'], extra_ldflags=['-lcublas'], verbose=False)\nclass ModelNew(nn.Module):\n def __init__(self,in_features,out_features,scaling_factor):\n super(ModelNew,self).__init__(); self.matmul=nn.Linear(in_features,out_features); self.scaling_factor=scaling_factor\n def forward(self,x):\n return _ext.linear_swish_forward(x.contiguous(), self.matmul.weight, self.matmul.bias, float(self.scaling_factor))\n" }
result ← run_correctness (ok)
okrun_correctness run_correctness PASSED: (5 / 5) trials all matched the reference. Numerical precision: max_abs_err=0.00e+00 mean_abs_err=0.00e+00 max_rel_err=0.00e+00
turn 535.1s turn · 35.1s LLM · 0.0s tools
reasoning
**Optimizing processing configuration** I'm considering the configuration of my processing setup with parameters M=128 and N=32768. This gives me 16384 blocks when using blocks of size 128x128, which seems good. With 256 threads, I'm aiming for efficient memory access. I want to ensure that the block dimensions are set correctly to 256 so that I can really optimize performance. Plus, making sure that each row is organized for coalesced access will help overall efficiency!
call → run_correctness
callrun_correctness { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n_cpp_src = r'''\n#include <torch/extension.h>\ntorch::Tensor linear_swish_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double scale_d);\n'''\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <cuda_runtime.h>\n#include <cublas_v2.h>\n#include <mutex>\nstatic cublasHandle_t get_handle(){static cublasHandle_t h=nullptr; static std::once_flag f; std::call_once(f, [](){cublasCreate(&h); cublasSetMathMode(h,CUBLAS_DEFAULT_MATH);}); return h;}\n__global__ void bias_swish_scale_2d(float* __restrict__ y, const float* __restrict__ bias, int M, int N, float scale){\n int col = blockIdx.x * blockDim.x + threadIdx.x;\n int row = blockIdx.y;\n if (row < M && col < N) {\n int t = row * N + col;\n float v = y[t] + bias[col];\n float s = 1.0f / (1.0f + expf(-v));\n y[t] = v * s * scale;\n }\n}\ntorch::Tensor linear_swish_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double scale_d){\n int64_t M64=x.size(0), K64=x.size(1), N64=weight.size(0); auto y=torch::empty({M64,N64}, x.options()); int M=(int)M64,N=(int)N64,K=(int)K64; float alpha=1.0f,beta=0.0f; cublasHandle_t h=get_handle(); cudaStream_t s=at::cuda::getCurrentCUDAStream(); cublasSetStream(h,s); cublasStatus_t st=cublasSgemm(h,CUBLAS_OP_T,CUBLAS_OP_N,N,M,K,&alpha,weight.data_ptr<float>(),K,x.data_ptr<float>(),K,&beta,y.data_ptr<float>(),N); TORCH_CHECK(st==CUBLAS_STATUS_SUCCESS,\"cublasSgemm failed\"); dim3 block(256); dim3 grid((N+255)/256, M); bias_swish_scale_2d<<<grid,block,0,s>>>(y.data_ptr<float>(),bias.data_ptr<float>(),M,N,(float)scale_d); C10_CUDA_KERNEL_LAUNCH_CHECK(); return y;}\n'''\n_ext=load_inline(name='linear_swish_ext_v4', cpp_sources=_cpp_src, cuda_sources=_cuda_src, functions=['linear_swish_forward'], extra_cuda_cflags=['-O3'], extra_ldflags=['-lcublas'], verbose=False)\nclass ModelNew(nn.Module):\n def __init__(self,in_features,out_features,scaling_factor):\n super(ModelNew,self).__init__(); self.matmul=nn.Linear(in_features,out_features); self.scaling_factor=scaling_factor\n def forward(self,x):\n return _ext.linear_swish_forward(x.contiguous(), self.matmul.weight, self.matmul.bias, float(self.scaling_factor))\n" }
result ← run_correctness (ok)
okrun_correctness run_correctness PASSED: (5 / 5) trials all matched the reference. Numerical precision: max_abs_err=0.00e+00 mean_abs_err=0.00e+00 max_rel_err=0.00e+00
turn 67.9s turn · 7.9s LLM · 0.0s tools
call → run_correctness
callrun_correctness { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n_cpp_src = r'''\n#include <torch/extension.h>\ntorch::Tensor linear_swish_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double scale_d);\n'''\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <cuda_runtime.h>\n#include <cublas_v2.h>\n#include <mutex>\nstatic cublasHandle_t get_handle(){static cublasHandle_t h=nullptr; static std::once_flag f; std::call_once(f, [](){cublasCreate(&h); cublasSetMathMode(h,CUBLAS_DEFAULT_MATH);}); return h;}\n__global__ void bias_swish_scale_2d(float* __restrict__ y, const float* __restrict__ bias, int M, int N, float scale){int col=blockIdx.x*blockDim.x+threadIdx.x; int row=blockIdx.y; if(row<M && col<N){int t=row*N+col; float v=y[t]+bias[col]; float s=1.0f/(1.0f+__expf(-v)); y[t]=v*s*scale;}}\ntorch::Tensor linear_swish_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double scale_d){int64_t M64=x.size(0),K64=x.size(1),N64=weight.size(0); auto y=torch::empty({M64,N64},x.options()); int M=(int)M64,N=(int)N64,K=(int)K64; float a=1,b=0; cublasHandle_t h=get_handle(); cudaStream_t s=at::cuda::getCurrentCUDAStream(); cublasSetStream(h,s); auto st=cublasSgemm(h,CUBLAS_OP_T,CUBLAS_OP_N,N,M,K,&a,weight.data_ptr<float>(),K,x.data_ptr<float>(),K,&b,y.data_ptr<float>(),N); TORCH_CHECK(st==CUBLAS_STATUS_SUCCESS,\"cublas\"); bias_swish_scale_2d<<<dim3((N+255)/256,M),dim3(256),0,s>>>(y.data_ptr<float>(),bias.data_ptr<float>(),M,N,(float)scale_d); C10_CUDA_KERNEL_LAUNCH_CHECK(); return y;}\n'''\n_ext=load_inline(name='linear_swish_ext_v5', cpp_sources=_cpp_src, cuda_sources=_cuda_src, functions=['linear_swish_forward'], extra_cuda_cflags=['-O3'], extra_ldflags=['-lcublas'], verbose=False)\nclass ModelNew(nn.Module):\n def __init__(self,in_features,out_features,scaling_factor):\n super(ModelNew,self).__init__(); self.matmul=nn.Linear(in_features,out_features); self.scaling_factor=scaling_factor\n def forward(self,x): return _ext.linear_swish_forward(x.contiguous(), self.matmul.weight, self.matmul.bias, float(self.scaling_factor))\n" }
result ← run_correctness (ok)
okrun_correctness run_correctness PASSED: (5 / 5) trials all matched the reference. Numerical precision: max_abs_err=4.77e-07 mean_abs_err=2.06e-09 max_rel_err=3.50e-07
turn 78.8s turn · 8.8s LLM · 0.0s tools
call → static_check
callstatic_check { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n_cpp_src = r'''\n#include <torch/extension.h>\ntorch::Tensor linear_swish_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double scale_d);\n'''\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <cuda_runtime.h>\n#include <cublas_v2.h>\n#include <mutex>\nstatic cublasHandle_t get_handle(){static cublasHandle_t h=nullptr; static std::once_flag f; std::call_once(f, [](){cublasCreate(&h); cublasSetMathMode(h,CUBLAS_DEFAULT_MATH);}); return h;}\n__global__ void bias_swish_scale_2d(float* __restrict__ y, const float* __restrict__ bias, int M, int N, float scale){int col=blockIdx.x*blockDim.x+threadIdx.x; int row=blockIdx.y; if(row<M && col<N){int t=row*N+col; float v=y[t]+bias[col]; float s=1.0f/(1.0f+__expf(-v)); y[t]=v*s*scale;}}\ntorch::Tensor linear_swish_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double scale_d){int64_t M64=x.size(0),K64=x.size(1),N64=weight.size(0); auto y=torch::empty({M64,N64},x.options()); int M=(int)M64,N=(int)N64,K=(int)K64; float a=1,b=0; cublasHandle_t h=get_handle(); cudaStream_t s=at::cuda::getCurrentCUDAStream(); cublasSetStream(h,s); auto st=cublasSgemm(h,CUBLAS_OP_T,CUBLAS_OP_N,N,M,K,&a,weight.data_ptr<float>(),K,x.data_ptr<float>(),K,&b,y.data_ptr<float>(),N); TORCH_CHECK(st==CUBLAS_STATUS_SUCCESS,\"cublas\"); bias_swish_scale_2d<<<dim3((N+255)/256,M),dim3(256),0,s>>>(y.data_ptr<float>(),bias.data_ptr<float>(),M,N,(float)scale_d); C10_CUDA_KERNEL_LAUNCH_CHECK(); return y;}\n'''\n_ext=load_inline(name='linear_swish_ext_final', cpp_sources=_cpp_src, cuda_sources=_cuda_src, functions=['linear_swish_forward'], extra_cuda_cflags=['-O3'], extra_ldflags=['-lcublas'], verbose=False)\nclass ModelNew(nn.Module):\n def __init__(self,in_features,out_features,scaling_factor):\n super(ModelNew,self).__init__(); self.matmul=nn.Linear(in_features,out_features); self.scaling_factor=scaling_factor\n def forward(self,x): return _ext.linear_swish_forward(x.contiguous(), self.matmul.weight, self.matmul.bias, float(self.scaling_factor))\n" }
result ← static_check (ok)
okstatic_check static_check PASSED: no violations or warnings detected.
turn 820.0s turn · 20.0s LLM · 0.0s tools
reasoning
**Exploring optimization for performance** I need to consider submitting but wonder if there's still room for optimization, especially with timing. I'm thinking about reference points like PyTorch, which might use torch Linear with cuBLAS TF32 by default, but correctness seems tricky if they're not using TF32. I need to ensure our implementation runs efficiently—maybe we need to check if torch's matmul disables TF32 during benchmarks. My approach could also involve fusing operations for speed compared to standard methods. **Exploring custom kernel optimization** I'm considering whether I could use cublasLt to create a custom epilogue to fuse biases since swish isn't available. Maybe I could implement a cublasLt matmul for bias alongside a swish scale kernel. Although cublasLt might be faster, it does complicate the compilation process. I need to think about optimizing the activation kernel with vectorized float4, given my current setup of 4M elements, to reduce overhead and improve performance. I also need to ensure proper alignment and handle memory efficiently. **Planning tool call testing** I’m considering testing the compilation and correctness of tool calls, aiming for two this time around. However, the user mentions there are still 22 tool calls left to make in total. This turn should allow some tool calls, so I’ll focus on running correctness checks with vectorization before submission. It's important to ensure I include the cublas defaults in my approach. Let’s see how I can streamline this to maintain efficiency!
call → run_correctness
callrun_correctness { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n_cpp_src = r'''\n#include <torch/extension.h>\ntorch::Tensor linear_swish_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double scale_d);\n'''\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <cuda_runtime.h>\n#include <cublas_v2.h>\n#include <mutex>\nstatic cublasHandle_t get_handle(){static cublasHandle_t h=nullptr; static std::once_flag f; std::call_once(f, [](){cublasCreate(&h); cublasSetMathMode(h,CUBLAS_DEFAULT_MATH);}); return h;}\n__device__ __forceinline__ float sw(float v, float scale){return v*(1.0f/(1.0f+__expf(-v)))*scale;}\n__global__ void bias_swish_scale_vec4(float* __restrict__ y, const float* __restrict__ bias, int M, int N4, float scale){\n int col4 = blockIdx.x * blockDim.x + threadIdx.x;\n int row = blockIdx.y;\n if(row < M && col4 < N4){\n int idx4 = row * N4 + col4;\n float4 yy = reinterpret_cast<float4*>(y)[idx4];\n float4 bb = reinterpret_cast<const float4*>(bias)[col4];\n yy.x = sw(yy.x + bb.x, scale);\n yy.y = sw(yy.y + bb.y, scale);\n yy.z = sw(yy.z + bb.z, scale);\n yy.w = sw(yy.w + bb.w, scale);\n reinterpret_cast<float4*>(y)[idx4] = yy;\n }\n}\n__global__ void bias_swish_scale_scalar(float* __restrict__ y, const float* __restrict__ bias, int total, int N, float scale){int i=blockIdx.x*blockDim.x+threadIdx.x; if(i<total){float v=y[i]+bias[i%N]; y[i]=sw(v,scale);}}\ntorch::Tensor linear_swish_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double scale_d){\n int64_t M64=x.size(0),K64=x.size(1),N64=weight.size(0); auto y=torch::empty({M64,N64},x.options()); int M=(int)M64,N=(int)N64,K=(int)K64; float a=1,b=0; cublasHandle_t h=get_handle(); cudaStream_t s=at::cuda::getCurrentCUDAStream(); cublasSetStream(h,s); auto st=cublasSgemm(h,CUBLAS_OP_T,CUBLAS_OP_N,N,M,K,&a,weight.data_ptr<float>(),K,x.data_ptr<float>(),K,&b,y.data_ptr<float>(),N); TORCH_CHECK(st==CUBLAS_STATUS_SUCCESS,\"cublas\"); float scale=(float)scale_d; if((N%4)==0){int N4=N/4; bias_swish_scale_vec4<<<dim3((N4+255)/256,M),dim3(256),0,s>>>(y.data_ptr<float>(),bias.data_ptr<float>(),M,N4,scale);} else {int total=M*N; bias_swish_scale_scalar<<<(total+255)/256,256,0,s>>>(y.data_ptr<float>(),bias.data_ptr<float>(),total,N,scale);} C10_CUDA_KERNEL_LAUNCH_CHECK(); return y;}\n'''\n_ext=load_inline(name='linear_swish_ext_v6', cpp_sources=_cpp_src, cuda_sources=_cuda_src, functions=['linear_swish_forward'], extra_cuda_cflags=['-O3'], extra_ldflags=['-lcublas'], verbose=False)\nclass ModelNew(nn.Module):\n def __init__(self,in_features,out_features,scaling_factor):\n super(ModelNew,self).__init__(); self.matmul=nn.Linear(in_features,out_features); self.scaling_factor=scaling_factor\n def forward(self,x): return _ext.linear_swish_forward(x.contiguous(), self.matmul.weight, self.matmul.bias, float(self.scaling_factor))\n" }
result ← run_correctness (ok)
okrun_correctness run_correctness PASSED: (5 / 5) trials all matched the reference. Numerical precision: max_abs_err=4.77e-07 mean_abs_err=2.06e-09 max_rel_err=3.50e-07
turn 98.8s turn · 8.8s LLM · 0.0s tools · FINAL
call → submit_kernel
callsubmit_kernel { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n_cpp_src = r'''\n#include <torch/extension.h>\ntorch::Tensor linear_swish_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double scale_d);\n'''\n\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <cuda_runtime.h>\n#include <cublas_v2.h>\n#include <mutex>\n\nstatic cublasHandle_t get_handle(){\n static cublasHandle_t h=nullptr;\n static std::once_flag f;\n std::call_once(f, [](){\n cublasCreate(&h);\n cublasSetMathMode(h, CUBLAS_DEFAULT_MATH);\n });\n return h;\n}\n\n__device__ __forceinline__ float swish_scale(float v, float scale){\n return v * (1.0f / (1.0f + __expf(-v))) * scale;\n}\n\n__global__ void bias_swish_scale_vec4(float* __restrict__ y,\n const float* __restrict__ bias,\n int M, int N4, float scale){\n int col4 = blockIdx.x * blockDim.x + threadIdx.x;\n int row = blockIdx.y;\n if(row < M && col4 < N4){\n int idx4 = row * N4 + col4;\n float4 yy = reinterpret_cast<float4*>(y)[idx4];\n float4 bb = reinterpret_cast<const float4*>(bias)[col4];\n yy.x = swish_scale(yy.x + bb.x, scale);\n yy.y = swish_scale(yy.y + bb.y, scale);\n yy.z = swish_scale(yy.z + bb.z, scale);\n yy.w = swish_scale(yy.w + bb.w, scale);\n reinterpret_cast<float4*>(y)[idx4] = yy;\n }\n}\n\n__global__ void bias_swish_scale_scalar(float* __restrict__ y,\n const float* __restrict__ bias,\n int total, int N, float scale){\n int i = blockIdx.x * blockDim.x + threadIdx.x;\n if(i < total){\n float v = y[i] + bias[i % N];\n y[i] = swish_scale(v, scale);\n }\n}\n\ntorch::Tensor linear_swish_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double scale_d){\n int64_t M64 = x.size(0), K64 = x.size(1), N64 = weight.size(0);\n auto y = torch::empty({M64, N64}, x.options());\n int M = (int)M64, N = (int)N64, K = (int)K64;\n\n float alpha = 1.0f, beta = 0.0f;\n cublasHandle_t h = get_handle();\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n cublasSetStream(h, stream);\n\n cublasStatus_t st = cublasSgemm(h, CUBLAS_OP_T, CUBLAS_OP_N,\n N, M, K,\n &alpha,\n weight.data_ptr<float>(), K,\n x.data_ptr<float>(), K,\n &beta,\n y.data_ptr<float>(), N);\n TORCH_CHECK(st == CUBLAS_STATUS_SUCCESS, \"cublasSgemm failed\");\n\n float scale = (float)scale_d;\n if((N & 3) == 0){\n int N4 = N >> 2;\n bias_swish_scale_vec4<<<dim3((N4 + 255) / 256, M), dim3(256), 0, stream>>>(\n y.data_ptr<float>(), bias.data_ptr<float>(), M, N4, scale);\n } else {\n int total = M * N;\n bias_swish_scale_scalar<<<(total + 255) / 256, 256, 0, stream>>>(\n y.data_ptr<float>(), bias.data_ptr<float>(), total, N, scale);\n }\n C10_CUDA_KERNEL_LAUNCH_CHECK();\n return y;\n}\n'''\n\n_ext = load_inline(name='linear_swish_ext_final',\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=['linear_swish_forward'],\n extra_cuda_cflags=['-O3'],\n extra_ldflags=['-lcublas'],\n verbose=False)\n\nclass ModelNew(nn.Module):\n def __init__(self, in_features, out_features, scaling_factor):\n super(ModelNew, self).__init__()\n self.matmul = nn.Linear(in_features, out_features)\n self.scaling_factor = scaling_factor\n\n def forward(self, x):\n return _ext.linear_swish_forward(x.contiguous(), self.matmul.weight, self.matmul.bias, float(self.scaling_factor))\n" }
result ← submit_kernel (ok)
oksubmit_kernel submit_kernel PASSED: (5 / 5) correctness trials all passed. Kernel runtime: 5.28 μs Runtime stats: mean=5.28μs median=?μs std=0.01μs Numerical precision: max_abs_err=4.77e-07 mean_abs_err=2.06e-09 max_rel_err=3.50e-07 Memory: 8257.25 MB peak (ref: 8289.25 MB, ratio: 0.9961x) Kernel launches: 1 (ref: 8, fusion ratio: 8.0) Energy: 464.6 mJ/run (ref: 696.62 mJ, ratio: 1.4994x) SOL score: 0.9736
final submitted kernel (108 lines, 3,924 chars) — full source, untruncated
import torch
import torch.nn as nn
from torch.utils.cpp_extension import load_inline

_cpp_src = r'''
#include <torch/extension.h>
torch::Tensor linear_swish_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double scale_d);
'''

_cuda_src = r'''
#include <torch/extension.h>
#include <ATen/cuda/CUDAContext.h>
#include <cuda_runtime.h>
#include <cublas_v2.h>
#include <mutex>

static cublasHandle_t get_handle(){
    static cublasHandle_t h=nullptr;
    static std::once_flag f;
    std::call_once(f, [](){
        cublasCreate(&h);
        cublasSetMathMode(h, CUBLAS_DEFAULT_MATH);
    });
    return h;
}

__device__ __forceinline__ float swish_scale(float v, float scale){
    return v * (1.0f / (1.0f + __expf(-v))) * scale;
}

__global__ void bias_swish_scale_vec4(float* __restrict__ y,
                                      const float* __restrict__ bias,
                                      int M, int N4, float scale){
    int col4 = blockIdx.x * blockDim.x + threadIdx.x;
    int row = blockIdx.y;
    if(row < M && col4 < N4){
        int idx4 = row * N4 + col4;
        float4 yy = reinterpret_cast<float4*>(y)[idx4];
        float4 bb = reinterpret_cast<const float4*>(bias)[col4];
        yy.x = swish_scale(yy.x + bb.x, scale);
        yy.y = swish_scale(yy.y + bb.y, scale);
        yy.z = swish_scale(yy.z + bb.z, scale);
        yy.w = swish_scale(yy.w + bb.w, scale);
        reinterpret_cast<float4*>(y)[idx4] = yy;
    }
}

__global__ void bias_swish_scale_scalar(float* __restrict__ y,
                                        const float* __restrict__ bias,
                                        int total, int N, float scale){
    int i = blockIdx.x * blockDim.x + threadIdx.x;
    if(i < total){
        float v = y[i] + bias[i % N];
        y[i] = swish_scale(v, scale);
    }
}

torch::Tensor linear_swish_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double scale_d){
    int64_t M64 = x.size(0), K64 = x.size(1), N64 = weight.size(0);
    auto y = torch::empty({M64, N64}, x.options());
    int M = (int)M64, N = (int)N64, K = (int)K64;

    float alpha = 1.0f, beta = 0.0f;
    cublasHandle_t h = get_handle();
    cudaStream_t stream = at::cuda::getCurrentCUDAStream();
    cublasSetStream(h, stream);

    cublasStatus_t st = cublasSgemm(h, CUBLAS_OP_T, CUBLAS_OP_N,
                                    N, M, K,
                                    &alpha,
                                    weight.data_ptr<float>(), K,
                                    x.data_ptr<float>(), K,
                                    &beta,
                                    y.data_ptr<float>(), N);
    TORCH_CHECK(st == CUBLAS_STATUS_SUCCESS, "cublasSgemm failed");

    float scale = (float)scale_d;
    if((N & 3) == 0){
        int N4 = N >> 2;
        bias_swish_scale_vec4<<<dim3((N4 + 255) / 256, M), dim3(256), 0, stream>>>(
            y.data_ptr<float>(), bias.data_ptr<float>(), M, N4, scale);
    } else {
        int total = M * N;
        bias_swish_scale_scalar<<<(total + 255) / 256, 256, 0, stream>>>(
            y.data_ptr<float>(), bias.data_ptr<float>(), total, N, scale);
    }
    C10_CUDA_KERNEL_LAUNCH_CHECK();
    return y;
}
'''

_ext = load_inline(name='linear_swish_ext_final',
                   cpp_sources=_cpp_src,
                   cuda_sources=_cuda_src,
                   functions=['linear_swish_forward'],
                   extra_cuda_cflags=['-O3'],
                   extra_ldflags=['-lcublas'],
                   verbose=False)

class ModelNew(nn.Module):
    def __init__(self, in_features, out_features, scaling_factor):
        super(ModelNew, self).__init__()
        self.matmul = nn.Linear(in_features, out_features)
        self.scaling_factor = scaling_factor

    def forward(self, x):
        return _ext.linear_swish_forward(x.contiguous(), self.matmul.weight, self.matmul.bias, float(self.scaling_factor))