Kimi-K2.6 · popcorn · l12_default_gpt
correct 30_broadcast_masked_from_row0.py
model
Kimi-K2.6
turns / max
7 / 10
tool calls
7
tokens (total)
0
wall clock
—
truncated
no
backend
cuda fp32
variant
popcorn
runtime
0.01 μs
ref runtime
0.01 μs
speedup
1.18x
started
2026-05-02T19:34:32Z
timingkernelbench.timing
kernel runtime
0.01 μs
ref runtime
0.01 μs
speedup
1.18x
kernel mean / median / std
0.01 / — / 1.62e-04 μs
ref mean / median / std
0.01 / — / 6.86e-04 μs
numerical precisioneval_kernel_against_ref
max abs error
0.00
mean abs error
0.00
max rel error
0.00
mean rel error
0.00
gpu memoryextended_metrics.measure_memory
kernel peak
33.01 MB
ref peak
33.01 MB
kernel / ref
1.00x
kernel launches / fusiontorch.profiler
kernel launches
2
ref launches
11
fusion ratio (ref / kernel)
5.50x
total cuda time
54 μs
SOL (speed-of-light)nsight_hardware_counters
SOL score (0–1)
6.000e-04
dram util %
0.1%
compute util %
0.0%
bottleneck
unknown
dominant pipe
None
arithmetic intensity
—
ridge point
20.00
roofline / occupancynsight_hardware_counters
dram bandwidth
2.00 GB/s
dram util %
0.1%
fp32 tflops
—
fp32 util %
—
fp16 tflops
—
occupancy %
10.8%
bottleneck
unknown
dominant pipe %
—
arithmetic intensity
—
ridge point
20.00
L1 hit %
—
L2 hit %
99.2%
ld sectors / req
4.36
st sectors / req
—
regs / thread
16
smem / block
1024 B
block size
256
peak bw
3350.00 GB/s
peak fp32 tflops
67.00
peak fp16 tflops
1979.00
warp stalls (top 5)nsight
long_scoreboard
1612.3%
short_scoreboard
860.2%
reference PyTorch source (the prompt the agent sees)
"""
Simulated broadcast of row 0 into masked columns for all rows: where mask[j] is True,
every row matches x[0, j]; elsewhere keep x[b, j].
"""

import torch
import torch.nn as nn

from kernelbench.distributed_collectives import default_device

B = 18
D = 44

# Fixed mask (not all True, not all False)
_MASK = torch.tensor(
    [1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1],
    dtype=torch.bool,
)


class Model(nn.Module):
    def __init__(self):
        super().__init__()
        self.register_buffer("row_mask", _MASK.clone(), persistent=False)

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        m = self.row_mask.to(device=x.device).view(1, D).expand(B, D)
        row0 = x[0:1].expand(B, D)
        return torch.where(m, row0, x)


def get_inputs():
    dev = default_device()
    return [torch.randn(popcorn_pri.jitter_int(B), D, device=dev)]


def get_init_inputs():
    return []
