From a3b1e8ef3db0075915c5869a9c2eebfd5ffdba22 Mon Sep 17 00:00:00 2001 From: DarkSharpness <76582120+DarkSharpness@users.noreply.github.com> Date: Thu, 1 Jan 2026 21:40:05 +0800 Subject: [PATCH] [Feature] add aligned_vector type for JIT kernel (#16162) --- python/sglang/jit_kernel/csrc/hicache.cuh | 5 ++ python/sglang/jit_kernel/csrc/norm.cuh | 23 ++--- .../include/sgl_kernel/source_location.h | 34 +++++++ .../jit_kernel/include/sgl_kernel/utils.cuh | 5 -- .../jit_kernel/include/sgl_kernel/utils.h | 10 +-- .../jit_kernel/include/sgl_kernel/vec.cuh | 89 +++++++++++++++++++ .../jit_kernel/include/sgl_kernel/warp.cuh | 21 ++++- 7 files changed, 165 insertions(+), 22 deletions(-) create mode 100644 python/sglang/jit_kernel/include/sgl_kernel/source_location.h create mode 100644 python/sglang/jit_kernel/include/sgl_kernel/vec.cuh diff --git a/python/sglang/jit_kernel/csrc/hicache.cuh b/python/sglang/jit_kernel/csrc/hicache.cuh index e86fe9973..230e4d513 100644 --- a/python/sglang/jit_kernel/csrc/hicache.cuh +++ b/python/sglang/jit_kernel/csrc/hicache.cuh @@ -12,6 +12,11 @@ namespace device::warp { +template +struct device_vec { + T data[N]; +}; + namespace details { template diff --git a/python/sglang/jit_kernel/csrc/norm.cuh b/python/sglang/jit_kernel/csrc/norm.cuh index 0f9e7ac53..c5e369df4 100644 --- a/python/sglang/jit_kernel/csrc/norm.cuh +++ b/python/sglang/jit_kernel/csrc/norm.cuh @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -9,6 +10,7 @@ #include #include +#include #include #include @@ -52,18 +54,17 @@ template __always_inline __device__ void apply_norm(void* __restrict__ input, const void* __restrict__ weight, float eps) { using namespace device; - constexpr auto kLoopCount = kHeadDim / (kWarpThreads * 2); + constexpr std::size_t kLoopCount = kHeadDim / (kWarpThreads * 2); static_assert(kHeadDim % (kWarpThreads * 2) == 0); - const auto lane_id = threadIdx.x % kWarpThreads; float sum_of_squares = 0.0f; - using vec_t = device_vec; - auto input_vec = static_cast(input)[lane_id]; + using vec_t = aligned_vector; + const auto input_vec = warp::load(input); #pragma unroll for (auto i = 0u; i < kLoopCount; ++i) { - const auto fp16_input = input_vec.data[i]; + const auto fp16_input = input_vec[i]; const auto fp32_input = to_float2(fp16_input); sum_of_squares += fp32_input.x * fp32_input.x; sum_of_squares += fp32_input.y * fp32_input.y; @@ -71,20 +72,20 @@ __always_inline __device__ void apply_norm(void* __restrict__ input, const void* sum_of_squares = warp::reduce_sum(sum_of_squares); const auto norm_factor = rsqrtf(sum_of_squares / kHeadDim + eps); - const auto weight_vec = static_cast(weight)[lane_id]; - + const auto weight_vec = warp::load(weight); vec_t output_vec; + #pragma unroll for (auto i = 0u; i < kLoopCount; ++i) { - const auto fp32_weight = to_float2(weight_vec.data[i]); - const auto fp32_input = to_float2(input_vec.data[i]); - output_vec.data[i] = from_float2({ + const auto fp32_input = to_float2(input_vec[i]); + const auto fp32_weight = to_float2(weight_vec[i]); + output_vec[i] = from_float2({ fp32_input.x * norm_factor * fp32_weight.x, fp32_input.y * norm_factor * fp32_weight.y, }); } - static_cast(input)[lane_id] = output_vec; + warp::store(input, output_vec); } constexpr uint32_t kWarpsPerBlock = 4; diff --git a/python/sglang/jit_kernel/include/sgl_kernel/source_location.h b/python/sglang/jit_kernel/include/sgl_kernel/source_location.h new file mode 100644 index 000000000..9616fa7da --- /dev/null +++ b/python/sglang/jit_kernel/include/sgl_kernel/source_location.h @@ -0,0 +1,34 @@ +#pragma once +#include + +/// NOTE: fallback to a minimal source_location implementation +#if defined(__cpp_lib_source_location) +#include + +using source_location_t = std::source_location; + +#else + +struct source_location_fallback { + public: + static constexpr source_location_fallback current() noexcept { + return source_location_fallback{}; + } + constexpr source_location_fallback() noexcept = default; + constexpr unsigned line() const noexcept { + return 0; + } + constexpr unsigned column() const noexcept { + return 0; + } + constexpr const char* file_name() const noexcept { + return ""; + } + constexpr const char* function_name() const noexcept { + return ""; + } +}; + +using source_location_t = source_location_fallback; + +#endif diff --git a/python/sglang/jit_kernel/include/sgl_kernel/utils.cuh b/python/sglang/jit_kernel/include/sgl_kernel/utils.cuh index 738da6176..8d7da5ee3 100644 --- a/python/sglang/jit_kernel/include/sgl_kernel/utils.cuh +++ b/python/sglang/jit_kernel/include/sgl_kernel/utils.cuh @@ -74,11 +74,6 @@ __always_inline __device__ auto offset(const T* ptr, U... offset) -> const void* } // namespace pointer -template -struct device_vec { - T data[N]; -}; - template __forceinline__ __device__ void PDLWaitPrimary() { #ifndef USE_ROCM diff --git a/python/sglang/jit_kernel/include/sgl_kernel/utils.h b/python/sglang/jit_kernel/include/sgl_kernel/utils.h index 3f59349a5..c3cc7c1e5 100644 --- a/python/sglang/jit_kernel/include/sgl_kernel/utils.h +++ b/python/sglang/jit_kernel/include/sgl_kernel/utils.h @@ -21,16 +21,16 @@ #define consteval constexpr -#include +#include "source_location.h" #undef consteval #pragma pop_macro("__cpp_consteval") #pragma pop_macro("_NODISCARD") #else // __CUDACC__ && CUDA_VERSION > 12010 -#include +#include "source_location.h" #endif #else // no __CUDACC__ -#include +#include "source_location.h" #endif #include @@ -44,8 +44,8 @@ namespace host { -struct DebugInfo : public std::source_location { - DebugInfo(std::source_location loc = std::source_location::current()) : std::source_location(loc) {} +struct DebugInfo : public source_location_t { + DebugInfo(source_location_t loc = source_location_t::current()) : source_location_t(loc) {} }; struct PanicError : public std::runtime_error { diff --git a/python/sglang/jit_kernel/include/sgl_kernel/vec.cuh b/python/sglang/jit_kernel/include/sgl_kernel/vec.cuh new file mode 100644 index 000000000..c0e72c255 --- /dev/null +++ b/python/sglang/jit_kernel/include/sgl_kernel/vec.cuh @@ -0,0 +1,89 @@ +#pragma once +#include +#include + +#include +#include + +namespace device { + +namespace details { + +template +struct uint_trait {}; + +template <> +struct uint_trait<1> { + using type = uint8_t; +}; + +template <> +struct uint_trait<2> { + using type = uint16_t; +}; + +template <> +struct uint_trait<4> { + using type = uint32_t; +}; + +template <> +struct uint_trait<8> { + using type = uint64_t; +}; + +template +using sized_int = typename uint_trait::type; + +} // namespace details + +template +struct alignas(sizeof(T) * N) aligned_storage { + T data[N]; +}; + +template +struct aligned_vector { + private: + /// NOTE: 1. must be pow of two 2. 16 * 8 = 128 byte, which is the max vector size supported by most devices + static_assert((N > 0 && (N & (N - 1)) == 0) && sizeof(T) * N <= 16, "CUDA only support at most 128B vector op"); + using element_t = typename details::sized_int; + using storage_t = aligned_storage; + + public: + template + __forceinline__ __device__ void load(const U* ptr, std::size_t offset = 0) { + static_assert(std::is_same_v || std::is_same_v); + m_storage = reinterpret_cast(ptr)[offset]; + } + template + __forceinline__ __device__ void store(U* ptr, std::size_t offset = 0) const { + static_assert(std::is_same_v || std::is_same_v); + reinterpret_cast(ptr)[offset] = m_storage; + } + __forceinline__ __device__ void fill(T value) { + const auto store_value = *reinterpret_cast(&value); +#pragma unroll + for (std::size_t i = 0; i < N; ++i) { + m_storage.data[i] = store_value; + } + } + + __forceinline__ __device__ auto operator[](std::size_t idx) -> T& { + return reinterpret_cast(&m_storage)[idx]; + } + __forceinline__ __device__ auto operator[](std::size_t idx) const -> T { + return reinterpret_cast(&m_storage)[idx]; + } + __forceinline__ __device__ auto data() -> T* { + return reinterpret_cast(&m_storage); + } + __forceinline__ __device__ auto data() const -> const T* { + return reinterpret_cast(&m_storage); + } + + private: + storage_t m_storage; +}; + +} // namespace device diff --git a/python/sglang/jit_kernel/include/sgl_kernel/warp.cuh b/python/sglang/jit_kernel/include/sgl_kernel/warp.cuh index e18b6bd95..88804b42b 100644 --- a/python/sglang/jit_kernel/include/sgl_kernel/warp.cuh +++ b/python/sglang/jit_kernel/include/sgl_kernel/warp.cuh @@ -1,14 +1,33 @@ #pragma once +#include +#include + +#include // Some warp primitives namespace device::warp { template -__always_inline __device__ T reduce_sum(T val, uint32_t active_mask = 0xffffffff) { +__forceinline__ __device__ T reduce_sum(T val, uint32_t active_mask = 0xffffffff) { #pragma unroll for (int mask = 16; mask > 0; mask >>= 1) val += __shfl_xor_sync(active_mask, val, mask, 32); return val; } +template +__forceinline__ __device__ T load(const void* ptr) { + return static_cast(ptr)[threadIdx.x % kWarpThreads]; +} + +template +__forceinline__ __device__ T load(const T* ptr) { + return static_cast(ptr)[threadIdx.x % kWarpThreads]; +} + +template +__forceinline__ __device__ void store(void* ptr, T val) { + static_cast(ptr)[threadIdx.x % kWarpThreads] = val; +} + } // namespace device::warp