| 218 | # @torch.compile(fullgraph=True) |
| 219 | @nvtx.annotate() |
| 220 | def fused_mm_sample_triton( |
| 221 | weights: torch.Tensor, # [V_local, D] (may be a TP shard) |
| 222 | hidden_states: torch.Tensor, # [n_hidden_states, D] |
| 223 | num_samples: int, |
| 224 | temperature: torch.Tensor, # scalar (0-d) |
| 225 | seed: int, |
| 226 | greedy_sampling: bool = False, |
| 227 | tp: "TPInfo" = TP1, |
| 228 | return_logits: bool = False, |
| 229 | ): |
| 230 | assert torch.cuda.is_available(), "fused_mm_sample_triton requires CUDA" |
| 231 | V, D = weights.shape # noqa: N806 |
| 232 | H, D2 = hidden_states.shape # noqa: N806 |
| 233 | if D2 != D: |
| 234 | raise ValueError( |
| 235 | f"hidden_states second dimension ({D2}) must match weights second dimension ({D})" |
| 236 | ) |
| 237 | |
| 238 | # The kernel uses TMA descriptors which need a runtime allocator. Some |
| 239 | # autotuner configs (notably the ones picked on B200/sm_100) request global |
| 240 | # scratch from this allocator; without it Triton raises a RuntimeError at launch. |
| 241 | set_torch_allocator_for_tma_descriptors_cached() |
| 242 | |
| 243 | NUM_SMS = num_sms_cached(weights.device.index) # noqa: N806 |
| 244 | |
| 245 | max_grid_size_v = triton.cdiv(V, MIN_BLOCK_SIZE_V) |
| 246 | if tp.size > 1: |
| 247 | maxs, maxs_idx, symm_mem_hdl, storage_offset_maxs_idx = allocate_symm_mem_outputs( |
| 248 | num_samples=num_samples, |
| 249 | max_grid_size_v=max_grid_size_v, |
| 250 | H=H, |
| 251 | ) |
| 252 | kernel_maxs = maxs[tp.rank] |
| 253 | kernel_maxs_idx = maxs_idx[tp.rank] |
| 254 | symm_mem_buffer_ptrs = symm_mem_hdl.buffer_ptrs_dev |
| 255 | else: |
| 256 | maxs = torch.empty( |
| 257 | (num_samples, max_grid_size_v, H), |
| 258 | dtype=torch.bfloat16, |
| 259 | device=weights.device, |
| 260 | ) |
| 261 | maxs_idx = torch.empty_like(maxs, dtype=torch.long) |
| 262 | kernel_maxs = maxs |
| 263 | kernel_maxs_idx = maxs_idx |
| 264 | storage_offset_maxs_idx = 0 |
| 265 | symm_mem_buffer_ptrs = maxs |
| 266 | |
| 267 | # logits_out is only read when RETURN_LOGITS=True. For the common path |
| 268 | # (return_logits=False), allocating a (V, H) fp32 buffer per call is wasted |
| 269 | # HBM (155 MB per decode step at Qwen3-1.7B / H=256) for a buffer the |
| 270 | # kernel never touches. Pass a 1-element dummy in that case so the kernel |
| 271 | # still has a valid pointer to receive. |
| 272 | logits_shape = (V, H) if return_logits else (1,) |
| 273 | logits_out = torch.empty(logits_shape, dtype=torch.float32, device=weights.device) |
| 274 | |
| 275 | grid_size = {"v": None} |
| 276 | |
| 277 | def grid(meta): |