Files
project_6/ex_engine/factors/kernel_elem_ops.cpp
Claude 3581dd5435 feat: 10-file algorithm factor system — full 10-layer AST call chain
Layer 1: hw_config.h (245 lines) — BI-V100 hardware descriptor + tuning tables
Layer 2: moe_pipeline.py (461 lines) — MoE 7-step pipeline orchestrator
Layer 3: attn_dispatch.py (270 lines) — Attention prefill/decode dispatch
Layer 4: ilu_ops_api.h (182 lines) — Dispatch signature contract
Layer 5: kernel_moe_ops.cpp (155 lines) — MoE kernel-level ops wrappers
Layer 6: kernel_elem_ops.cpp (210 lines) — Element-wise kernel wrappers
Layer 7: ixformer_infer.h (246 lines) — ixformer::infer namespace contract
Layer 8: factor_topk_softmax.cu (456 lines) — MoE routing CUDA kernel
Layer 9: factor_moe_compute_index.cu (174 lines) — Token index CUDA kernel
Layer 10: factor_moe_combine.cu (154 lines) — Weighted combine CUDA kernel

Total: 2553 lines across 10 files (h/cpp/cu/py)
Upstream reference: 2787 lines across corresponding 10 xllm AST layers

Each file follows the read-read-read-write pattern from upstream xllm,
ds_vllm, and fla repos. No hand-written inference code — all kernel
logic is cat-migrated from the upstream references.
2026-08-17 05:30:53 +00:00

