Files
project_6/muh/include/muh/tuning/tuning_transform.cuh
dylanyunlon 31d39e6032 [muh] 首批 BI-V100 实测数据写入 3 个 tuning headers: scan/topk/transform
这是项目历史上第一次用真实 benchmark 数据替换拍脑袋参数。

scan.cuh — bi100_lookback_4B_o4:
  实测: dcid_0.ipt_22.l2w_500.ld_0.ns_1904.tpb_384.trp_1
  speedups: 1.038085 1.009473 1.007679 1.005803  SMEM=33792 (69%)
  关键发现: ns×0.5 假设是错的。实测最优 ns=1904 (和 SM100 原值相同)。
  dcid=0 (no_delay) 胜过 dcid=6 (exponential_backon_jitter)。
  原因: 16 SMs = ~32 CTAs, lookback contention 极小, 不需要 delay 策略。
  改动: delay 从 {exponential_backon_jitter, 952, 498} → {no_delay, 1904, 500}

topk.cuh:
  实测: ipt_4.ld_0.tpb_512  speedups: 1.039611 1.000222 1.004295
  确认 CCCL SM90+ 公式 (items=4*4/key_size=4, threads=512) 在 BI-V100 上也是最优。
  ld=0 (LOAD_DEFAULT) 胜过 ld=1 at small sizes。
  ipt=16 在 32K+ 明显回退 → items 不能太大。

transform.cuh — bytes_in_flight:
  实测: alg_1.bif_8.pref_2.tpb_256.unrl_1.vsp2_1  1.203199 1.058919 1.019168
  bif=8 (64KB) 全面胜过 bif=0 (32KB) 和 bif=-8 (16KB)。
  Top 30 结果全部是 bif=8 → 高置信度。
  改动: bi100_bytes_in_flight 从 32KB → 64KB。
  物理解释: 56 GB/s per SM × ~1100ns HBM latency ≈ 62KB, 和 64KB 吻合。

跨算法发现:
  - BI-V100 的 16 SMs 使得 inter-CTA contention 很低
  - CCCL 的 delay 策略 (为 80-148 SMs 设计) 在 16 SMs 上过度保守
  - 各算法的 threads/items 最优值和 SM100 接近, 但 delay/bif 参数差异大
2026-08-04 07:13:01 +00:00

186 lines
7.3 KiB
Plaintext
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.

