[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 参数差异大
This commit is contained in:
dylanyunlon
2026-08-04 07:13:01 +00:00
parent 475574fd3d
commit 31d39e6032
3 changed files with 47 additions and 5 deletions

View File

@@ -21,6 +21,13 @@
// Heuristic: ns *= 0.5, l2w *= 0.6 (PENDING BI-V100 BENCHMARK)
// 3. Tile maximization: fewer CTAs = each must process more data
// Small tiles (e.g. 1B offset=4: tile=9216, 19% SMEM) waste capacity
//
// BI-V100 BENCHMARK VALIDATION (bench_bi100.py on iluvatar-bi-v100):
// scan/float32 TOP 10 — all use ns=1904 (SM100 raw, NOT ×0.5!)
// The ns×0.5 heuristic was WRONG. BI-V100 has 16 SMs = ~32 CTAs,
// so lookback contention is minimal → large ns spacing is fine.
// Best dcid=0 (no_delay), not dcid=6 (exponential_backon_jitter).
// SMEM usage: 33792/49152 = 69% for ipt=22,tpb=384,value=4B.
#pragma once
@@ -108,11 +115,19 @@ struct bi100_lookback_2B_o4 {
};
struct bi100_lookback_4B_o4 {
// SM100 ref: ipt_22.tpb_384.ns_1904.dcid_6.l2w_830 → 1.148x
// BI-V100 BENCHMARK RESULT (bench_bi100.py scan/float32):
// #1: 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%)
//
// KEY FINDING: ns=1904 (same as SM100 raw, NOT ×0.5!)
// The ns×0.5 heuristic was WRONG for BI-V100.
// dcid=0 (no_delay) beat dcid=6 (exponential_backon_jitter).
// With only 16 SMs → ~32 concurrent CTAs → minimal lookback contention
// → simple no_delay with ns=1904 spacing is optimal.
static constexpr int threads = 384;
static constexpr int items = 22;
static constexpr LookbackDelayPolicy delay = {
LookbackDelayAlgorithm::exponential_backon_jitter, 952, 498};
LookbackDelayAlgorithm::no_delay, 1904, 500};
static constexpr BlockLoadAlgorithm load_algo = BLOCK_LOAD_WARP_TRANSPOSE;
static constexpr BlockStoreAlgorithm store_algo = BLOCK_STORE_WARP_TRANSPOSE;
static constexpr CacheLoadModifier load_mod = LOAD_DEFAULT;

View File

@@ -76,13 +76,23 @@ struct policy_selector {
constexpr TopkPolicy operator()(const hardware_capability& hw) const {
if (hw.at_least(hardware_capability::vendor_t::iluvatar, 100)) {
// SM90+ path from CCCL: 16 bytes per thread
// BI-V100 BENCHMARK RESULT (bench_bi100.py topk/float32):
// #1: ipt_4.ld_0.tpb_512 speedups: 1.039611 1.000222 1.004295
// (baseline: 1K=76.6us, 32K=220.8us, 152K=554.4us)
// #2: ipt_1.ld_1.tpb_256 speedups: 1.017337 1.020884 1.000531
// #3: ipt_1.ld_1.tpb_512 speedups: 0.986497 1.047220 1.004375
//
// KEY FINDINGS:
// - ipt=4, tpb=512 matches CCCL SM90+ formula (4*4/4=4) → CONFIRMED
// - ld=0 (LOAD_DEFAULT) beats ld=1 (LOAD_LDG/LOAD_CA) at small sizes
// - For 32K+ items, ld=1 is competitive but ipt=4 ld=0 wins overall
// - ipt=16 regresses at 32K and 152K sizes (too many items per thread)
constexpr int nominal_4b_items = 4;
int items = nominal_4b_items * 4 / key_size;
if (items < 1) items = 1;
return {512, items,
BLOCK_LOAD_VECTORIZE, // CCCL uses VECTORIZE, not DIRECT
BLOCK_LOAD_VECTORIZE, // CCCL VECTORIZE; BI-V100 ld=0 confirmed best
BLOCK_SCAN_WARP_SCANS,
calc_bits_per_pass(key_size)};
}

View File

@@ -97,7 +97,24 @@ struct TransformPolicy {
// PENDING BENCHMARK: %RANGE% bif 16384:65536:4096
// ============================================================
constexpr int bi100_bytes_in_flight = 32 * 1024; // 32KB, was 16KB (bug)
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