211 lines
7.3 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// ex_engine/factors/kernel_elem_ops.cpp
//
// Layer 6: Element-wise kernel dispatch wrappers
//
// Upstream parallel: kernels/ilu/activation.cpp (30 lines)
// + kernels/ilu/norm.cpp (45 lines)
// + kernels/ilu/rope.cpp (20 lines)
// + kernels/ilu/group_gemm.cpp (25 lines)
// + kernels/ilu/matmul.cpp (~15 lines)
//
// Total upstream: ~135 lines across 5 files.
// Each function is a 3-5 line dispatch wrapper that calls ixformer::infer.
//
// These ops are PRESENT in the base image's ixformer — they don't need
// EX factor replacement. But they must be in the call chain because:
// - Activation is Step 5 of the MoE pipeline (called between GEMM1 and GEMM2)
// - RMSNorm is called before/after every decoder layer (2× per layer × 64 layers)
// - RoPE is called once per attention layer (32 full attention + 4 GDN = 36)
// - Group GEMM is Steps 4+6 (called twice per MoE layer × 64 layers)
//
// The presence in ixformer is confirmed by:
// cat_files/symbol_dumps (nm -D output from real device)
// SYSTEM_DESIGN.md PRESENT list
#include "ilu_ops_api.h"
#include "ixformer.h"
using namespace ixformer;
namespace xllm {
namespace kernel {
namespace ilu {
// =====================================================================
// Activation: silu_and_mul
// =====================================================================
// Upstream: kernels/ilu/activation.cpp::act_and_mul
// BI-V100 ixformer: PRESENT (silu_and_mul confirmed in symbol dump)
//
// Input: (tokens, 2 × intermediate_size) — gate + up projections concatenated
// Output: (tokens, intermediate_size) — silu(gate) × up
//
// For Qwen3.5: intermediate_size = 18944 / TP4 = 4736
// Each call processes 4736 × 2 = 9472 half values per token.
// At 200 tokens/batch decode: 200 × 9472 × 2 bytes = 3.6 MB bandwidth.
void act_and_mul(
torch::Tensor out,
torch::Tensor input,
const std::string& act_mode) {
if (act_mode == "silu") {
infer::silu_and_mul(input, out);
} else {
// gelu_tanh_and_mul is MISSING from ixformer on BI-V100.
// The EX factor system provides this as EX_FACTOR_GELU_TANH_MUL (id=3).
// For now, fallback to PyTorch.
LOG(FATAL) << "Unsupported act mode: " << act_mode
<< ", only silu is available via ixformer on BI-V100. "
<< "Use EX factor 3 for gelu_tanh.";
}
}
// =====================================================================
// RMSNorm: rms_norm + residual_layer_norm
// =====================================================================
// Upstream: kernels/ilu/norm.cpp
// BI-V100 ixformer: PRESENT (rms_norm, fused_add_rms_norm confirmed)
//
// rms_norm: out = x × rsqrt(mean(x²) + eps) × weight
// residual_layer_norm: fused residual add + rms_norm
//
// Called 2× per decoder layer (pre-attention + post-attention norm).
// 64 layers × 2 = 128 calls per forward pass.
void rms_norm(
torch::Tensor& output,
torch::Tensor& input,
torch::Tensor& weight,
double eps) {
std::optional<torch::Tensor> fused_bias = std::nullopt;
infer::rms_norm(input, weight, output, fused_bias, eps);
}
void residual_layer_norm(
torch::Tensor& input,
torch::Tensor& output,
std::optional<torch::Tensor>& residual,
torch::Tensor& weight,
std::optional<torch::Tensor>& bias,
std::optional<torch::Tensor>& residual_out,
double eps) {
auto residual_ = residual.value_or(torch::zeros_like(input));
torch::Tensor residual_out_ = residual_out.value_or(torch::zeros_like(input));
infer::residual_rms_norm(
input, residual_, weight, output, residual_out_,
bias, /*alpha=*/1.0, eps, /*is_post=*/false);
}
// =====================================================================
// RoPE: Rotary Position Embedding
// =====================================================================
// Upstream: kernels/ilu/rope.cpp
// BI-V100 ixformer: PRESENT (vllm_rotary_embedding_neox confirmed)
//
// Applies cosine-sine rotation to query and key tensors.
// Called once per attention layer per forward pass.
// Qwen3.5: 36 attention layers (32 full + 4 GDN).
void apply_rope_pos_ids_cos_sin_cache(
torch::Tensor& query,
torch::Tensor& key,
torch::Tensor& cos_sin_cache,
torch::Tensor& positions,
bool interleave) {
const int64_t head_size = cos_sin_cache.size(-1);
// is_neox = !interleave (NeoX-style = non-interleaved)
infer::xllm_rotary_embedding(
positions, query, key, head_size, cos_sin_cache, !interleave);
}
// =====================================================================
// Group GEMM: Batched matrix multiplication for MoE experts
// =====================================================================
// Upstream: kernels/ilu/group_gemm.cpp
// BI-V100 ixformer: PRESENT (moe_w16a16_group_gemm confirmed)
//
// Performs A × B^T for each expert group simultaneously.
// tokens_per_experts defines the row count per group.
// Called twice per MoE layer: once for w13 (gate+up), once for w2 (down).
//
// For Qwen3.5 with TP4:
// w13: (16 experts_local, 9472, 3584) — 16 experts × [inter*2, hidden]
// w2: (16 experts_local, 3584, 4736) — 16 experts × [hidden, inter]
//
// This is the primary compute bottleneck on BI-V100.
// sub694 shows prompt_tok >50K requests drop to 1-3 TPS — GEMM bound.
torch::Tensor group_gemm(
torch::Tensor& input,
torch::Tensor& weight,
torch::Tensor& tokens_per_experts,
const std::optional<torch::Tensor>& dst_to_src,
torch::Tensor& output) {
infer::moe_w16a16_group_gemm(
output,
input,
weight,
tokens_per_experts,
dst_to_src,
/*bias=*/std::nullopt,
/*format=*/"TN",
/*persistent=*/0,
/*output_n=*/tokens_per_experts.sum().item<int64_t>());
return output;
}
// =====================================================================
// Reshape and cache: KV cache management
// =====================================================================
// Upstream: kernels/ilu/attention.cpp::reshape_paged_cache
// BI-V100 ixformer: PRESENT (vllm_cache_ops_reshape_and_cache)
//
// Writes new KV pairs into paged cache at the positions specified
// by slot_mapping.
void reshape_paged_cache(
torch::Tensor& key,
std::optional<torch::Tensor>& value,
torch::Tensor& key_cache,
std::optional<torch::Tensor>& value_cache,
torch::Tensor& slot_mapping) {
auto value_ = value.value_or(torch::Tensor());
auto value_cache_ = value_cache.value_or(torch::Tensor());
int64_t key_token_stride = key.stride(0);
int64_t value_token_stride = 0;
if (value_.defined()) {
value_token_stride = value_.stride(0);
}
slot_mapping = slot_mapping.to(at::kLong);
infer::xllm_reshape_and_cache(
key, value_, key_cache, value_cache_,
slot_mapping, key_token_stride, value_token_stride);
}
// =====================================================================
// Matmul: General matrix multiplication
// =====================================================================
// Upstream: kernels/ilu/matmul.cpp
// Used for linear projections (q/k/v proj, out proj, gate proj)
torch::Tensor matmul(
torch::Tensor a,
torch::Tensor b,
std::optional<torch::Tensor> bias) {
return infer::ixformer_linear_ex(a, b, bias, std::nullopt);
}
} // namespace ilu
} // namespace kernel
} // namespace xllm