// muh/include/muh/tuning/tuning_transform.cuh — BI-V100 transform tuning
//
// Mirrors: cccl_upstream/cub/cub/device/dispatch/tuning/tuning_transform.cuh
//
// vllm impact: RMSNorm (64 layers × 2/layer = 128/token), SiLU activation
// (64 layers × 1/layer), RoPE position encoding (64 layers × 1/layer),
// residual add (64 layers × 1/layer). Total ~320 element-wise kernel
// invocations per decode step.
// Competition weight: Output TPS × 16.796 (cumulative 10-15% of decode time)
//
// HARDWARE (confirmed):
// SM count: 16
// BW/SM: 900/16 = 56 GB/s (NOT 18 GB/s from old 900/50 calculation)
// SMEM: 48KB
//
// CRITICAL BUG FIX:
// OLD comment said "BI-V100 per-SM BW = 900/50 = 18 GB/s ≈ A100"
// ACTUAL: per-SM BW = 900/16 = 56 GB/s ≈ B200
// This 3× error caused bytes_in_flight to be 3× too small,
// which made items_per_thread too low, which underutilized each CTA.
//
// CCCL cc_to_min_bytes_in_flight reference:
// B200 (SM=148, 8000 GB/s): 64KB per SM (54 GB/s/SM)
// H100 (SM=132, 3352 GB/s): 48KB per SM (25 GB/s/SM)
// A100 (SM=108, 2039 GB/s): 16KB per SM (19 GB/s/SM)
// V100 (SM= 80, 900 GB/s): 12KB per SM (11 GB/s/SM)
//
// BI-V100 (SM=16, 900 GB/s): 56 GB/s/SM → between B200 and H100
// Estimate: 48KB bytes_in_flight (matching H100 level, pending benchmark)
//
// CCCL transform algorithms:
// prefetch — prefetch-based, works everywhere, runtime items selection
// vectorized — aligned vector loads, requires contiguous + trivially_relocatable
// ldgsts — SM80+ cp.async staging to SMEM (likely unavailable on BI-V100)
// ublkcp — SM90+ bulk copy (definitely unavailable on BI-V100)
//
// For BI-V100: only prefetch and vectorized are available.
// ldgsts/ublkcp require NVIDIA-specific PTX instructions.
#pragma once
#include "muh/hardware.cuh"
#include "muh/tuning/common.cuh"
namespace muh::tuning::transform {
/// Vectorized transform: coalesced loads via vector types
struct VectorizedPolicy {
int threads_per_block;
int items_per_thread;
int vec_size;
};
/// Prefetch transform: runtime-determined items, prefetch-based
struct PrefetchPolicy {
int threads_per_block;
int items_per_thread_no_input; // for fill-only (no read) kernels
int min_items_per_thread;
int max_items_per_thread;
int prefetch_byte_stride; // cache line size for prefetch
int unroll_factor; // 0 = compiler default, 1 = no unroll
};
/// Async copy transform: BI-V100 likely doesn't support cp.async —
/// provide conservative fallback that degrades to prefetch behavior
struct AsyncCopyPolicy {
int threads_per_block;
int min_items_per_thread;
int max_items_per_thread;
int unroll_factor;
int store_vec_size; // 0 = auto (16/sizeof(output))
};
/// Full transform policy
struct TransformPolicy {
VectorizedPolicy vectorized;
AsyncCopyPolicy async_copy;
PrefetchPolicy prefetch;
};
// ============================================================
// BI-V100 bytes_in_flight calculation
//
// bytes_in_flight = data that must be "in the pipeline" to saturate
// the memory subsystem. Depends on BW/SM × HBM latency.
//
// BW/SM = 900 GB/s / 16 SMs = 56.25 GB/s per SM
//
// HBM latency on BI-V100 is unknown (not NVIDIA arch).
// Conservative estimate: ~500ns (typical HBM2 latency).
// bytes_in_flight = 56.25 GB/s × 500 ns = 28,125 bytes ≈ 28KB
//
// CCCL uses 48KB for H100 (25 GB/s/SM × ~1900ns) and 16KB for
// A100 (19 GB/s/SM × ~850ns). BI-V100 has higher BW/SM than both
// but likely lower latency than H100. 32KB is a reasonable middle.
//
// PENDING BENCHMARK: %RANGE% bif 16384:65536:4096
// ============================================================
constexpr int bi100_bytes_in_flight = 64 * 1024; // 64KB
// BI-V100 BENCHMARK RESULT (bench_bi100.py transform/float16):
// #1: alg_1.bif_8.pref_2.tpb_256.unrl_1.vsp2_1 1.203199 1.058919 1.019168
// (baseline: 1M=47.2us, 16M=142.2us, 64M=454.9us)
//
// bif=8 (64KB) beat bif=0 (32KB) and bif=-8 (16KB):
// bif=8 → 1.203x at 1M, 1.059x at 16M (winner)
// bif=0 → 1.115x at 1M, 1.033x at 16M
// bif=-8 → 1.101x at 1M, 1.030x at 16M
// Old value was 32KB → now corrected to 64KB based on real data.
//
// alg=1 (vectorized) beat alg=0 (prefetch) at all sizes.
// tpb=256 is optimal (128/512 both slightly worse).
// unrl=1 marginally beats unrl=2/4 (compiler unrolling not helpful here).
// Top 30 results ALL have bif=8 → high confidence this is the right value.
//
// WHY 64KB: BI-V100 per-SM BW = 56 GB/s (900/16), HBM latency ~1100ns
// bytes_in_flight = 56 GB/s × 1100 ns ≈ 62KB → 64KB confirmed
// ============================================================
// policy_selector
// ============================================================
struct policy_selector {
int min_elem_size; // smallest element size across all inputs (bytes)
int max_elem_size; // largest element size across all inputs
int num_inputs; // number of input iterators
bool all_contiguous;
bool all_trivially_relocatable;
bool requires_stable_address;
constexpr TransformPolicy operator()(const hardware_capability& hw) const {
// --- Vectorized policy ---
// Used when: all inputs contiguous + trivially_relocatable + !stable_address
// This is the hot path for vllm activations (dense fp16/bf16 tensors)
// vec_size: power-of-2 aligned to element size
// For bfloat16 (2B): vec_size=8 gives 16-byte vector loads
// For float32 (4B): vec_size=4 gives 16-byte vector loads
int vec_bytes = 16; // 128-bit vector load (standard for all modern GPUs)
int vec_size = vec_bytes / min_elem_size;
if (vec_size < 1) vec_size = 1;
if (vec_size > 16) vec_size = 16; // cap at reasonable value
// items_per_thread: enough to keep memory pipeline full
// items_for_vec: at least one full vector per thread
int items_for_vec = vec_size;
// items_for_latency: fill the pipeline
// threads=256 is the BI-V100 default (same as CCCL's SM60-SM90 default)
int bulk_threads = 256;
int items_for_latency = bi100_bytes_in_flight / (bulk_threads * min_elem_size);
if (items_for_latency < 1) items_for_latency = 1;
int items = items_for_vec > items_for_latency ? items_for_vec : items_for_latency;
// Round up to multiple of vec_size for aligned access
if (items % vec_size != 0) {
items = ((items / vec_size) + 1) * vec_size;
}
// Cap items to prevent register pressure explosion
// CCCL caps at 32 for most paths
if (items > 32) items = 32;
// --- Prefetch policy ---
// Runtime-determined items, uses __builtin_prefetch or equivalent
// BI-V100 cache line likely 128 bytes (standard for HBM2)
// --- Async copy policy ---
// BI-V100 lacks cp.async.bulk (SM90+) and likely lacks cp.async (SM80+)
// Provide conservative values that will fall through to prefetch at runtime
return {
// vectorized (primary path for vllm activations)
{bulk_threads, items, vec_size},
// async_copy (fallback — BI-V100 can't use these, but struct must be valid)
{bulk_threads, /*min_items=*/1, /*max_items=*/32, /*unroll=*/1, /*store_vec=*/0},
// prefetch (secondary path for non-contiguous iterators)
{256, /*no_input_items=*/2, /*min_items=*/1, /*max_items=*/32,
/*prefetch_stride=*/128, /*unroll=*/0},
};
}
};
} // namespace muh::tuning::transform