|
| 1 | +#!/usr/bin/env bash |
| 2 | +# Perf harness for flydsl_qk_norm_rope_quant -- BF16 (no-quant) variant. |
| 3 | +# gfx1250, DeepSeek-V4-Flash shape: H=64, D=512, RD=64. |
| 4 | +# |
| 5 | +# BF16 uses the --no-quant path (output bf16, no fp8 pack / block scales). |
| 6 | +# |
| 7 | +# Two modes: |
| 8 | +# default run_perftest sweep -> us / GB/s / %peak table |
| 9 | +# TRACE=1 rocprofv3 kernel-trace -> per-T min/median dispatch time. |
| 10 | +# Use this for small T (decode, e.g. T=64): the kernel is only |
| 11 | +# ~6us there, so run_perftest's torch-profiler timing is |
| 12 | +# dominated by profiler/launch noise. kernel-trace min is the |
| 13 | +# true hardware dispatch duration. |
| 14 | +# |
| 15 | +# Usage: |
| 16 | +# ./runperf-qknormrope-bf16.sh # sweep, T=64 |
| 17 | +# SWEEP_T="64 256 16384" ./runperf-qknormrope-bf16.sh |
| 18 | +# TRACE=1 ./runperf-qknormrope-bf16.sh # kernel-trace min, T=64 |
| 19 | +# TRACE=1 SWEEP_T="64 256 1024" ./runperf-qknormrope-bf16.sh |
| 20 | +export HIP_VISIBLE_DEVICES=1 |
| 21 | +set -euo pipefail |
| 22 | + |
| 23 | +# --- tunables (override via env) -------------------------------------------- |
| 24 | +TEST="${TEST:-op_tests/test_flydsl_qk_norm_rope_quant.py}" |
| 25 | +H="${H:-64}" # num Q heads per rank (= num_attention_heads / TP) |
| 26 | +D="${D:-512}" # head_dim (MVP: 512 only) |
| 27 | +RD="${RD:-64}" # rope_head_dim |
| 28 | +SWEEP_T="${SWEEP_T:-64}" # T values (default: token=64 decode point) |
| 29 | +TRACE="${TRACE:-0}" # 1 -> kernel-trace min/median instead of sweep |
| 30 | +OUTDIR="${OUTDIR:-/tmp/prof_qknorm_bf16}" |
| 31 | + |
| 32 | +COMMON="--H ${H} --D ${D} --RD ${RD} --no-quant" |
| 33 | + |
| 34 | +echo "config: H=${H} D=${D} RD=${RD} dtype=BF16 (no-quant) T=${SWEEP_T} TRACE=${TRACE}" |
| 35 | + |
| 36 | +if [[ "$TRACE" == "0" ]]; then |
| 37 | + python "$TEST" -T ${SWEEP_T} $COMMON |
| 38 | + exit 0 |
| 39 | +fi |
| 40 | + |
| 41 | +# --- kernel-trace mode: one dispatch DB per T, report min/median ------------ |
| 42 | +for T in $SWEEP_T; do |
| 43 | + d="${OUTDIR}/T${T}" |
| 44 | + rm -rf "$d" |
| 45 | + rocprofv3 --kernel-trace -d "$d" \ |
| 46 | + -- python "$TEST" -T ${T} $COMMON >/dev/null 2>&1 |
| 47 | + DB=$(ls "$d"/*/*.db 2>/dev/null | head -1) |
| 48 | + if [[ -z "$DB" ]]; then echo "T=${T}: no trace db"; continue; fi |
| 49 | + T_VAL=$T H_VAL=$H D_VAL=$D python3 - "$DB" <<'PY' |
| 50 | +import sqlite3, sys, os, statistics |
| 51 | +db = sys.argv[1] |
| 52 | +T = int(os.environ["T_VAL"]); H = int(os.environ["H_VAL"]); D = int(os.environ["D_VAL"]) |
| 53 | +c = sqlite3.connect(db) |
| 54 | +tabs = [r[0] for r in c.execute("SELECT name FROM sqlite_master WHERE type='table'")] |
| 55 | +def tb(p): return [t for t in tabs if t.startswith(p)][0] |
| 56 | +ks, kd = tb("rocpd_info_kernel_symbol"), tb("rocpd_kernel_dispatch") |
| 57 | +q = (f"SELECT (d.end-d.start)/1000.0 FROM {kd} d JOIN {ks} s ON d.kernel_id=s.id " |
| 58 | + f"WHERE s.display_name LIKE '%H{H}%D{D}%' ORDER BY d.start") |
| 59 | +ts = [r[0] for r in c.execute(q)] |
| 60 | +if not ts: |
| 61 | + print(f"T={T}: no matching dispatches"); sys.exit() |
| 62 | +# bf16 traffic: Q in + KV in + Q out + KV out (all bf16, 2B) |
| 63 | +by = T*H*D*2 + T*D*2 + T*H*D*2 + T*D*2 |
| 64 | +mn = min(ts) |
| 65 | +gbps = by/(mn*1e-6)/1e9 |
| 66 | +print(f"T={T:6d} n={len(ts):3d} min={mn:8.2f}us p50={statistics.median(ts):8.2f}us " |
| 67 | + f"max={max(ts):8.2f}us | min-based {gbps:6.0f} GB/s") |
| 68 | +PY |
| 69 | +done |
0 commit comments