turn 0 · 1 tool call(s) · 60.9s turn · 60.9s LLM · 28,636 chars (click to expand)
turn 060.9s turn · 60.9s LLM · 0.0s tools
reasoning
We need to write a custom CUDA kernel that replaces the forward computation of the given PyTorch model. Reference model: - registers a buffer `row_mask` of shape (D,) where D=44, with boolean mask values. - forward(x): `m = self.row_mask.to(device=x.device).view(1, D).expand(B, D)`, `row0 = x[0:1].expand(B, D)`, `return torch.where(m, row0, x)`. B=18, D=44. This is a tiny tensor, 18*44. The operation is essentially: for each column j, if mask[j] is True, output[b,j] = x[0,j] for all rows b; else output[b,j] = x[b,j]. This is a very small operation; a custom CUDA kernel might not be much faster than PyTorch, but we can try. However, the overhead of kernel launch may dominate. But we can try to make it efficient: use a fused kernel reading x and mask and writing output. Since B=18, D=44, we can launch one thread per element or perhaps one warp per row. The operation is straightforward. We need to produce a Python module that defines ModelNew, using torch.utils.cpp_extension.load_inline to compile and bind CUDA. The GPU specs may be useful, but the problem is heavily memory-bound for such a small tensor. Still, we can try to optimize. But wait: The evaluation likely times the forward pass. For such tiny tensors, the reference PyTorch operation is executed on GPU and may be memory-bound but with very small data. PyTorch's torch.where may launch a kernel that reads mask (bool), row0 (which is just x[0] broadcasted), and x. Since row0 is broadcasted, PyTorch might materialize the expanded tensors or use indexing in the kernel. In any case, a custom kernel that fuses everything into a single read of x and mask and writes output could be faster. However, there might be a catch: the mask is a CPU tensor registered as a buffer but not necessarily on GPU. In the reference, `self.row_mask.to(device=x.device)` copies it to GPU each forward call. In ModelNew, we could pre-move the mask to GPU in `__init__` if we know the device? But the constructor doesn't get device. However, `self.row_mask` is a buffer. We can register it as a buffer and then in forward, if it's not on the same device as x, move it. But that would be similar to reference. Actually, looking at the reference: `self.register_buffer("row_mask", _MASK.clone(), persistent=False)`. `_MASK` is a CPU bool tensor. So `self.row_mask` is a CPU buffer. In forward, it does `.to(device=x.device)`. That means each forward call copies the mask to GPU. Since D=44, it's tiny, but still a cudaMemcpy each call. In ModelNew, we could avoid that by caching the mask on GPU. But we need to know the device. We can do: if `self.row_mask.device != x.device`, move it and cache. But the buffer is registered on CPU. We can just store it as a CPU tensor and in forward, if not on x.device, do `.to(x.device)` but perhaps assign to a local variable. That's similar to reference. But the reference uses `.view(1, D).expand(B, D)` which are cheap views. Then `torch.where` reads three tensors: m (bool), row0 (float, broadcasted from x[0:1]), x (float). Broadcasting row0 means reading x[0] repeatedly. The kernel likely does: result = condition ? row0 : x. But because row0 is broadcasted, the kernel likely reads x[0] per thread or uses a shared broadcast mechanism. A custom kernel can do: each thread computes index i = blockIdx.x * blockDim.x + threadIdx.x. If i < B*D: b = i / D, d = i % D. If mask[d] is true, out[i] = x[d] (since x[0,d] is just the first row). Wait, x is shape (B,D). So x[0,d] is at index d. Else out[i] = x[b*D + d]. We can pass x (float*), mask (bool*), out (float*). Since B and D are small compile-time constants? They are fixed at module level: B=18, D=44. We can embed them in the kernel as constants or pass as arguments. Passing as arguments is fine. But note: the forward signature is `forward(self, x: torch.Tensor) -> torch.Tensor`. x has shape (B,D) presumably. We should check shape but trust it. We can also consider vectorized loads/stores. Since D=44, not a multiple of 4 (in floats), but B*D=792. That's very small. We can launch 256 threads in one block, or multiple blocks. 256 threads is enough to cover 792 elements with 4 blocks of 256? Actually one block of 1024 threads would cover it. But we might want small blocks for occupancy, but occupancy doesn't matter for such tiny launch. Overhead is dominated by kernel launch time. So minimizing kernel launch overhead is key. But we can't avoid it. Maybe we can use a single thread to process the whole thing? That would be terrible. A single block with 256 threads is fine. Let's use a simple kernel. Wait, perhaps there is a trick: The mask is static (same each call). We can precompute a float mask (0/1) or an index list. But since it's tiny, it doesn't matter. Another thought: Can we do it without a custom kernel but using torch.where with precomputed mask on GPU? The reference is doing `.to(device=x.device)` each time. If we cache the GPU mask in ModelNew, we can avoid the HtoD copy. Since `ModelNew.__init__` is called once, we can register the buffer but also maybe store a GPU version? But the device is unknown at init time. However, in `forward`, we can cache it: `if not hasattr(self, '_gpu_mask') or self._gpu_mask.device != x.device: self._gpu_mask = self.row_mask.to(x.device)`. That avoids copying the mask each call. That alone could give a speedup! But the main task is to replace with a custom CUDA kernel. We can combine both: a custom kernel + cached mask. But we must ensure correctness. Also we need to compile the kernel. Since it's tiny, writing a generic elementwise kernel is easy. Let's draft the CUDA code: ```cpp #include <torch/extension.h> #include <cuda_runtime.h> __global__ void masked_broadcast_kernel( const float* __restrict__ x, const bool* __restrict__ mask, float* __restrict__ out, int B, int D) { int idx = blockIdx.x * blockDim.x + threadIdx.x; int total = B * D; if (idx < total) { int d = idx % D; if (mask[d]) { out[idx] = x[d]; // x[0, d] } else { out[idx] = x[idx]; } } } torch::Tensor masked_broadcast_cuda(torch::Tensor x, torch::Tensor mask) { int B = x.size(0); int D = x.size(1); auto out = torch::empty_like(x); int total = B * D; const int threads = 256; const int blocks = (total + threads - 1) / threads; masked_broadcast_kernel<<<blocks, threads>>>( x.data_ptr<float>(), mask.data_ptr<bool>(), out.data_ptr<float>(), B, D ); return out; } ``` Then load_inline with functions=['masked_broadcast_cuda']. ModelNew: ```python class ModelNew(nn.Module): def __init__(self): super().__init__() self.register_buffer("row_mask", _MASK.clone(), persistent=False) def forward(self, x: torch.Tensor) -> torch.Tensor: if not hasattr(self, '_row_mask_gpu') or self._row_mask_gpu.device != x.device: self._row_mask_gpu = self.row_mask.to(device=x.device) return masked_broadcast_cuda(x, self._row_mask_gpu) ``` Wait: In the reference, `row0 = x[0:1].expand(B, D)`. So row0 is the first row. In our kernel, we used `x[d]` for mask true. That matches x[0,d]. Good. Edge case: What if x is not contiguous? `x.data_ptr<float>()` works for contiguous tensors? If x is not contiguous, `data_ptr` still gives the base pointer, but indexing `x[idx]` directly is wrong. However, since we get inputs from `get_inputs()` which uses `torch.randn(B, D, device=dev)`, it's contiguous. But to be safe, we could make x contiguous or use `x.stride(0)` and `x.stride(1)`. But for simplicity, we can call `x = x.contiguous()` before passing to kernel. In PyTorch, `.contiguous()` is cheap if already contiguous. We can do: ```python x_contig = x.contiguous() out = masked_broadcast_cuda(x_contig, self._row_mask_gpu) ``` But out will be contiguous, same as reference output which is contiguous. That's fine. However, there is a nuance: The reference `torch.where(m, row0, x)` handles non-contiguous tensors? It does, but inputs are contiguous. Let's also consider using `__restrict__` and ensuring the kernel is inlined. Also, we could unroll loops or vectorize, but with 792 elements it's overkill. But we need to think about performance relative to PyTorch reference. The reference does: 1. `.to(device=x.device)`: memcpy HtoD of 44 bytes. 2. `.view(1,D).expand(B,D)`: just metadata. 3. `x[0:1].expand(B,D)`: metadata. 4. `torch.where(m, row0, x)`: kernel launch reading mask (bool), x, row0 (broadcasted). Since row0 is broadcasted from x[0], the kernel might read x[0] via a separate path or read x directly. Our custom kernel: 1. Cached mask on GPU: no HtoD copy after first call. But if the evaluation runs many forward passes, this saves time. 2. Single kernel launch doing a single read of mask (bool), read of x (float), write of out (float). When mask[d] is true, we read x[d] (already in cache). When false, we read x[idx]. So overall memory traffic: read x (B*D floats), read mask (D bools), write out (B*D floats). The reference `torch.where` reads m (B*D bools? or broadcasted), row0 (B*D floats? or broadcasted), x (B*D floats), writes out (B*D floats). The mask broadcast might be handled by reading mask[D] repeatedly or materializing. But row0 broadcast means reading x[0,D] repeatedly. So reference might have more reads: it reads x twice? Actually `torch.where` reads three tensors: condition, self, other. Condition is m (broadcasted mask). Self is row0 (broadcasted x[0]). Other is x. So it reads x (for other), x[0] (for self), mask (for condition). So total reads: B*D floats from x, B*D floats from row0 (which is x[0] broadcasted), B*D bools from m. Writes: B*D floats. Our kernel reads x once (B*D floats), mask once (D bools), writes out (B*D floats). So we reduce memory traffic by ~1/3. For a memory-bound kernel, this should give a speedup. But is it compute-bound? No. So reducing reads is good. We can further optimize by not reading mask at all if we bake it into the kernel? Since mask is static, we could pass it as a bitmask constant. But D=44, it's not too hard to pass as a uint64_t bitmask: each bit corresponds to a column. Then the kernel reads a `uint64_t mask_bits` and checks `(mask_bits >> d) & 1`. That eliminates reading mask array from global memory. Since D=44 fits in 64 bits, this is perfect. Let's do that! In `forward`, we can compute a 64-bit integer from the bool mask: ```python mask_cpu = self.row_mask # shape (D,) # Pack into uint64 mask_bits = 0 for i, val in enumerate(mask_cpu.tolist()): if val: mask_bits |= (1 << i) ``` Then pass `mask_bits` as a scalar (uint64_t) to the kernel. The kernel signature becomes: ```cpp __global__ void masked_broadcast_kernel(const float* __restrict__ x, float* __restrict__ out, uint64_t mask_bits, int B, int D) ``` In the kernel: ```cpp int idx = blockIdx.x * blockDim.x + threadIdx.x; int total = B * D; if (idx < total) { int d = idx % D; if ((mask_bits >> d) & 1ULL) { out[idx] = x[d]; } else { out[idx] = x[idx]; } } ``` This eliminates the mask tensor entirely, no memory read for mask. Very nice. But we need to be careful: D=44, shifting by d is fine. `mask_bits` passed by value to the kernel. In the host wrapper: ```cpp torch::Tensor masked_broadcast_cuda(torch::Tensor x, int64_t mask_bits) { int B = x.size(0); int D = x.size(1); auto out = torch::empty_like(x); int total = B * D; const int threads = 256; const int blocks = (total + threads - 1) / threads; masked_broadcast_kernel<<<blocks, threads>>>( x.data_ptr<float>(), out.data_ptr<float>(), static_cast<uint64_t>(mask_bits), B, D ); return out; } ``` Wait, can we pass `int64_t` from Python? Yes, via pybind11, Python int converts to int64_t. The wrapper takes `int64_t mask_bits`. In kernel, we cast to `uint64_t`. Or we can use unsigned long long. Let's use `unsigned long long` for kernel param and `int64_t` for wrapper argument. But pybind11 may map Python int to `int64_t` automatically. Or `unsigned long long`. Let's use `int64_t` in C++ wrapper and cast. However, when launching the kernel, we need to ensure the type matches. Let's use `uint64_t mask_bits` in the wrapper, but pybind might map Python int to uint64_t? Actually, pybind11 handles `unsigned long long`. But to be safe, we can pass as `int64_t` and cast. Let's just use `int64_t mask_bits` in the wrapper and then pass `(uint64_t)mask_bits` to the kernel. ModelNew: ```python class ModelNew(nn.Module): def __init__(self): super().__init__() self.register_buffer("row_mask", _MASK.clone(), persistent=False) # Precompute bitmask on CPU mask_bits = 0 for i, val in enumerate(self.row_mask.tolist()): if val: mask_bits |= (1 << i) self.mask_bits = mask_bits def forward(self, x: torch.Tensor) -> torch.Tensor: x = x.contiguous() return masked_broadcast_cuda(x, self.mask_bits) ``` This is very efficient. But will it be numerically equivalent? Yes, it's the same operation. Wait, what if D > 63? Here D=44, fine. But we shouldn't hardcode D? The problem says B and D are fixed module-level constants. We can rely on D=44. But to be safe, we could pass mask as a tensor and support any D. However, the bitmask approach is neat. But to be robust, maybe we should support any D up to 64. We can assert D <= 64 in the wrapper or just trust the problem. Alternatively, we could just pass the bool mask as a tensor and read it. Simpler, less risk of type mismatch. But the bitmask saves a memory read. For such a small kernel, the mask read is negligible? Actually, reading D bools (44 bytes) from global memory is tiny. But it's still a memory instruction. The real win might be caching the mask on GPU to avoid HtoD copy. But the bitmask also avoids that. The HtoD copy of 44 bytes is extremely fast but has overhead. However, here's a catch: `torch.utils.cpp_extension.load_inline` compiles at module load time. If we pack the bitmask in Python, we don't need to pass a GPU tensor to the kernel. This avoids any synchronization. Good. But we need to be careful: The reference mask is defined as `_MASK = torch.tensor([...], dtype=torch.bool)`. In ModelNew.__init__, `self.row_mask` is a copy of that CPU tensor. We compute `self.mask_bits` from it. This is fine. But what if `self.row_mask` is changed? It won't be. Let's think about whether the kernel should handle non-contiguous input. We call `x.contiguous()`. This ensures `x.data_ptr<float>()` and `x.stride(0)==D, x.stride(1)==1`. The output `out = torch.empty_like(x)` will also be contiguous. So it's fine. One more optimization: Since B*D=792, we can use a single block with, say, 1024 threads. Or 256 threads in 4 blocks. Actually, one block of 1024 threads covers 792, leaving some idle threads. The overhead of multiple blocks might be slightly higher due to hardware scheduling, but negligible. However, using a single block means only one SM is used. For such tiny data, that doesn't matter; using multiple SMs would have higher launch overhead. Actually, one thread block of 1024 threads may saturate one warp? No, 1024 threads = 32 warps. The GPU can run many warps. But for 792 elements, 1024 threads means 24.75 warps active, 7.25 warps idle in the last wave. That's fine. Using 256 threads in 4 blocks = 4 blocks, each with 8 warps. The GPU can run them concurrently on different SMs. But the memory bandwidth needed is tiny, so a single SM can handle it. Using multiple blocks might actually be slightly slower due to block dispatch overhead. But it's negligible. However, for max occupancy and to minimize launch overhead, we can just compute with a single block of 256 threads. Wait, a CUDA kernel launch always has overhead, but the number of blocks doesn't add much. Let's use `(total + threads - 1) / threads` blocks. That's standard. Could we further optimize by using vectorized loads/stores? B*D=792. If we process 4 floats per thread, we need 198 threads. We could do: ```cpp __global__ void kernel(...) { int idx = blockIdx.x * blockDim.x + threadIdx.x; int total = B * D; // process 4 elements per thread for (int i = idx; i < total; i += blockDim.x * gridDim.x) { ... } } ``` But with a single block, it's fine. Actually, `blockDim.x * gridDim.x` is the total number of threads. If we use a grid-stride loop, we can handle arbitrary sizes with a fixed block/grid configuration. For 792 elements, a grid-stride loop is unnecessary. Simple per-thread assignment is fine. But we might consider a single warp (32 threads) could handle the whole thing with a loop. However, the kernel launch overhead is the same. Wait, maybe we should do the computation on CPU? The data is tiny. But the inputs and outputs are on GPU. Moving to CPU would be slower. Another thing: The reference uses `torch.where`, which might be fused into a single kernel with broadcasts handled internally. The custom kernel should be faster because we avoid reading x twice (once as `x`, once as `row0`). Also we avoid reading mask from global memory by packing it into a scalar. But there is a potential issue: `x[d]` in the kernel for all threads reading the same address may cause bank conflicts or serialization? In global memory, it's a broadcast, which is efficient (cached in L1). For the first row, all threads read from the same 44 floats. So it's fine. One more nuance: The input x might be fp32 or fp16? The reference returns fp32 because x is fp32. The problem says "at fp32 precision". So x is float. We'll assume float. Let's write the code. The Python file must define `ModelNew`. We need to embed the CUDA source. Use `torch.utils.cpp_extension.load_inline`. ```python import torch import torch.nn as nn from torch.utils.cpp_extension import load_inline cuda_source = ''' #include <torch/extension.h> #include <cuda_runtime.h> __global__ void masked_broadcast_kernel(const float* __restrict__ x, float* __restrict__ out, unsigned long long mask_bits, int B, int D) { int idx = blockIdx.x * blockDim.x + threadIdx.x; int total = B * D; if (idx < total) { int d = idx % D; if ((mask_bits >> d) & 1ULL) { out[idx] = x[d]; } else { out[idx] = x[idx]; } } } torch::Tensor masked_broadcast_cuda(torch::Tensor x, unsigned long long mask_bits) { int B = x.size(0); int D = x.size(1); auto out = torch::empty_like(x); int total = B * D; const int threads = 256; const int blocks = (total + threads - 1) / threads; masked_broadcast_kernel<<<blocks, threads>>>(x.data_ptr<float>(), out.data_ptr<float>(), mask_bits, B, D); return out; } ''' cpp_source = '' # not needed # load inline masked_broadcast_cuda = load_inline( name="masked_broadcast_cuda", cpp_sources='', cuda_sources=cuda_source, functions=['masked_broadcast_cuda'], extra_cuda_cflags=['-O3'], verbose=False, ) ``` Wait, `load_inline` signature: `torch.utils.cpp_extension.load_inline(name, cpp_sources, cuda_sources, functions, extra_cflags=None, extra_cuda_cflags=None, extra_ldflags=None, extra_include_paths=None, build_directory=None, verbose=False)`. Yes. But we need to be careful: including `<torch/extension.h>` is fine. We don't need pybind module. Now ModelNew: ```python B = 18 D = 44 _MASK = torch.tensor([...], dtype=torch.bool) class ModelNew(nn.Module): def __init__(self): super().__init__() self.register_buffer("row_mask", _MASK.clone(), persistent=False) mask_bits = 0 for i, val in enumerate(self.row_mask.tolist()): if val: mask_bits |= (1 << i) self.mask_bits = mask_bits def forward(self, x: torch.Tensor) -> torch.Tensor: x = x.contiguous() return masked_broadcast_cuda(x, self.mask_bits) ``` This looks good. But let's think about types: `self.mask_bits` is a Python int. When passed to `masked_broadcast_cuda`, pybind11 will convert it to `unsigned long long`. In the wrapper, we take `unsigned long long mask_bits`. That's fine. But if D=44, `1 << i` for i up to 43 fits in Python int. No problem. Wait, `1 << i` where i=43 is 8.8e12, well within Python int. Good. Should we worry about sign extension? No, because we treat it as unsigned. Potential issue: The CUDA compiler might warn about shifting by >= width if D were 64. But D=44. Fine. Let's also think about whether `x` could require grad. The reference is inside a nn.Module forward. The output should preserve gradient? Actually, the reference uses torch.where which preserves gradients. Our custom CUDA kernel: if x requires grad, the output of a custom op won't have a registered autograd function, so it will break gradient flow. But the problem says "Replace the forward computation". Does the evaluation check gradients? Usually, these tasks only check forward output correctness. The problem statement: "Produce numerically equivalent outputs at fp32 precision." It doesn't mention backward. So we don't need to support autograd. However, to be safe, maybe we should wrap it in a `torch.autograd.Function`? No, that's overkill and might add overhead. The reference model is used for forward inference. The get_inputs doesn't set requires_grad. So we can ignore gradients. But does the evaluation test backward? The prompt says "Replace the forward computation". Usually they only test forward. If they test backward, they'd mention it. So fine. Now, let's compile and test. We need to write the code as a string. Then call compile_kernel. Since we are in a chat, we need to call the tool. Let's compose the kernel code string exactly.
call → compile_kernel
callcompile_kernel { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n# Fixed constants from the reference\nB = 18\nD = 44\n_MASK = torch.tensor(\n [1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1],\n dtype=torch.bool,\n)\n\ncuda_source = \"\"\"\n#include <torch/extension.h>\n#include <cuda_runtime.h>\n\n__global__ void masked_broadcast_kernel(\n const float* __restrict__ x,\n float* __restrict__ out,\n unsigned long long mask_bits,\n int B,\n int D)\n{\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n int total = B * D;\n if (idx < total) {\n int d = idx % D;\n if ((mask_bits >> d) & 1ULL) {\n out[idx] = x[d];\n } else {\n out[idx] = x[idx];\n }\n }\n}\n\ntorch::Tensor masked_broadcast_cuda(torch::Tensor x, unsigned long long mask_bits) {\n int B = x.size(0);\n int D = x.size(1);\n auto out = torch::empty_like(x);\n int total = B * D;\n const int threads = 256;\n const int blocks = (total + threads - 1) / threads;\n masked_broadcast_kernel<<<blocks, threads>>>(\n x.data_ptr<float>(),\n out.data_ptr<float>(),\n mask_bits,\n B,\n D\n );\n return out;\n}\n\"\"\"\n\nmasked_broadcast_cuda = load_inline(\n name=\"masked_broadcast_cuda\",\n cpp_sources=\"\",\n cuda_sources=cuda_source,\n functions=[\"masked_broadcast_cuda\"],\n extra_cuda_cflags=[\"-O3\"],\n verbose=False,\n)\n\nclass ModelNew(nn.Module):\n def __init__(self):\n super().__init__()\n self.register_buffer(\"row_mask\", _MASK.clone(), persistent=False)\n mask_bits = 0\n for i, val in enumerate(self.row_mask.tolist()):\n if val:\n mask_bits |= (1 << i)\n self.mask_bits = mask_bits\n\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n x = x.contiguous()\n return masked_broadcast_cuda(x, self.mask_bits)\n" }
result ← compile_kernel (fail)
failcompile_kernel compile_kernel FAILED: RuntimeError. RuntimeError: Error building extension 'masked_broadcast_cuda': [1/3] /opt/conda/bin/x86_64-conda-linux-gnu-c++ -MMD -MF main.o.d -DTORCH_EXTENSION_NAME=masked_broadcast_cuda -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/popcorn/Kimi-K2.6/level_1_problem_30_cache/k_fb392af4d46c/masked_broadcast_cuda/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=masked_broadcast_cuda -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/popcorn/Kimi-K2.6/level_1_problem_30_cache/k_fb392af4d46c/masked_broadcast_cuda/main.cpp -o main.o /scratch/tejas/PopcornBench/runs/l12_default/popcorn/Kimi-K2.6/level_1_problem_30_cache/k_fb392af4d46c/masked_broadcast_cuda/main.cpp: In function 'void pybind11_init_masked_broadcast_cuda(pybind11::module_&)': /scratch/tejas/PopcornBench/runs/l12_default/popcorn/Kimi-K2.6/level_1_problem_30_cache/k_fb392af4d46c/masked_broadcast_cuda/main.cpp:4:60: error: 'masked_broadcast_cuda' was not declared in this scope; did you mean 'PyInit_masked_broadcast_cuda'? 4 | m.def("masked_broadcast_cuda", torch::wrap_pybind_function(masked_broadcast_cuda), "masked_broadcast_cuda"); | ^~~~~~~~~~~~~~~~~~~~~ | PyInit_masked_broadcast_cuda [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=masked_broadcast_cuda -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/popcorn/Kimi-K2.6/level_1_problem_30_cache/k_fb392af4d46c/masked_broadcast_cuda/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 14.3s turn · 4.3s LLM · 0.0s tools
reasoning
The error is because `load_inline` generates a pybind11 module automatically, and expects the functions to be declared in the C++ source. But since we only provided cuda_sources and empty cpp_sources, the function declaration isn't visible to the auto-generated binding. The correct way is to provide a `cpp_sources` with the function declaration, and put the implementation in `cuda_sources`. Let me fix this.
call → compile_kernel
callcompile_kernel { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n# Fixed constants from the reference\nB = 18\nD = 44\n_MASK = torch.tensor(\n [1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1],\n dtype=torch.bool,\n)\n\ncpp_sources = \"\"\"\ntorch::Tensor masked_broadcast_cuda(torch::Tensor x, unsigned long long mask_bits);\n\"\"\"\n\ncuda_source = \"\"\"\n#include <torch/extension.h>\n#include <cuda_runtime.h>\n\n__global__ void masked_broadcast_kernel(\n const float* __restrict__ x,\n float* __restrict__ out,\n unsigned long long mask_bits,\n int B,\n int D)\n{\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n int total = B * D;\n if (idx < total) {\n int d = idx % D;\n if ((mask_bits >> d) & 1ULL) {\n out[idx] = x[d];\n } else {\n out[idx] = x[idx];\n }\n }\n}\n\ntorch::Tensor masked_broadcast_cuda(torch::Tensor x, unsigned long long mask_bits) {\n int B = x.size(0);\n int D = x.size(1);\n auto out = torch::empty_like(x);\n int total = B * D;\n const int threads = 256;\n const int blocks = (total + threads - 1) / threads;\n masked_broadcast_kernel<<<blocks, threads>>>(\n x.data_ptr<float>(),\n out.data_ptr<float>(),\n mask_bits,\n B,\n D\n );\n return out;\n}\n\"\"\"\n\nmasked_broadcast_cuda = load_inline(\n name=\"masked_broadcast_cuda\",\n cpp_sources=cpp_sources,\n cuda_sources=cuda_source,\n functions=[\"masked_broadcast_cuda\"],\n extra_cuda_cflags=[\"-O3\"],\n verbose=False,\n)\n\nclass ModelNew(nn.Module):\n def __init__(self):\n super().__init__()\n self.register_buffer(\"row_mask\", _MASK.clone(), persistent=False)\n mask_bits = 0\n for i, val in enumerate(self.row_mask.tolist()):\n if val:\n mask_bits |= (1 << i)\n self.mask_bits = mask_bits\n\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n x = x.contiguous()\n return masked_broadcast_cuda(x, self.mask_bits)\n" }
result ← compile_kernel (ok)
okcompile_kernel compile_kernel PASSED: kernel compiled without errors.
turn 28.7s turn · 8.7s LLM · 0.0s tools
reasoning
Great, it compiled. Now let's run correctness.
call → run_correctness
callrun_correctness { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n# Fixed constants from the reference\nB = 18\nD = 44\n_MASK = torch.tensor(\n [1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1],\n dtype=torch.bool,\n)\n\ncpp_sources = \"\"\"\ntorch::Tensor masked_broadcast_cuda(torch::Tensor x, unsigned long long mask_bits);\n\"\"\"\n\ncuda_source = \"\"\"\n#include <torch/extension.h>\n#include <cuda_runtime.h>\n\n__global__ void masked_broadcast_kernel(\n const float* __restrict__ x,\n float* __restrict__ out,\n unsigned long long mask_bits,\n int B,\n int D)\n{\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n int total = B * D;\n if (idx < total) {\n int d = idx % D;\n if ((mask_bits >> d) & 1ULL) {\n out[idx] = x[d];\n } else {\n out[idx] = x[idx];\n }\n }\n}\n\ntorch::Tensor masked_broadcast_cuda(torch::Tensor x, unsigned long long mask_bits) {\n int B = x.size(0);\n int D = x.size(1);\n auto out = torch::empty_like(x);\n int total = B * D;\n const int threads = 256;\n const int blocks = (total + threads - 1) / threads;\n masked_broadcast_kernel<<<blocks, threads>>>(\n x.data_ptr<float>(),\n out.data_ptr<float>(),\n mask_bits,\n B,\n D\n );\n return out;\n}\n\"\"\"\n\nmasked_broadcast_cuda = load_inline(\n name=\"masked_broadcast_cuda\",\n cpp_sources=cpp_sources,\n cuda_sources=cuda_source,\n functions=[\"masked_broadcast_cuda\"],\n extra_cuda_cflags=[\"-O3\"],\n verbose=False,\n)\n\nclass ModelNew(nn.Module):\n def __init__(self):\n super().__init__()\n self.register_buffer(\"row_mask\", _MASK.clone(), persistent=False)\n mask_bits = 0\n for i, val in enumerate(self.row_mask.tolist()):\n if val:\n mask_bits |= (1 << i)\n self.mask_bits = mask_bits\n\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n x = x.contiguous()\n return masked_broadcast_cuda(x, self.mask_bits)\n" }
result ← run_correctness (fail)
failrun_correctness run_correctness FAILED: ? trials did not all match. runtime_error: 'module' object is not callable
turn 33.8s turn · 3.8s LLM · 0.0s tools
reasoning
Hmm, it seems the load_inline returns a module, and the function is accessible as an attribute. Let me fix that.
call → compile_kernel
callcompile_kernel { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n# Fixed constants from the reference\nB = 18\nD = 44\n_MASK = torch.tensor(\n [1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1],\n dtype=torch.bool,\n)\n\ncpp_sources = \"\"\"\ntorch::Tensor masked_broadcast_cuda(torch::Tensor x, unsigned long long mask_bits);\n\"\"\"\n\ncuda_source = \"\"\"\n#include <torch/extension.h>\n#include <cuda_runtime.h>\n\n__global__ void masked_broadcast_kernel(\n const float* __restrict__ x,\n float* __restrict__ out,\n unsigned long long mask_bits,\n int B,\n int D)\n{\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n int total = B * D;\n if (idx < total) {\n int d = idx % D;\n if ((mask_bits >> d) & 1ULL) {\n out[idx] = x[d];\n } else {\n out[idx] = x[idx];\n }\n }\n}\n\ntorch::Tensor masked_broadcast_cuda(torch::Tensor x, unsigned long long mask_bits) {\n int B = x.size(0);\n int D = x.size(1);\n auto out = torch::empty_like(x);\n int total = B * D;\n const int threads = 256;\n const int blocks = (total + threads - 1) / threads;\n masked_broadcast_kernel<<<blocks, threads>>>(\n x.data_ptr<float>(),\n out.data_ptr<float>(),\n mask_bits,\n B,\n D\n );\n return out;\n}\n\"\"\"\n\n_cuda_module = load_inline(\n name=\"masked_broadcast_cuda\",\n cpp_sources=cpp_sources,\n cuda_sources=cuda_source,\n functions=[\"masked_broadcast_cuda\"],\n extra_cuda_cflags=[\"-O3\"],\n verbose=False,\n)\n\nclass ModelNew(nn.Module):\n def __init__(self):\n super().__init__()\n self.register_buffer(\"row_mask\", _MASK.clone(), persistent=False)\n mask_bits = 0\n for i, val in enumerate(self.row_mask.tolist()):\n if val:\n mask_bits |= (1 << i)\n self.mask_bits = mask_bits\n\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n x = x.contiguous()\n return _cuda_module.masked_broadcast_cuda(x, self.mask_bits)\n" }
result ← compile_kernel (ok)
okcompile_kernel compile_kernel PASSED: kernel compiled without errors.
turn 45.5s turn · 5.5s 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# Fixed constants from the reference\nB = 18\nD = 44\n_MASK = torch.tensor(\n [1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1],\n dtype=torch.bool,\n)\n\ncpp_sources = \"\"\"\ntorch::Tensor masked_broadcast_cuda(torch::Tensor x, unsigned long long mask_bits);\n\"\"\"\n\ncuda_source = \"\"\"\n#include <torch/extension.h>\n#include <cuda_runtime.h>\n\n__global__ void masked_broadcast_kernel(\n const float* __restrict__ x,\n float* __restrict__ out,\n unsigned long long mask_bits,\n int B,\n int D)\n{\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n int total = B * D;\n if (idx < total) {\n int d = idx % D;\n if ((mask_bits >> d) & 1ULL) {\n out[idx] = x[d];\n } else {\n out[idx] = x[idx];\n }\n }\n}\n\ntorch::Tensor masked_broadcast_cuda(torch::Tensor x, unsigned long long mask_bits) {\n int B = x.size(0);\n int D = x.size(1);\n auto out = torch::empty_like(x);\n int total = B * D;\n const int threads = 256;\n const int blocks = (total + threads - 1) / threads;\n masked_broadcast_kernel<<<blocks, threads>>>(\n x.data_ptr<float>(),\n out.data_ptr<float>(),\n mask_bits,\n B,\n D\n );\n return out;\n}\n\"\"\"\n\n_cuda_module = load_inline(\n name=\"masked_broadcast_cuda\",\n cpp_sources=cpp_sources,\n cuda_sources=cuda_source,\n functions=[\"masked_broadcast_cuda\"],\n extra_cuda_cflags=[\"-O3\"],\n verbose=False,\n)\n\nclass ModelNew(nn.Module):\n def __init__(self):\n super().__init__()\n self.register_buffer(\"row_mask\", _MASK.clone(), persistent=False)\n mask_bits = 0\n for i, val in enumerate(self.row_mask.tolist()):\n if val:\n mask_bits |= (1 << i)\n self.mask_bits = mask_bits\n\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n x = x.contiguous()\n return _cuda_module.masked_broadcast_cuda(x, self.mask_bits)\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 58.0s turn · 8.0s LLM · 0.0s tools
reasoning
The kernel compiled and is correct - 5/5 trials matched with exactly zero error. Now let me get the GPU specs and think about optimization. The current kernel is fairly simple - one thread per element. The problem has B=18, D=44, so total elements = 792. That's tiny. With 256 threads per block, we'd only launch around 3-4 blocks. On an H100, that's barely anything. However, the reference operation is also extremely simple in PyTorch (where + expand + indexing), so we might not need much optimization. The overhead of kernel launch might dominate. Let me get GPU specs first and think about whether to optimize further. Actually, let me just check if static analysis passes, and then submit. For such a small operation, the kernel should already be faster than PyTorch because PyTorch internally allocates intermediates for m, row0, and does a where operation. Our kernel does everything in one go with no extra allocations. Let me first do the static check.
call → static_check
callstatic_check { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n# Fixed constants from the reference\nB = 18\nD = 44\n_MASK = torch.tensor(\n [1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1],\n dtype=torch.bool,\n)\n\ncpp_sources = \"\"\"\ntorch::Tensor masked_broadcast_cuda(torch::Tensor x, unsigned long long mask_bits);\n\"\"\"\n\ncuda_source = \"\"\"\n#include <torch/extension.h>\n#include <cuda_runtime.h>\n\n__global__ void masked_broadcast_kernel(\n const float* __restrict__ x,\n float* __restrict__ out,\n unsigned long long mask_bits,\n int B,\n int D)\n{\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n int total = B * D;\n if (idx < total) {\n int d = idx % D;\n if ((mask_bits >> d) & 1ULL) {\n out[idx] = x[d];\n } else {\n out[idx] = x[idx];\n }\n }\n}\n\ntorch::Tensor masked_broadcast_cuda(torch::Tensor x, unsigned long long mask_bits) {\n int B = x.size(0);\n int D = x.size(1);\n auto out = torch::empty_like(x);\n int total = B * D;\n const int threads = 256;\n const int blocks = (total + threads - 1) / threads;\n masked_broadcast_kernel<<<blocks, threads>>>(\n x.data_ptr<float>(),\n out.data_ptr<float>(),\n mask_bits,\n B,\n D\n );\n return out;\n}\n\"\"\"\n\n_cuda_module = load_inline(\n name=\"masked_broadcast_cuda\",\n cpp_sources=cpp_sources,\n cuda_sources=cuda_source,\n functions=[\"masked_broadcast_cuda\"],\n extra_cuda_cflags=[\"-O3\"],\n verbose=False,\n)\n\nclass ModelNew(nn.Module):\n def __init__(self):\n super().__init__()\n self.register_buffer(\"row_mask\", _MASK.clone(), persistent=False)\n mask_bits = 0\n for i, val in enumerate(self.row_mask.tolist()):\n if val:\n mask_bits |= (1 << i)\n self.mask_bits = mask_bits\n\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n x = x.contiguous()\n return _cuda_module.masked_broadcast_cuda(x, self.mask_bits)\n" }
result ← static_check (ok)
okstatic_check static_check PASSED: no violations or warnings detected.
turn 68.0s turn · 8.0s LLM · 0.0s tools · FINAL
reasoning
The kernel compiled, correctness checks passed, and static check passed. Let me now see if there are any optimizations I should make before submitting. Given that B=18 and D=44, the total elements are only 792. This is a very small kernel, so the main overhead is likely launch overhead and memory operations. Let me think about potential optimizations: 1. Use larger block size or different grid configuration 2. Maybe use vectorized loads/stores 3. Maybe process multiple elements per thread But for such a small size, the simple approach may already be close to optimal. The reference PyTorch implementation creates intermediates (expand, where), so avoiding those should help significantly. Let me check if I should further optimize. For 792 elements: - With 256 threads/block, that's ~4 blocks. - On an H100, this is extremely small. One possible optimization is to have each thread process multiple elements (unroll), which can better utilize memory bandwidth. But for correctness and simplicity, and given that B and D are fixed and small, this kernel should be fast enough. Actually, let me reconsider the kernel. Right now it does: - 1 memory read per output (either x[d] or x[idx]) - 1 memory write per output For the reference: 1. `self.row_mask.to(device=x.device).view(1, D).expand(B, D)` - creates an expanded mask tensor 2. `x[0:1].expand(B, D)` - creates an expanded row0 tensor 3. `torch.where(m, row0, x)` - reads mask, row0, x and writes output So the reference does multiple memory operations and allocates temporary tensors. Our kernel does it in one pass with no temporary allocations. This should be much faster for this small size. One thing I should verify - does the correctness check pass with the expected inputs? The test generates random inputs with a fixed seed, and we matched perfectly. One small issue: I should make sure that the mask is baked in at init time (which it is), and that x[0:1] is correctly interpreted as row 0 for all columns. In the reference, `x[0:1]` is shape (1, D) and expanded to (B, D). The first row of the output where mask is True should be x[0, d] - but since the first row already has x[0, d], this means effectively: - For any row b (including row 0), if mask[d] is True, output = x[0, d] - If mask[d] is False, output = x[b, d] This matches our kernel: for any (b, d), if mask[d] is True, output = x[d] = x[0, d]; else output = x[b, d]. Wait, actually, x[d] = x[0, d] because the first row starts at x[0] and x[d] is indeed x[0, d]. So yes, it's correct. Let me submit this kernel.
call → submit_kernel
callsubmit_kernel { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n# Fixed constants from the reference\nB = 18\nD = 44\n_MASK = torch.tensor(\n [1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1],\n dtype=torch.bool,\n)\n\ncpp_sources = \"\"\"\ntorch::Tensor masked_broadcast_cuda(torch::Tensor x, unsigned long long mask_bits);\n\"\"\"\n\ncuda_source = \"\"\"\n#include <torch/extension.h>\n#include <cuda_runtime.h>\n\n__global__ void masked_broadcast_kernel(\n const float* __restrict__ x,\n float* __restrict__ out,\n unsigned long long mask_bits,\n int B,\n int D)\n{\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n int total = B * D;\n if (idx < total) {\n int d = idx % D;\n if ((mask_bits >> d) & 1ULL) {\n out[idx] = x[d];\n } else {\n out[idx] = x[idx];\n }\n }\n}\n\ntorch::Tensor masked_broadcast_cuda(torch::Tensor x, unsigned long long mask_bits) {\n int B = x.size(0);\n int D = x.size(1);\n auto out = torch::empty_like(x);\n int total = B * D;\n const int threads = 256;\n const int blocks = (total + threads - 1) / threads;\n masked_broadcast_kernel<<<blocks, threads>>>(\n x.data_ptr<float>(),\n out.data_ptr<float>(),\n mask_bits,\n B,\n D\n );\n return out;\n}\n\"\"\"\n\n_cuda_module = load_inline(\n name=\"masked_broadcast_cuda\",\n cpp_sources=cpp_sources,\n cuda_sources=cuda_source,\n functions=[\"masked_broadcast_cuda\"],\n extra_cuda_cflags=[\"-O3\"],\n verbose=False,\n)\n\nclass ModelNew(nn.Module):\n def __init__(self):\n super().__init__()\n self.register_buffer(\"row_mask\", _MASK.clone(), persistent=False)\n mask_bits = 0\n for i, val in enumerate(self.row_mask.tolist()):\n if val:\n mask_bits |= (1 << i)\n self.mask_bits = mask_bits\n\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n x = x.contiguous()\n return _cuda_module.masked_broadcast_cuda(x, self.mask_bits)\n" }
result ← submit_kernel (ok)
oksubmit_kernel submit_kernel PASSED: (5 / 5) correctness trials all passed. Kernel runtime: 0.01 μs Runtime stats: mean=0.01μs median=?μs std=0.00μs Numerical precision: max_abs_err=0.00e+00 mean_abs_err=0.00e+00 max_rel_err=0.00e+00 Memory: 33.01 MB peak (ref: 33.01 MB, ratio: 1.0x) Kernel launches: 2 (ref: 11, fusion ratio: 5.5) SOL score: 0.0006
final submitted kernel (80 lines, 2,071 chars) — full source, untruncated
import torch
import torch.nn as nn
from torch.utils.cpp_extension import load_inline

# Fixed constants from the reference
B = 18
D = 44
_MASK = torch.tensor(
    [1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1],
    dtype=torch.bool,
)

cpp_sources = """
torch::Tensor masked_broadcast_cuda(torch::Tensor x, unsigned long long mask_bits);
"""

cuda_source = """
#include <torch/extension.h>
#include <cuda_runtime.h>

__global__ void masked_broadcast_kernel(
    const float* __restrict__ x,
    float* __restrict__ out,
    unsigned long long mask_bits,
    int B,
    int D)
{
    int idx = blockIdx.x * blockDim.x + threadIdx.x;
    int total = B * D;
    if (idx < total) {
        int d = idx % D;
        if ((mask_bits >> d) & 1ULL) {
            out[idx] = x[d];
        } else {
            out[idx] = x[idx];
        }
    }
}

torch::Tensor masked_broadcast_cuda(torch::Tensor x, unsigned long long mask_bits) {
    int B = x.size(0);
    int D = x.size(1);
    auto out = torch::empty_like(x);
    int total = B * D;
    const int threads = 256;
    const int blocks = (total + threads - 1) / threads;
    masked_broadcast_kernel<<<blocks, threads>>>(
        x.data_ptr<float>(),
        out.data_ptr<float>(),
        mask_bits,
        B,
        D
    );
    return out;
}
"""

_cuda_module = load_inline(
    name="masked_broadcast_cuda",
    cpp_sources=cpp_sources,
    cuda_sources=cuda_source,
    functions=["masked_broadcast_cuda"],
    extra_cuda_cflags=["-O3"],
    verbose=False,
)

class ModelNew(nn.Module):
    def __init__(self):
        super().__init__()
        self.register_buffer("row_mask", _MASK.clone(), persistent=False)
        mask_bits = 0
        for i, val in enumerate(self.row_mask.tolist()):
            if val:
                mask_bits |= (1 << i)
        self.mask_bits = mask_bits

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        x = x.contiguous()
        return _cuda_module.masked_broadcast_cuda(x, self.mask_bits)