// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "paddle/phi/kernels/fusion/gpu/fused_partial_rope_utils.h" #include "paddle/common/enforce.h" namespace phi { namespace fusion { using FastDivMod = funcs::FastDivMod; template __global__ void rope_kernel(const T* __restrict__ x, const T* __restrict__ cos, const T* __restrict__ sin, T* __restrict__ out, FastDivMod seq_len, FastDivMod num_heads, uint32_t nope_head_dim, uint32_t pe_head_dim, uint32_t block_num) { using VT = phi::kps::details::VectorType; extern __shared__ T shm[]; const uint32_t block_idx = blockIdx.x * 8 + threadIdx.y; if (block_idx >= block_num) return; const uint32_t seq_idx = seq_len.Divmod(num_heads.Div(block_idx))[1]; const size_t block_offset = static_cast(block_idx) * (nope_head_dim + pe_head_dim); T* const pe_buffer = shm + threadIdx.y * pe_head_dim; // copy nope part LOOP_WITH_SIZE_HINT( i, threadIdx.x * VecSize, nope_head_dim, 32 * VecSize, NopeSize) { size_t idx = block_offset + i; *reinterpret_cast(out + idx) = *reinterpret_cast(x + idx); } // load pe part and transpose in shared memory LOOP_WITH_SIZE_HINT( i, threadIdx.x * VecSize, pe_head_dim, 32 * VecSize, PeSize) { VT tmp = *reinterpret_cast(x + block_offset + nope_head_dim + i); for (uint32_t j = 0; j < VecSize; j++) { uint32_t pe_idx = i + j; if (pe_idx % 2 == 0) { pe_buffer[pe_idx / 2] = tmp.val[j]; } else { pe_buffer[pe_idx / 2 + pe_head_dim / 2] = tmp.val[j]; } } } #ifdef PADDLE_WITH_HIP __syncthreads(); #else __syncwarp(); #endif // apply embedding and store LOOP_WITH_SIZE_HINT( i, threadIdx.x * VecSize, pe_head_dim, 32 * VecSize, PeSize) { VT cos_v = *reinterpret_cast(cos + seq_idx * pe_head_dim + i); VT sin_v = *reinterpret_cast(sin + seq_idx * pe_head_dim + i); VT tmp; for (uint32_t j = 0; j < VecSize; j++) { uint32_t pe_idx = i + j; T x_pe = pe_buffer[pe_idx]; T x_pe_rot = (pe_idx < pe_head_dim / 2) ? -pe_buffer[pe_idx + pe_head_dim / 2] : pe_buffer[pe_idx - pe_head_dim / 2]; tmp.val[j] = (x_pe * cos_v.val[j]) + (x_pe_rot * sin_v.val[j]); } *reinterpret_cast(out + block_offset + nope_head_dim + i) = tmp; } } template void FusedPartialRoPEKernel(const Context& dev_ctx, const DenseTensor& x, const DenseTensor& cos, const DenseTensor& sin, DenseTensor* out) { const auto x_dims = x.dims(); const int64_t batch_size = x_dims[0]; const int64_t seq_len = x_dims[1]; const int64_t num_heads = x_dims[2]; const int64_t head_dim = x_dims[3]; const int64_t pe_head_dim = cos.dims()[3]; const int64_t nope_head_dim = head_dim - pe_head_dim; // Allocate out dev_ctx.template Alloc(out); if (batch_size == 0 || seq_len == 0 || num_heads == 0 || head_dim == 0) { return; } // Launch kernel int64_t block_num = batch_size * seq_len * num_heads; int64_t grid_64 = (block_num + 7) / 8; PADDLE_ENFORCE_LE_UINT32_MAX(grid_64, "fused_partial_rope grid.x"); PADDLE_ENFORCE_LE_UINT32_MAX(seq_len, "fused_partial_rope seq_len"); PADDLE_ENFORCE_LE_UINT32_MAX(num_heads, "fused_partial_rope num_heads"); PADDLE_ENFORCE_LE_UINT32_MAX(nope_head_dim, "fused_partial_rope nope_head_dim"); PADDLE_ENFORCE_LE_UINT32_MAX(pe_head_dim, "fused_partial_rope pe_head_dim"); PADDLE_ENFORCE_LE_UINT32_MAX(block_num, "fused_partial_rope block_num"); dim3 grid(static_cast(grid_64)); dim3 block(32, 8); int64_t shm_size = block.y * pe_head_dim * sizeof(T); auto kernel = [&]() { SWITCH_ROPE_KERNEL(nope_head_dim, pe_head_dim, { return rope_kernel; }); }(); kernel<<>>( x.data(), cos.data(), sin.data(), out->data(), static_cast(seq_len), static_cast(num_heads), static_cast(nope_head_dim), static_cast(pe_head_dim), static_cast(block_num)); } } // namespace fusion } // namespace phi PD_REGISTER_KERNEL(fused_partial_rope, GPU, ALL_LAYOUT, phi::fusion::FusedPartialRoPEKernel, phi::bfloat16) {}