[DSA] Fix top-k v2 dropping non-primary ranks' output on CUDA 13.1+ (root cause for #33835) (#34167)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
169783d42f
commit
accc51c6db
@@ -11,12 +11,19 @@
|
|||||||
|
|
||||||
namespace sglang {
|
namespace sglang {
|
||||||
|
|
||||||
#ifndef SGL_TOPK
|
// `topk` is a *runtime* value (<= kMaxTopK), so one module serves every k. It
|
||||||
#define SGL_TOPK 512
|
// used to be baked in via -DSGL_TOPK, which built a separate module per k --
|
||||||
#endif
|
// and because `kTopK` came from a macro rather than a template parameter, both
|
||||||
|
// modules exported identically mangled symbols. The function-local static in
|
||||||
constexpr uint32_t kTopK = SGL_TOPK;
|
// setup_kernel_smem_once() is emitted as STB_GNU_UNIQUE, which the loader
|
||||||
constexpr uint32_t kTopKBlockSize = SGL_TOPK;
|
// merges across every loaded object, so whichever module was used second
|
||||||
|
// skipped its cudaFuncSetAttribute opt-in and then failed to launch with 64 KB
|
||||||
|
// of dynamic shared memory ("invalid argument").
|
||||||
|
constexpr uint32_t kMaxTopK = 1024;
|
||||||
|
// Fixed, and deliberately not tied to `topk`: run_cumsum() and the histogram
|
||||||
|
// init below index up to RADIX + 1 == 257 threads, so a block sized after a
|
||||||
|
// small topk would silently skip part of the histogram.
|
||||||
|
constexpr uint32_t kTopKBlockSize = kMaxTopK;
|
||||||
constexpr uint32_t kSMEM = 16 * 1024 * sizeof(uint32_t); // 64KB (bytes)
|
constexpr uint32_t kSMEM = 16 * 1024 * sizeof(uint32_t); // 64KB (bytes)
|
||||||
|
|
||||||
struct TopKParams {
|
struct TopKParams {
|
||||||
@@ -28,6 +35,7 @@ struct TopKParams {
|
|||||||
const int64_t score_stride;
|
const int64_t score_stride;
|
||||||
const int64_t page_table_stride;
|
const int64_t page_table_stride;
|
||||||
uint32_t page_bits;
|
uint32_t page_bits;
|
||||||
|
uint32_t topk;
|
||||||
};
|
};
|
||||||
|
|
||||||
SGL_DEVICE uint8_t convert_to_uint8(float x) {
|
SGL_DEVICE uint8_t convert_to_uint8(float x) {
|
||||||
@@ -54,14 +62,14 @@ SGL_DEVICE void naive_transform(
|
|||||||
int32_t* __restrict__ indices,
|
int32_t* __restrict__ indices,
|
||||||
int32_t* __restrict__ raw_indices, // optional: output raw abs position indices
|
int32_t* __restrict__ raw_indices, // optional: output raw abs position indices
|
||||||
const uint32_t length,
|
const uint32_t length,
|
||||||
const uint32_t page_bits) {
|
const uint32_t page_bits,
|
||||||
static_assert(kTopK <= kTopKBlockSize);
|
const uint32_t topk) {
|
||||||
if (const auto tx = threadIdx.x; tx < length) {
|
if (const auto tx = threadIdx.x; tx < length) {
|
||||||
indices[tx] = page_to_indices(page_table, tx, page_bits);
|
indices[tx] = page_to_indices(page_table, tx, page_bits);
|
||||||
if (raw_indices != nullptr) {
|
if (raw_indices != nullptr) {
|
||||||
raw_indices[tx] = tx;
|
raw_indices[tx] = tx;
|
||||||
}
|
}
|
||||||
} else if (kTopK == kTopKBlockSize || tx < kTopK) {
|
} else if (tx < topk) {
|
||||||
indices[tx] = -1; // fill invalid indices to -1
|
indices[tx] = -1; // fill invalid indices to -1
|
||||||
if (raw_indices != nullptr) {
|
if (raw_indices != nullptr) {
|
||||||
raw_indices[tx] = -1;
|
raw_indices[tx] = -1;
|
||||||
@@ -70,7 +78,8 @@ SGL_DEVICE void naive_transform(
|
|||||||
}
|
}
|
||||||
|
|
||||||
[[maybe_unused]]
|
[[maybe_unused]]
|
||||||
SGL_DEVICE void radix_topk(const float* __restrict__ input, int32_t* __restrict__ output, const uint32_t length) {
|
SGL_DEVICE void
|
||||||
|
radix_topk(const float* __restrict__ input, int32_t* __restrict__ output, const uint32_t length, const uint32_t topk) {
|
||||||
constexpr uint32_t RADIX = 256;
|
constexpr uint32_t RADIX = 256;
|
||||||
constexpr uint32_t BLOCK_SIZE = kTopKBlockSize;
|
constexpr uint32_t BLOCK_SIZE = kTopKBlockSize;
|
||||||
constexpr uint32_t SMEM_INPUT_SIZE = kSMEM / (2 * sizeof(int32_t));
|
constexpr uint32_t SMEM_INPUT_SIZE = kSMEM / (2 * sizeof(int32_t));
|
||||||
@@ -84,7 +93,7 @@ SGL_DEVICE void radix_topk(const float* __restrict__ input, int32_t* __restrict_
|
|||||||
extern __shared__ uint32_t s_input_idx[][kSMEM / (2 * sizeof(int32_t))];
|
extern __shared__ uint32_t s_input_idx[][kSMEM / (2 * sizeof(int32_t))];
|
||||||
|
|
||||||
const uint32_t tx = threadIdx.x;
|
const uint32_t tx = threadIdx.x;
|
||||||
uint32_t remain_topk = kTopK;
|
uint32_t remain_topk = topk;
|
||||||
auto& s_histogram = _s_histogram_buf[0];
|
auto& s_histogram = _s_histogram_buf[0];
|
||||||
|
|
||||||
const auto run_cumsum = [&] {
|
const auto run_cumsum = [&] {
|
||||||
@@ -208,7 +217,7 @@ SGL_DEVICE void radix_topk(const float* __restrict__ input, int32_t* __restrict_
|
|||||||
if (round == 3) {
|
if (round == 3) {
|
||||||
const auto pos = ::atomicAdd(&s_last_remain, -1);
|
const auto pos = ::atomicAdd(&s_last_remain, -1);
|
||||||
if (pos > 0) {
|
if (pos > 0) {
|
||||||
output[kTopK - pos] = idx;
|
output[topk - pos] = idx;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const auto pos = ::atomicAdd(&s_num_input[r_idx ^ 1], 1);
|
const auto pos = ::atomicAdd(&s_num_input[r_idx ^ 1], 1);
|
||||||
@@ -231,7 +240,7 @@ template <bool kUsePDL>
|
|||||||
__global__ void topk_transform_kernel(const __grid_constant__ TopKParams params) {
|
__global__ void topk_transform_kernel(const __grid_constant__ TopKParams params) {
|
||||||
const auto &[
|
const auto &[
|
||||||
scores, seq_lens, page_table, page_indices, raw_indices, // pointers
|
scores, seq_lens, page_table, page_indices, raw_indices, // pointers
|
||||||
score_stride, page_table_stride, page_bits // sizes
|
score_stride, page_table_stride, page_bits, topk // sizes
|
||||||
] = params;
|
] = params;
|
||||||
const uint32_t work_id = blockIdx.x;
|
const uint32_t work_id = blockIdx.x;
|
||||||
|
|
||||||
@@ -239,19 +248,18 @@ __global__ void topk_transform_kernel(const __grid_constant__ TopKParams params)
|
|||||||
const uint32_t seq_len = seq_lens[work_id];
|
const uint32_t seq_len = seq_lens[work_id];
|
||||||
const auto score_ptr = scores + work_id * score_stride;
|
const auto score_ptr = scores + work_id * score_stride;
|
||||||
const auto page_ptr = page_table + work_id * page_table_stride;
|
const auto page_ptr = page_table + work_id * page_table_stride;
|
||||||
const auto indices_ptr = page_indices + work_id * kTopK;
|
const auto indices_ptr = page_indices + work_id * topk;
|
||||||
const auto raw_indices_ptr = raw_indices != nullptr ? raw_indices + work_id * kTopK : nullptr;
|
const auto raw_indices_ptr = raw_indices != nullptr ? raw_indices + work_id * topk : nullptr;
|
||||||
|
|
||||||
device::PDLWaitPrimary<kUsePDL>();
|
device::PDLWaitPrimary<kUsePDL>();
|
||||||
|
|
||||||
if (seq_len <= kTopK) {
|
if (seq_len <= topk) {
|
||||||
naive_transform(score_ptr, page_ptr, indices_ptr, raw_indices_ptr, seq_len, page_bits);
|
naive_transform(score_ptr, page_ptr, indices_ptr, raw_indices_ptr, seq_len, page_bits, topk);
|
||||||
} else {
|
} else {
|
||||||
__shared__ int32_t s_topk_indices[kTopK];
|
__shared__ int32_t s_topk_indices[kMaxTopK];
|
||||||
radix_topk(score_ptr, s_topk_indices, seq_len);
|
radix_topk(score_ptr, s_topk_indices, seq_len, topk);
|
||||||
static_assert(kTopK <= kTopKBlockSize);
|
|
||||||
const auto tx = threadIdx.x;
|
const auto tx = threadIdx.x;
|
||||||
if (kTopK == kTopKBlockSize || tx < kTopK) {
|
if (tx < topk) {
|
||||||
indices_ptr[tx] = page_to_indices(page_ptr, s_topk_indices[tx], page_bits);
|
indices_ptr[tx] = page_to_indices(page_ptr, s_topk_indices[tx], page_bits);
|
||||||
if (raw_indices_ptr != nullptr) {
|
if (raw_indices_ptr != nullptr) {
|
||||||
raw_indices_ptr[tx] = s_topk_indices[tx];
|
raw_indices_ptr[tx] = s_topk_indices[tx];
|
||||||
@@ -287,6 +295,7 @@ struct TopKKernel {
|
|||||||
auto B = SymbolicSize{"batch_size"};
|
auto B = SymbolicSize{"batch_size"};
|
||||||
auto S = SymbolicSize{"score_stride"};
|
auto S = SymbolicSize{"score_stride"};
|
||||||
auto P = SymbolicSize{"page_table_stride"};
|
auto P = SymbolicSize{"page_table_stride"};
|
||||||
|
auto K = SymbolicSize{"topk"};
|
||||||
auto device = SymbolicDevice{};
|
auto device = SymbolicDevice{};
|
||||||
device.set_options<kDLCUDA>();
|
device.set_options<kDLCUDA>();
|
||||||
|
|
||||||
@@ -304,14 +313,14 @@ struct TopKKernel {
|
|||||||
.with_dtype<int32_t>()
|
.with_dtype<int32_t>()
|
||||||
.with_device(device)
|
.with_device(device)
|
||||||
.verify(page_table);
|
.verify(page_table);
|
||||||
TensorMatcher({B, kTopK}) // output, must be contiguous
|
TensorMatcher({B, K}) // output, must be contiguous
|
||||||
.with_dtype<int32_t>()
|
.with_dtype<int32_t>()
|
||||||
.with_device(device)
|
.with_device(device)
|
||||||
.verify(page_indices);
|
.verify(page_indices);
|
||||||
|
|
||||||
int32_t* raw_indices_ptr = nullptr;
|
int32_t* raw_indices_ptr = nullptr;
|
||||||
if (raw_indices.has_value()) {
|
if (raw_indices.has_value()) {
|
||||||
TensorMatcher({B, kTopK}) // optional raw indices output, must be contiguous
|
TensorMatcher({B, K}) // optional raw indices output, must be contiguous
|
||||||
.with_dtype<int32_t>()
|
.with_dtype<int32_t>()
|
||||||
.with_device(device)
|
.with_device(device)
|
||||||
.verify(raw_indices.value());
|
.verify(raw_indices.value());
|
||||||
@@ -321,6 +330,8 @@ struct TopKKernel {
|
|||||||
RuntimeCheck(std::has_single_bit(page_size), "page_size must be power of 2");
|
RuntimeCheck(std::has_single_bit(page_size), "page_size must be power of 2");
|
||||||
const auto page_bits = static_cast<uint32_t>(std::countr_zero(page_size));
|
const auto page_bits = static_cast<uint32_t>(std::countr_zero(page_size));
|
||||||
const auto batch_size = static_cast<uint32_t>(B.unwrap());
|
const auto batch_size = static_cast<uint32_t>(B.unwrap());
|
||||||
|
const auto topk = static_cast<uint32_t>(K.unwrap());
|
||||||
|
RuntimeCheck(topk > 0 && topk <= kMaxTopK, "topk must be in (0, 1024]");
|
||||||
const auto params = TopKParams{
|
const auto params = TopKParams{
|
||||||
.scores = static_cast<float*>(scores.data_ptr()),
|
.scores = static_cast<float*>(scores.data_ptr()),
|
||||||
.seq_lens = static_cast<int32_t*>(seq_lens.data_ptr()),
|
.seq_lens = static_cast<int32_t*>(seq_lens.data_ptr()),
|
||||||
@@ -330,6 +341,7 @@ struct TopKKernel {
|
|||||||
.score_stride = S.unwrap(),
|
.score_stride = S.unwrap(),
|
||||||
.page_table_stride = P.unwrap(),
|
.page_table_stride = P.unwrap(),
|
||||||
.page_bits = page_bits,
|
.page_bits = page_bits,
|
||||||
|
.topk = topk,
|
||||||
};
|
};
|
||||||
constexpr auto kSMEM_ = kSMEM + sizeof(int32_t); // align up a little
|
constexpr auto kSMEM_ = kSMEM + sizeof(int32_t); // align up a little
|
||||||
setup_kernel_smem_once<kernel, kSMEM_>();
|
setup_kernel_smem_once<kernel, kSMEM_>();
|
||||||
|
|||||||
@@ -215,24 +215,32 @@ CLUSTER_TOPK_KERNEL void topk_small_batch_kernel(const __grid_constant__ TopKLau
|
|||||||
|
|
||||||
// for small batch, we will fuse in the cluster case
|
// for small batch, we will fuse in the cluster case
|
||||||
if (problem.seq_len <= kReg4MaxSeqLen) {
|
if (problem.seq_len <= kReg4MaxSeqLen) {
|
||||||
if (blockIdx.y == worker_rank) Register4::forward<kPDL>(problem, &smem);
|
if (blockIdx.y != worker_rank) return;
|
||||||
} else if (problem.seq_len <= params.cluster_floor) {
|
Register4::forward<kPDL>(problem, &smem);
|
||||||
if (blockIdx.y == worker_rank) Streaming::forward<kPDL>(problem, &smem);
|
|
||||||
} else {
|
|
||||||
auto cluster = cooperative_groups::this_cluster();
|
|
||||||
// The mapped alias stays in a copy: the elected rank reads the very same
|
|
||||||
// bytes back through `topk_indices` below, and letting a shared::cluster
|
|
||||||
// address reach the `problem.out` that problem_transform loads makes cicc
|
|
||||||
// segfault on CUDA 13.x (issue #32830).
|
|
||||||
auto peer_problem = problem;
|
|
||||||
peer_problem.out = cluster.map_shared_rank(topk_indices, worker_rank);
|
|
||||||
Cluster::forward<kPDL>(peer_problem, &smem); // write to peer's output shared memory
|
|
||||||
cluster.sync();
|
|
||||||
}
|
|
||||||
|
|
||||||
device::PDLWaitPrimary<kPDL>();
|
device::PDLWaitPrimary<kPDL>();
|
||||||
__syncthreads();
|
__syncthreads();
|
||||||
if (blockIdx.y == worker_rank) problem_transform(problem, params.get_output_ptr(blockIdx.x));
|
} else if (problem.seq_len <= params.cluster_floor) {
|
||||||
|
if (blockIdx.y != worker_rank) return;
|
||||||
|
Streaming::forward<kPDL>(problem, &smem);
|
||||||
|
device::PDLWaitPrimary<kPDL>();
|
||||||
|
__syncthreads();
|
||||||
|
} else {
|
||||||
|
auto cluster = cooperative_groups::this_cluster();
|
||||||
|
problem.out = cluster.map_shared_rank(topk_indices, worker_rank);
|
||||||
|
Cluster::forward<kPDL>(problem, &smem); // write to peer's output shared memory
|
||||||
|
device::PDLWaitPrimary<kPDL>();
|
||||||
|
cluster.sync();
|
||||||
|
if (blockIdx.y != worker_rank) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only the elected worker reaches here, and it mapped `topk_indices` to
|
||||||
|
// itself, so `problem.out` is this block's own buffer. Stating that keeps the
|
||||||
|
// shared::cluster address out of the load problem_transform issues -- which is
|
||||||
|
// load-bearing, not an optimization: without it cicc segfaults on CUDA 13.1+
|
||||||
|
// for sm_90a (issue #32830, previously worked around by copying `problem` in
|
||||||
|
// #32910). Verified: dropping this line reproduces the crash on 13.1/13.2/13.3.
|
||||||
|
__builtin_assume(problem.out == topk_indices);
|
||||||
|
problem_transform(problem, params.get_output_ptr(blockIdx.x));
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Plan: choose cluster_threshold from the seq_len distribution -----------
|
// --- Plan: choose cluster_threshold from the seq_len distribution -----------
|
||||||
|
|||||||
@@ -776,15 +776,27 @@ struct TopKCluster : TopKRadixBase<10> {
|
|||||||
const auto threshold_bin = smem->threshold_bin;
|
const auto threshold_bin = smem->threshold_bin;
|
||||||
const float v_hi = coarse_bin_lower_bound<kHistBits>(threshold_bin + 1);
|
const float v_hi = coarse_bin_lower_bound<kHistBits>(threshold_bin + 1);
|
||||||
const float v_lo = coarse_bin_lower_bound<kHistBits>(threshold_bin);
|
const float v_lo = coarse_bin_lower_bound<kHistBits>(threshold_bin);
|
||||||
const auto cur_out = is_primary ? problem.out : smem->tmp_out;
|
|
||||||
|
// Phase 3: collect candidates. The primary scatters straight into
|
||||||
|
// `problem.out`, the others stage into block-local `smem->tmp_out`.
|
||||||
|
//
|
||||||
|
// DO NOT merge these two loops back into one by selecting the destination
|
||||||
|
// first (`cur_out = is_primary ? problem.out : smem->tmp_out`). `problem.out`
|
||||||
|
// can be a shared::cluster (DSMEM) alias of the elected rank's buffer while
|
||||||
|
// `tmp_out` is shared::cta; merging them into a single pointer variable makes
|
||||||
|
// cicc 13.1+ mis-lower the block-local arm on sm_90a and *silently drop every
|
||||||
|
// non-primary rank's staged output* -- `tmp_out` stays zero, and phase 3.5
|
||||||
|
// then faithfully copies zeros to correct DSMEM addresses. The result is a
|
||||||
|
// top-k output where only the primary's slots and the handle_tie tail are
|
||||||
|
// valid, which downstream sparse attention dereferences as garbage KV indices.
|
||||||
|
if (!is_primary) {
|
||||||
|
// stage to tmp_out first before writing to global/DSMEM
|
||||||
for_each_input(problem.in, local_seq_len, [&](float val, uint32_t local_idx) {
|
for_each_input(problem.in, local_seq_len, [&](float val, uint32_t local_idx) {
|
||||||
const auto idx = chunk_start + local_idx;
|
const auto idx = chunk_start + local_idx;
|
||||||
if (val >= v_hi) {
|
if (val >= v_hi) {
|
||||||
const auto pos = atomicAdd(&smem->count_gt, 1);
|
const auto pos = atomicAdd(&smem->count_gt, 1);
|
||||||
if (pos < topk) [[likely]] {
|
if (pos < topk) [[likely]] {
|
||||||
// rank 0's slots [0, a0) are final; other ranks stage raw indices and
|
smem->tmp_out[pos] = idx;
|
||||||
// page-translate them after the cross-rank prefix sum is known.
|
|
||||||
cur_out[pos] = idx;
|
|
||||||
}
|
}
|
||||||
} else if (val >= v_lo) {
|
} else if (val >= v_lo) {
|
||||||
const auto count_eq = atomicAdd(&smem->count_eq, 1);
|
const auto count_eq = atomicAdd(&smem->count_eq, 1);
|
||||||
@@ -793,11 +805,6 @@ struct TopKCluster : TopKRadixBase<10> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Phase 3.5: write tmp out and exit for non-primary blocks
|
|
||||||
uint32_t start_write = 0;
|
|
||||||
uint32_t num_write = 0;
|
|
||||||
if (!is_primary) {
|
|
||||||
__syncthreads();
|
__syncthreads();
|
||||||
const auto local_above_count = smem->count_gt;
|
const auto local_above_count = smem->count_gt;
|
||||||
const auto local_equal_count = min(smem->count_eq, kMaxNumTie);
|
const auto local_equal_count = min(smem->count_eq, kMaxNumTie);
|
||||||
@@ -818,12 +825,11 @@ struct TopKCluster : TopKRadixBase<10> {
|
|||||||
smem_0->tie.values[start_eq_local + t] = smem->tie.values[t];
|
smem_0->tie.values[start_eq_local + t] = smem->tie.values[t];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
start_write = start_gt_local;
|
|
||||||
num_write = local_above_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
cluster.sync();
|
cluster.sync();
|
||||||
if (!is_primary) {
|
|
||||||
|
const auto start_write = start_gt_local;
|
||||||
|
const auto num_write = local_above_count;
|
||||||
#pragma unroll
|
#pragma unroll
|
||||||
for (uint32_t i = 0; i < kTopKItems; ++i) {
|
for (uint32_t i = 0; i < kTopKItems; ++i) {
|
||||||
if (const auto t = tx + i * kBlockSize; t < num_write && start_write + t < topk) {
|
if (const auto t = tx + i * kBlockSize; t < num_write && start_write + t < topk) {
|
||||||
@@ -831,6 +837,23 @@ struct TopKCluster : TopKRadixBase<10> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
for_each_input(problem.in, local_seq_len, [&](float val, uint32_t local_idx) {
|
||||||
|
const auto idx = chunk_start + local_idx;
|
||||||
|
if (val >= v_hi) {
|
||||||
|
const auto pos = atomicAdd(&smem->count_gt, 1);
|
||||||
|
if (pos < topk) [[likely]] {
|
||||||
|
problem.emit(pos, idx);
|
||||||
|
}
|
||||||
|
} else if (val >= v_lo) {
|
||||||
|
const auto count_eq = atomicAdd(&smem->count_eq, 1);
|
||||||
|
if (count_eq < kMaxNumTie) [[likely]] {
|
||||||
|
smem->tie.values[count_eq] = {val, idx};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
cluster.sync();
|
||||||
|
|
||||||
// Phase 4: Handle ties.
|
// Phase 4: Handle ties.
|
||||||
const auto above_count = smem->count_gt;
|
const auto above_count = smem->count_gt;
|
||||||
const auto equal_count = smem->count_eq;
|
const auto equal_count = smem->count_eq;
|
||||||
|
|||||||
@@ -16,15 +16,18 @@ from .utils import make_name
|
|||||||
|
|
||||||
|
|
||||||
@cache_once
|
@cache_once
|
||||||
def _jit_topk_v1_module(topk: int):
|
def _jit_topk_v1_module():
|
||||||
|
# topk (<= 1024) is a runtime argument, not a compile-time constant, so a
|
||||||
|
# single module serves every k. Baking it in via -DSGL_TOPK used to build one
|
||||||
|
# module per k, and since the macro fed a `constexpr` rather than a template
|
||||||
|
# parameter every module exported identically mangled symbols -- see the
|
||||||
|
# comment in topk_v1.cuh for how that broke the second module's launch.
|
||||||
args = make_cpp_args(is_arch_support_pdl())
|
args = make_cpp_args(is_arch_support_pdl())
|
||||||
assert topk in (512, 1024), "Only support topk=512 or 1024"
|
|
||||||
return load_jit(
|
return load_jit(
|
||||||
make_name(f"topk_v1_{topk}"),
|
make_name("topk_v1"),
|
||||||
*args,
|
*args,
|
||||||
cuda_files=["deepseek_v4/topk_v1.cuh"],
|
cuda_files=["deepseek_v4/topk_v1.cuh"],
|
||||||
cuda_wrappers=[("topk_transform", f"TopKKernel<{args}>::transform")],
|
cuda_wrappers=[("topk_transform", f"TopKKernel<{args}>::transform")],
|
||||||
extra_cuda_cflags=[f"-DSGL_TOPK={topk}"],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -55,7 +58,7 @@ def topk_transform_512(
|
|||||||
scores, seq_lens, page_tables, out_page_indices, page_size, out_raw_indices
|
scores, seq_lens, page_tables, out_page_indices, page_size, out_raw_indices
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
module = _jit_topk_v1_module(out_page_indices.shape[1])
|
module = _jit_topk_v1_module()
|
||||||
module.topk_transform(
|
module.topk_transform(
|
||||||
scores, seq_lens, page_tables, out_page_indices, page_size, out_raw_indices
|
scores, seq_lens, page_tables, out_page_indices, page_size, out_raw_indices
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user