Download torch-ext/torch_binding.cpp from phanerozoic/model-as-a-kernel: direct link, hf CLI and curl.
- Browser
- Download file 11.5 kB
-
https://huggingface.co/kernels/phanerozoic/model-as-a-kernel/resolve/v1/torch-ext/torch_binding.cpp
- Command line
-
hf download hf://phanerozoic/model-as-a-kernel@v1/torch-ext/torch_binding.cpp
-
curl -L -o torch_binding.cpp https://huggingface.co/kernels/phanerozoic/model-as-a-kernel/resolve/v1/torch-ext/torch_binding.cpp
11.5 kB
| namespace { | |
| void check_prog(const at::Tensor& prog) { | |
| TORCH_CHECK(prog.is_cuda(), "prog must be CUDA"); | |
| TORCH_CHECK(prog.scalar_type() == at::kLong, "prog must be int64"); | |
| TORCH_CHECK(prog.dim() == 2 && prog.size(1) == 16 && prog.is_contiguous(), | |
| "prog must be a contiguous [n_phases, 16] tensor"); | |
| } | |
| void check_barrier(const at::Tensor& barrier) { | |
| TORCH_CHECK(barrier.is_cuda() && barrier.scalar_type() == at::kInt && | |
| barrier.numel() >= 34, | |
| "barrier must be a CUDA int32 tensor with >= 2 elements"); | |
| } | |
| struct LaunchShape { | |
| int smem; | |
| int ring_stages; | |
| }; | |
| // Dynamic shared = bf16 staging + the cp.async weight ring (one stage is | |
| // 8 warps x 32 lanes x 16B = 4KB); the ring depth adapts to the device. | |
| // Batched decode fully stages [B][K] for the small-K projections, so the | |
| // cap admits panels up to ~96KB; whether that many blocks stay co-resident | |
| // is settled by the occupancy query, not this bound. | |
| LaunchShape shape_for(int64_t stage_elems) { | |
| TORCH_CHECK(stage_elems > 0 && stage_elems <= 49152, | |
| "staging size out of range"); | |
| const int stage_bytes = (int)(stage_elems * 2); | |
| const int rs = mak_ring_stages_impl(stage_bytes); | |
| return {stage_bytes + rs * 4096, rs}; | |
| } | |
| } // namespace | |
| int64_t mak_num_blocks(at::Tensor prog, int64_t max_k) { | |
| const c10::cuda::CUDAGuard guard(prog.device()); | |
| return (int64_t)mak_grid_blocks_impl(shape_for(max_k).smem); | |
| } | |
| int64_t mak_batch_maxb() { return (int64_t)mak_batch_maxb_impl(); } | |
| double mak_bw_per_sm(at::Tensor probe) { | |
| const c10::cuda::CUDAGuard guard(probe.device()); | |
| int dev = 0; | |
| cudaGetDevice(&dev); | |
| int clk_khz = 0, bus_bits = 0, sms = 1; | |
| cudaDeviceGetAttribute(&clk_khz, cudaDevAttrMemoryClockRate, dev); | |
| cudaDeviceGetAttribute(&bus_bits, cudaDevAttrGlobalMemoryBusWidth, dev); | |
| cudaDeviceGetAttribute(&sms, cudaDevAttrMultiProcessorCount, dev); | |
| if (sms < 1) sms = 1; | |
| const double gbps = | |
| 2.0 * (double)clk_khz * 1e3 * ((double)bus_bits / 8.0) / 1e9; | |
| return gbps / (double)sms; | |
| } | |
| void mak_run(at::Tensor prog, at::Tensor barrier, int64_t pos, | |
| int64_t step_slot, int64_t max_k) { | |
| check_prog(prog); | |
| check_barrier(barrier); | |
| const c10::cuda::CUDAGuard guard(prog.device()); | |
| auto stream = at::cuda::getCurrentCUDAStream(); | |
| int* bar = barrier.data_ptr<int>(); | |
| const LaunchShape sh = shape_for(max_k); | |
| const cudaError_t err = mak_launch_mega( | |
| reinterpret_cast<const long long*>(prog.data_ptr<int64_t>()), | |
| (int)prog.size(0), (int)pos, 1, (int)step_slot, -1, 1, sh.ring_stages, | |
| bar, mak_grid_blocks_impl(sh.smem), sh.smem, stream.stream(), nullptr); | |
| TORCH_CHECK(err == cudaSuccess, "mak_run launch failed: ", | |
| cudaGetErrorString(err)); | |
| } | |
| void mak_run_steps(at::Tensor prog, at::Tensor barrier, int64_t pos0, | |
| int64_t steps, int64_t slot0, int64_t max_k) { | |
| check_prog(prog); | |
| check_barrier(barrier); | |
| const c10::cuda::CUDAGuard guard(prog.device()); | |
| auto stream = at::cuda::getCurrentCUDAStream(); | |
| int* bar = barrier.data_ptr<int>(); | |
| const long long* pp = | |
| reinterpret_cast<const long long*>(prog.data_ptr<int64_t>()); | |
| const int n = (int)prog.size(0); | |
| const LaunchShape sh = shape_for(max_k); | |
| const int grid = mak_grid_blocks_impl(sh.smem); | |
| for (int64_t i = 0; i < steps; ++i) { | |
| const cudaError_t err = | |
| mak_launch_mega(pp, n, (int)(pos0 + i), 1, (int)(slot0 + i), 0, 1, | |
| sh.ring_stages, bar, grid, sh.smem, stream.stream(), | |
| nullptr); | |
| TORCH_CHECK(err == cudaSuccess, "mak_run_steps launch failed: ", | |
| cudaGetErrorString(err)); | |
| } | |
| } | |
| void mak_run_seq(at::Tensor prog, at::Tensor barrier, int64_t pos0, | |
| int64_t steps, int64_t slot0, int64_t prompt_len, | |
| int64_t max_k, int64_t chunk_m) { | |
| check_prog(prog); | |
| check_barrier(barrier); | |
| TORCH_CHECK(steps >= 1, "steps must be >= 1"); | |
| TORCH_CHECK(chunk_m >= 1 && chunk_m <= 8, "chunk_m must be in [1, 8]"); | |
| const c10::cuda::CUDAGuard guard(prog.device()); | |
| auto stream = at::cuda::getCurrentCUDAStream(); | |
| int* bar = barrier.data_ptr<int>(); | |
| const LaunchShape sh = shape_for(max_k * chunk_m); | |
| const cudaError_t err = mak_launch_mega( | |
| reinterpret_cast<const long long*>(prog.data_ptr<int64_t>()), | |
| (int)prog.size(0), (int)pos0, (int)steps, (int)slot0, (int)prompt_len, | |
| (int)chunk_m, sh.ring_stages, bar, mak_grid_blocks_impl(sh.smem), | |
| sh.smem, stream.stream(), nullptr); | |
| TORCH_CHECK(err == cudaSuccess, "mak_run_seq launch failed: ", | |
| cudaGetErrorString(err)); | |
| } | |
| // B <= 8 runs the fused shared-staging kernel (input staged [B][K]); larger | |
| // B runs the global-scratch kernel, which does not stage the input in | |
| // shared and so is bounded only by the register accumulators. | |
| // stage_elems is the largest shared panel the batch program stages: for the | |
| // fused path max_k*B, for the wide path the max B*K over the projections | |
| // that stay fused (the rest transform into global scratch and stage nothing). | |
| void mak_run_batch(at::Tensor prog, at::Tensor barrier, at::Tensor pos_b, | |
| int64_t steps, int64_t slot0, int64_t max_k, | |
| int64_t kv_bstride, int64_t stage_elems) { | |
| check_prog(prog); | |
| check_barrier(barrier); | |
| const int maxb = mak_batch_maxb(); | |
| TORCH_CHECK(pos_b.is_cuda() && pos_b.scalar_type() == at::kInt && | |
| pos_b.is_contiguous() && pos_b.numel() >= 1 && | |
| pos_b.numel() <= maxb, | |
| "pos_b must be a contiguous CUDA int32 tensor with 1..", | |
| maxb, " elements"); | |
| TORCH_CHECK(steps >= 1, "steps must be >= 1"); | |
| const int B = (int)pos_b.numel(); | |
| const c10::cuda::CUDAGuard guard(prog.device()); | |
| auto stream = at::cuda::getCurrentCUDAStream(); | |
| int* bar = barrier.data_ptr<int>(); | |
| const long long* pp = | |
| reinterpret_cast<const long long*>(prog.data_ptr<int64_t>()); | |
| // The fully-fused path holds [B][K] for every projection and up to 8 | |
| // accumulators, so it serves B up to min(8, 16384 / max_k); wider batches | |
| // take the acc[NB] kernel, where large-K projections spill to scratch. | |
| const int64_t fused_cap = std::min<int64_t>(8, 16384 / max_k); | |
| const LaunchShape sh = shape_for(stage_elems); | |
| cudaError_t err; | |
| if ((int64_t)B <= fused_cap) { | |
| err = mak_launch_mega_batch( | |
| pp, (int)prog.size(0), (int)steps, (int)slot0, sh.ring_stages, bar, | |
| mak_grid_blocks_impl(sh.smem), sh.smem, pos_b.data_ptr<int>(), B, | |
| (long long)kv_bstride, stream.stream()); | |
| } else { | |
| err = mak_launch_mega_batch_big( | |
| pp, (int)prog.size(0), (int)steps, (int)slot0, sh.ring_stages, bar, | |
| mak_grid_blocks_big_impl(sh.smem), sh.smem, pos_b.data_ptr<int>(), B, | |
| (long long)kv_bstride, stream.stream()); | |
| } | |
| TORCH_CHECK(err == cudaSuccess, "mak_run_batch launch failed: ", | |
| cudaGetErrorString(err)); | |
| } | |
| void mak_run_ts(at::Tensor prog, at::Tensor barrier, int64_t pos, | |
| int64_t step_slot, int64_t max_k, at::Tensor ts) { | |
| check_prog(prog); | |
| check_barrier(barrier); | |
| TORCH_CHECK(ts.is_cuda() && ts.scalar_type() == at::kLong && | |
| ts.numel() >= prog.size(0) + 1, | |
| "ts must be a CUDA int64 tensor with n_phases+1 elements"); | |
| const c10::cuda::CUDAGuard guard(prog.device()); | |
| auto stream = at::cuda::getCurrentCUDAStream(); | |
| int* bar = barrier.data_ptr<int>(); | |
| const LaunchShape sh = shape_for(max_k); | |
| const cudaError_t err = mak_launch_mega( | |
| reinterpret_cast<const long long*>(prog.data_ptr<int64_t>()), | |
| (int)prog.size(0), (int)pos, 1, (int)step_slot, -1, 1, sh.ring_stages, | |
| bar, mak_grid_blocks_impl(sh.smem), sh.smem, stream.stream(), | |
| reinterpret_cast<long long*>(ts.data_ptr<int64_t>())); | |
| TORCH_CHECK(err == cudaSuccess, "mak_run_ts launch failed: ", | |
| cudaGetErrorString(err)); | |
| } | |
| at::Tensor mak_run_phased(at::Tensor prog, int64_t pos, int64_t step_slot, | |
| bool timed, int64_t max_k) { | |
| check_prog(prog); | |
| const c10::cuda::CUDAGuard guard(prog.device()); | |
| auto stream = at::cuda::getCurrentCUDAStream(); | |
| const long long* pp = | |
| reinterpret_cast<const long long*>(prog.data_ptr<int64_t>()); | |
| const int n = (int)prog.size(0); | |
| const LaunchShape sh = shape_for(max_k); | |
| const int grid = mak_grid_blocks_impl(sh.smem); | |
| if (timed) { | |
| std::vector<float> ms((size_t)n, 0.f); | |
| cudaEvent_t a, b; | |
| cudaEventCreate(&a); | |
| cudaEventCreate(&b); | |
| for (int p = 0; p < n; ++p) { | |
| cudaEventRecord(a, stream.stream()); | |
| const cudaError_t err = mak_launch_phase(pp, p, (int)pos, | |
| (int)step_slot, | |
| sh.ring_stages, grid, sh.smem, | |
| stream.stream()); | |
| TORCH_CHECK(err == cudaSuccess, "mak_run_phased launch failed: ", | |
| cudaGetErrorString(err)); | |
| cudaEventRecord(b, stream.stream()); | |
| cudaEventSynchronize(b); | |
| cudaEventElapsedTime(&ms[p], a, b); | |
| } | |
| cudaEventDestroy(a); | |
| cudaEventDestroy(b); | |
| return torch::tensor(ms, torch::dtype(torch::kFloat32)); | |
| } | |
| for (int p = 0; p < n; ++p) { | |
| const cudaError_t err = mak_launch_phase(pp, p, (int)pos, (int)step_slot, | |
| sh.ring_stages, grid, sh.smem, | |
| stream.stream()); | |
| TORCH_CHECK(err == cudaSuccess, "mak_run_phased launch failed: ", | |
| cudaGetErrorString(err)); | |
| } | |
| return torch::empty({0}, torch::dtype(torch::kFloat32)); | |
| } | |
| TORCH_LIBRARY_EXPAND(TORCH_EXTENSION_NAME, ops) { | |
| ops.def("mak_run(Tensor prog, Tensor barrier, int pos, int step_slot, " | |
| "int max_k) -> ()"); | |
| ops.def("mak_run_steps(Tensor prog, Tensor barrier, int pos0, int steps, " | |
| "int slot0, int max_k) -> ()"); | |
| ops.def("mak_run_seq(Tensor prog, Tensor barrier, int pos0, int steps, " | |
| "int slot0, int prompt_len, int max_k, int chunk_m) -> ()"); | |
| ops.def("mak_run_phased(Tensor prog, int pos, int step_slot, bool timed, " | |
| "int max_k) -> Tensor"); | |
| ops.def("mak_num_blocks(Tensor prog, int max_k) -> int"); | |
| ops.def("mak_bw_per_sm(Tensor probe) -> float"); | |
| ops.def("mak_run_ts(Tensor prog, Tensor barrier, int pos, int step_slot, " | |
| "int max_k, Tensor ts) -> ()"); | |
| ops.def("mak_run_batch(Tensor prog, Tensor barrier, Tensor pos_b, " | |
| "int steps, int slot0, int max_k, int kv_bstride, " | |
| "int stage_elems) -> ()"); | |
| // no tensor argument, so register a device-agnostic implementation | |
| ops.def("mak_batch_maxb() -> int", &mak_batch_maxb); | |
| ops.impl("mak_run", torch::kCUDA, &mak_run); | |
| ops.impl("mak_run_steps", torch::kCUDA, &mak_run_steps); | |
| ops.impl("mak_run_seq", torch::kCUDA, &mak_run_seq); | |
| ops.impl("mak_run_phased", torch::kCUDA, &mak_run_phased); | |
| ops.impl("mak_num_blocks", torch::kCUDA, &mak_num_blocks); | |
| ops.impl("mak_bw_per_sm", torch::kCUDA, &mak_bw_per_sm); | |
| ops.impl("mak_run_ts", torch::kCUDA, &mak_run_ts); | |
| ops.impl("mak_run_batch", torch::kCUDA, &mak_run_batch); | |
| } | |
| REGISTER_EXTENSION(TORCH_EXTENSION_NAME) | |