#include #include #include #include #include template __global__ void compute_problem_sizes_w4a8( const int32_t* __restrict__ topk_ids, int32_t* problem_sizes1, int32_t* problem_sizes2, const int topk_length, const int n, const int k) { int expert_id = blockIdx.x; int occurrences = 0; // Optimized: vectorized memory access using int4 for better memory bandwidth // Process vectorized chunks first bool aligned = (reinterpret_cast(topk_ids) % 16 == 0); if (aligned) { const int4* vec_ptr = reinterpret_cast(topk_ids); int vec_length = topk_length / 4; for (int i = threadIdx.x; i < vec_length; i += BLOCK_SIZE) { int4 vec_data = vec_ptr[i]; occurrences += (vec_data.x == expert_id) + (vec_data.y == expert_id) + (vec_data.z == expert_id) + (vec_data.w == expert_id); } for (int i = vec_length * 4 + threadIdx.x; i < topk_length; i += BLOCK_SIZE) { occurrences += (topk_ids[i] == expert_id); } } else { for (int i = threadIdx.x; i < topk_length; i += BLOCK_SIZE) { occurrences += (topk_ids[i] == expert_id); } } using BlockReduce = cub::BlockReduce; __shared__ typename BlockReduce::TempStorage temp_storage; int final_occurrences = BlockReduce(temp_storage).Sum(occurrences); if (threadIdx.x == 0) { problem_sizes1[expert_id * 3] = 2 * n; problem_sizes1[expert_id * 3 + 1] = final_occurrences; problem_sizes1[expert_id * 3 + 2] = k; problem_sizes2[expert_id * 3] = k; problem_sizes2[expert_id * 3 + 1] = final_occurrences; problem_sizes2[expert_id * 3 + 2] = n; } } template __device__ void cumsum_block_scan(const int32_t* __restrict__ input, int32_t* __restrict__ output, int n, int input_stride) { using BlockScan = cub::BlockScan; __shared__ typename BlockScan::TempStorage temp_scan_storage; __shared__ int32_t s_broadcast_val; int tid = threadIdx.x; int32_t base_prefix_sum = 0; const int num_chunks = (n + BLOCK_SIZE - 1) / BLOCK_SIZE; for (int chunk = 0; chunk < num_chunks; chunk++) { const int base_idx = chunk * BLOCK_SIZE; const int index = base_idx + tid; const int32_t val = (index < n) ? input[index * input_stride] : 0; int32_t local_prefix_sum; BlockScan(temp_scan_storage).InclusiveSum(val, local_prefix_sum); const int32_t prefix_sum = local_prefix_sum + base_prefix_sum; if (index < n) { output[index] = prefix_sum; } if (chunk < num_chunks - 1) { if (tid == BLOCK_SIZE - 1) { s_broadcast_val = prefix_sum; } __syncthreads(); base_prefix_sum = s_broadcast_val; } } } template __global__ void compute_expert_offsets_w4a8_kernel( const int32_t* __restrict__ problem_sizes1, int32_t* __restrict__ expert_offsets, int n, int stride) { if (threadIdx.x == 0) { expert_offsets[0] = 0; } cumsum_block_scan(problem_sizes1, expert_offsets + 1, n, stride); } void compute_expert_offsets_w4a8( cudaStream_t stream, const int32_t* problem_sizes1, int32_t* expert_offsets, int n, int stride = 1, int off = 0) { #define compute_expert_offsets_w4a8_call(BLOCK_SIZE) \ compute_expert_offsets_w4a8_kernel \ <<<1, BLOCK_SIZE, 0, stream>>>(problem_sizes1 + off, expert_offsets, n, stride); if (n <= 32) { compute_expert_offsets_w4a8_call(32); } else if (n <= 64) { compute_expert_offsets_w4a8_call(64); } else if (n <= 128) { compute_expert_offsets_w4a8_call(128); } else if (n <= 256) { compute_expert_offsets_w4a8_call(256); } else if (n <= 512) { compute_expert_offsets_w4a8_call(512); } else { compute_expert_offsets_w4a8_call(1024); } #undef compute_expert_offsets_w4a8_call } void get_cutlass_w4a8_moe_mm_data_caller( const torch::Tensor& topk_ids, torch::Tensor& expert_offsets, torch::Tensor& problem_sizes1, torch::Tensor& problem_sizes2, torch::Tensor& input_permutation, torch::Tensor& output_permutation, const int64_t num_experts, const int64_t n, const int64_t k) { auto stream = at::cuda::getCurrentCUDAStream(topk_ids.device().index()); auto options_int32 = torch::TensorOptions().dtype(torch::kInt32).device(topk_ids.device()); constexpr uint64_t BLOCK_SIZE = 512; compute_problem_sizes_w4a8<<>>( static_cast(topk_ids.data_ptr()), static_cast(problem_sizes1.data_ptr()), static_cast(problem_sizes2.data_ptr()), topk_ids.numel(), n, k); compute_expert_offsets_w4a8( stream, static_cast(problem_sizes1.data_ptr()), static_cast(expert_offsets.data_ptr()), num_experts, 3, 1); }