
1. TunableOp 不是“又一个调度器”而是把 Kernel 选择从玄学拉回工程现场的测量引擎你有没有遇到过这种场景写完一个 GEMM 算子调用 hipBLASLt 或 rocBLAS结果在 MI250X 上跑出 65% 的理论带宽利用率在 MI300X 上却掉到 42%不是代码错了不是数据没对齐甚至不是编译器没开 O3——而是你根本不知道底层到底选了哪个 Kernel。rocBLAS 内部有几十个 GEMM 实现变体有的专为小矩阵优化有的吃满 L2 缓存有的靠寄存器重用压榨计算密度有的则依赖特定 wavefront size 才能打满 CU。它们不公开、不文档化、不暴露选择逻辑。你只能祈祷 runtime 猜对——而它经常猜错。TunableOp 就是为此而生的“反猜测”机制。它不试图预测哪个 Kernel 最快而是直接测量。不是在模型训练前做一次离线 benchmark也不是靠静态 shape 分类表查表匹配而是在推理 pipeline 中对当前 batch 的真实输入 shape、dtype、layout、memory layout比如是否 contiguous、甚至当前 GPU 的实时 occupancy 状态发起轻量级、低开销的实测 probe。它真正价值不在“可调”而在“可证”每个 Kernel 的执行时间不是估算值是纳秒级 timestamp 的实测结果选择依据不是 heuristic rule是实打实的 latency 差值。这彻底改变了 AI 推理优化的底层范式——从“相信库作者的直觉”转向“只信自己测出来的数字”。我第一次在客户现场部署 TunableOp 时发现一个看似简单的 1024x1024x1024 FP16 GEMM在 MI250 上始终卡在 38 TFLOPS远低于标称的 120。rocBLAS 默认选了GEMM_NN_16x16变体但实测发现它在该 shape 下 cache miss 率高达 37%。TunableOp 在 12ms 内完成 5 个候选 Kernel 的 probe每个 probe 仅运行 32 次 warmup 64 次 timing最终锁定GEMM_NN_32x8_TILED实测性能跃升至 52 TFLOPS。这不是 magic是把 Kernel 选择这件事从黑盒决策变成了白盒工程。提示TunableOp 的 probe 开销极低但绝非零成本。它默认只在首次 shape 出现时触发 full probe后续相同 shape 直接复用缓存结果。缓存 key 不仅包含 M/N/K还包含 stride、leading_dim、是否 transposed 等内存布局细节——因为哪怕只是 transpose 一下最优 Kernel 就可能完全不同。2. 为什么传统 Kernel 选择机制注定失效从 rocBLAS 的设计哲学说起要理解 TunableOp 的不可替代性必须先看清传统 BLAS 库如 rocBLAS、hipBLASLtKernel 选择机制的底层局限。这不是 bug而是 design trade-off 的必然结果。rocBLAS 的 Kernel 选择核心逻辑本质上是一个三层决策树第一层shape 分类根据 M/N/K 的数值范围粗略划分成 “small”、“medium”、“large”、“very large”。这个分类阈值是硬编码在gemm_dispatch.cpp里的常量比如M 64 N 64判定为 small。但它完全忽略了一个关键事实同样 M32,N32,K128如果 A 是 row-major 而 B 是 col-major内存访问模式天差地别最优 Kernel 必然不同。而 shape 分类对此毫无感知。第二层硬件特征映射基于 GPU 架构代号如 gfx90a, gfx942和 compute unit 数量从预编译的 Kernel 表中筛选出“理论上可用”的子集。问题在于同一架构下不同型号的 L2 cache size、GMEM bandwidth、wavefront scheduler behavior 存在显著差异。MI250X 的 L2 是 32MBMI300X 是 96MB但 rocBLAS 的 dispatch logic 对此无区分仍用同一套规则。第三层启发式打分对筛选出的候选 Kernel用一组 hand-crafted 公式打分例如score (M * N * K) / (L2_cache_size * 2) (K * sizeof(dtype)) / (GMEM_bandwidth)这个公式假设所有访存都是理想连续的完全无视实际 stride、padding、alignment 导致的 bank conflict 和 cache line split。更致命的是它无法反映 runtime 状态——比如当前 GPU 正在跑一个高 priority kernel导致 scheduler delay此时一个原本 low-latency 的 Kernel 可能因调度抖动而变慢。我曾用 perfetto 抓取过 rocBLAS 在 MI300A 上的 Kernel 执行 trace发现一个典型 case当系统 memory controller 处于 high-load 状态时某个本应高效的GEMM_NN_64x4Kernel 的平均 latency 波动从 12.3μs 涨到 28.7μs而 rocBLAS 的 static dispatch 完全无法感知这一变化仍持续选用它。TunableOp 的破局点正在于绕过这三层抽象。它不依赖任何预设分类、不信任任何理论公式、不假设硬件状态恒定。它直接问硬件“你现在用这个 exact input跑这个 exact Kernel要多久”答案只有一个实测时间。这个时间戳包含了所有你无法建模的复杂性——cache warm/cold effect、scheduler jitter、memory controller contention、even thermal throttling。它把 Kernel 选择从一个基于假设的推理问题还原成一个基于观测的实证问题。注意TunableOp 的 probe 并非暴力穷举。它采用 adaptive sampling 策略先快速 run 10 次若 latency std dev 15%则自动增加 sample count 至 100 次并启用 perf_event 采集 cache miss 和 instruction retired 数据用于二次过滤明显 outlier Kernel。这保证了 probe 结果的统计鲁棒性。3. TunableOp 的实测工作流从 probe 到 deployment 的完整闭环TunableOp 的价值只有在真实部署链路中才能被 fully realized。它不是一个独立工具而是深度嵌入推理 runtime 的测量-决策-缓存闭环。下面以一个典型的 Triton-based inference server 集成为例拆解其端到端工作流。3.1 Probe 阶段轻量、精准、可中断Probe 不发生在模型加载时而是在第一个请求到达、且遇到全新 shape 组合时触发。整个过程严格控制在 20ms 内避免影响首包延迟P99 5ms 是多数线上服务 SLA。具体步骤如下Candidate Kernel 枚举TunableOp 不 probe 所有 Kernel而是基于当前 GPU arch 和 dtype从 rocBLAS 的gemm_kernels.h中提取一个精简候选集。例如在 MI300X FP16 场景下候选集仅包含 7 个经过历史 benchmark 验证的 high-potential Kernel如GEMM_NN_32x16,GEMM_NT_64x8,GEMM_TN_16x32剔除掉已知在该 arch 下表现差的变体。这一步由 offline profiling database 驱动数据库本身通过 nightly CI 在真实硬件上持续更新。Probe Execution每个 candidate Kernel 被封装为一个独立的 HIP kernel launch输入 buffer 使用 pinned memory 并 pre-warmed。probe sequence 采用 round-robin 方式避免单个 Kernel 连续执行导致 cache pollution。每次 launch 后用hipEventRecord()hipEventElapsedTime()获取精确 latency同时用rocprof --set sys --timestamp采集 L2 cache hit rate 和 memory bandwidth utilization。所有数据在 host 端聚合。结果判定与缓存latency 数据经 outlier rejection使用 IQR 方法后取 median 值作为最终 score。若某 Kernel 的 median latency 比最优者差 25%且 L2 hit rate 60%则标记为 “unstable” 并从缓存中排除。最终shape layout arch 的组合被 hash 成 key对应最优 Kernel ID 和 probe metadata如采样数、std dev写入 LRU cache。cache 默认大小为 2048 entries可配置。3.2 Runtime 阶段零开销的最优路径一旦 probe 完成并缓存后续所有相同 shape 的请求TunableOp 的介入近乎零开销Dispatch bypassTunableOp hook 在 rocBLAS 的rocblas_gemm_ex入口检测到缓存命中后直接跳过 rocBLAS 自身的 dispatch logic将 control flow 重定向到缓存中记录的最优 Kernel 的 raw function pointer。Memory layout adaptation缓存中不仅存 Kernel ID还存有该 Kernel 所需的最优 memory layout。例如GEMM_NT_64x8可能要求 B matrix 为 column-majorTunableOp 会自动插入一个 lightweight transpose kernel用 Triton 实现 0.1ms确保输入满足要求而非让上层模型做 costly reshape。动态降级机制若 runtime 检测到 GPU temperature 85°C通过rocm-smi --showtempAPI则临时启用 “thermal-safe mode”从缓存中选取 latency 稍高但功耗更低的 Kernel避免 thermal throttling 导致的 latency spike。我在某视频生成服务中部署此流程后GEMM ops 的 P99 latency 从 18.7ms 降至 11.2ms且 variance 降低 63%。最关键的是运维不再需要为不同 batch size 手动 tuning 参数——TunableOp 自动适配。提示probe cache 的持久化是可选的。我们建议在容器启动时加载一个预热 cacheJSON 文件内容来自 offline profiling cluster 的最新结果。这样新实例上线无需等待首次 probe首包延迟直接达标。4. TunableOp 与 hipBLASLt 的协同不是替代而是增强一个常见误解是TunableOp 是为了取代 hipBLASLt。恰恰相反它的设计哲学是“站在巨人的肩膀上补上巨人看不见的盲区”。hipBLASLt 是一个极其优秀的、高度工程化的库它提供了丰富的 Kernel 变体覆盖各种 corner case高效的 workspace management 和 memory reuse对 Tensor Core 和 Matrix Core 的深度优化完善的 error handling 和 debug tracingTunableOp 不重复造轮子而是作为 hipBLASLt 的“智能 wrapper”专注于它最薄弱的环节Kernel selection 的 context-awareness。二者协同工作流如下User App → TunableOp Dispatch Layer → hipBLASLt ↓ [Probe Mode] → hipBLASLts internal profiler → TunableOp cache update ↓ [Runtime Mode] → direct call to hipBLASLts specific kernel function关键点在于TunableOp 从不自己实现 GEMM Kernel它 always calls into hipBLASLt’s existing functions。它只是决定“call which one, and when”。例如当 TunableOp 决定选用hipblasltMatmulDescSetAttribute(desc, HIPBLASLT_MATMUL_DESC_TRANSA, trans_a, sizeof(trans_a))时它实际调用的是 hipBLASLt 提供的hipblasLtMatmul(...)只是传入了经过实测验证的最优参数组合。我们做过对比测试在相同 MI300X 机器上纯 hipBLASLtdefault dispatch vs TunableOp hipBLASLtprobe-enabledWorkloadhipBLASLt default (TFLOPS)TunableOp hipBLASLt (TFLOPS)SpeedupCache Hit Rate512x512x512 FP1648.261.71.28x99.3%2048x2048x128 FP1672.189.51.24x98.7%Dynamic shape (batch1..32)35.6 avg54.8 avg1.54x87.2%注意最后一行dynamic shape 场景下 speedup 最高。因为 hipBLASLt 的 static dispatch 在 shape 变化时频繁 mispredict而 TunableOp 的 per-shape probe 天然适应动态性。注意TunableOp 与 hipBLASLt 的 ABI 兼容性至关重要。我们强制要求 TunableOp 只使用 hipBLASLt 的 public C API如hipblasLtMatmul,hipblasLtMatmulHeuristicResult_t绝不 touch internal symbols。这保证了即使 hipBLASLt 升级到新版本只要 API signature 不变TunableOp 无需修改即可继续工作。5. TunableOp 的边界与陷阱它不能解决什么以及如何规避TunableOp 强大但绝非万能。理解其边界是避免误用、发挥最大价值的前提。以下是我们在数十个客户现场踩过的坑按严重程度排序5.1 无法解决 Kernel 本身的缺陷probe 只能选不能修TunableOp 的 probe 只能告诉你“哪个 Kernel 相对最快”但它无法让一个本身有 bug 的 Kernel 变得正确。我们曾遇到一个案例某 hipBLASLt 版本中GEMM_NN_128x4Kernel 在 K1024 且 A stride 不是 64-byte aligned 时会产生 NaN 输出。TunableOp 的 probe 发现它 latency 最低10.2μs于是将其选为最优结果整个推理 pipeline 输出全毁。规避方案TunableOp 内置 sanity check phase。在 probe 的每个 candidate Kernel 执行后不仅测 latency还做 lightweight correctness validation取 output tensor 的 corner 4x4 block与 reference CPU implementation用 numpy比对允许 1 ULP error。若 validation fail则该 Kernel 被永久 ban不参与后续 ranking。这个 check 增加约 0.3ms 开销但杜绝了 silent failure。5.2 probe 开销在极端低延迟场景下仍需权衡对于 ultra-low-latency 服务如高频交易信号处理20ms 的首次 probe 可能超出容忍阈值。此时不能简单关闭 TunableOp而应采用 hybrid strategyOffline profiling online fallback在 model build 阶段用 representative dataset 运行 full probe生成 shape-to-Kernel mapping table打包进 model artifact。runtime 优先加载此 table仅当遇到 table 未覆盖的 shape 时才触发 online probe并设置 timeout5ms超时则 fallback to hipBLASLt default。Coarse-grained grouping对 shape 空间做 k-means clustering基于 log(M), log(N), log(K)每个 cluster 代表一个 “shape family”。probe 只在每个 cluster 的 centroid shape 上执行结果泛化到整个 cluster。实测在 95% 的 workload 下loss in optimal performance 3%。5.3 cache pollution 与多租户干扰在 shared GPU 环境如 Kubernetes pod 共享一张 MI300TunableOp 的 probe 可能被其他 tenant 的 workload 干扰。例如当 probe 正在运行时另一个 pod 启动了一个 memory-intensive job导致 L2 cache 被 flushprobe 测出的 latency 失真。规避方案TunableOp 支持 hardware isolation aware probing。通过rocm-smi --showuse查询当前 GPU 的 memory bandwidth utilization若 70%则自动 delay probe 500ms 并重试最多 3 次。同时probe kernel 自身使用__hip_shared__memory 尽量减少 global memory access降低对 system memory controller 的冲击。5.4 不适用于 Kernel 数量极少的算子TunableOp 的价值与候选 Kernel 的多样性正相关。对于像ADD、MUL这类只有 2~3 个实现的 element-wise opprobe 的收益微乎其微反而增加 complexity。我们的实践是只对 GEMM、Conv2D、LayerNorm 等 Kernel space 5 的算子启用 TunableOp其他算子走 hipBLASLt default。这通过一个 simple config file 控制tunable_ops: - name: gemm enabled: true candidates: 7 - name: conv2d enabled: true candidates: 12 - name: add enabled: false提示TunableOp 的 probe log 是调试黄金线索。我们强制要求开启TUNABLEOP_LOG_LEVELDEBUG它会输出每一轮 probe 的详细 timing breakdownkernel launch, HtoD copy, DtoH copy, validation time以及最终 decision rationale。当性能异常时第一件事就是 grep 这个 log而不是怀疑模型或数据。6. TunableOp 的未来演进从 Kernel 选择到 whole-stack co-designTunableOp 的当前形态聚焦于单个算子主要是 GEMM的 Kernel 选择优化。但这只是起点。它的测量基因正在驱动更宏大的 whole-stack co-design vision。6.1 Cross-op measurement打破算子孤岛当前 TunableOp 的 probe 是 per-op 的。但真实模型中op 之间存在 data dependency 和 memory reuse。例如一个 GEMM 的 output 直接作为下一个 LayerNorm 的 input如果 GEMM 选了需要 padding 的 Kernel而 LayerNorm 的最优实现恰好要求 no-padding就会产生额外的 copy overhead。下一代 TunableOp 正在 prototype “cross-op probe”它不再单独 probe GEMM而是 probe “GEMM LayerNorm” 的 fused subgraph。probe 时测量整个 subgraph 的 end-to-end latency而非单个 op。这需要与 compiler如 Triton or ROCm’s MIOpen深度集成动态生成 fused kernel。初步测试显示在 transformer decoder layer 中cross-op probe 比 per-op probe 额外带来 8~12% 的 throughput 提升。6.2 Hardware state-aware probing把 GPU 当作传感器probe 不再只关注 “what is fastest”也开始回答 “what is most stable”。我们正在接入 ROCm 的 hardware telemetry API实时读取L2 cache occupancy (%)Memory controller queue depthCU utilization (%)Die temperature (°C)这些指标被作为 probe 的 contextual features。例如当 memory queue depth 100 时probe 会主动 penalize Kernel with high memory bandwidth demand即使其 baseline latency 更低。这实现了真正的 QoS-aware optimization。6.3 Auto-tuning as a service从 client-side 到 cloud-nativeTunableOp 正在从一个 library演变为一个云服务。我们构建了一个 centralized TunableOp Profiling ServiceTPS它接收来自全球客户集群的 anonymized probe logsshape, arch, latency, hw state用 federated learning 更新 global probe model识别跨硬件的通用 pattern为新硬件如尚未发布的 MI350提供 zero-shot prediction基于相似 archgfx942的历史数据生成 initial probe candidate set这意味着当你拿到一台全新的 MI350 服务器TunableOp 不是从零开始 probe而是带着一个 80% accurate 的 prior knowledge 启动首次 probe 时间缩短 60%。我在去年的一次内部分享中说过TunableOp 的终极目标不是让每个 Kernel 都更快而是让“选择 Kernel”这件事彻底退出工程师的日常 checklist。当测量足够 cheap当 cache 足够 smart当 cross-op awareness 成为 defaultKernel selection 就像 TCP congestion control 一样——你不再需要手动调参它就在那里安静、可靠、自适应地工作。这才是 AI 推理基础设施该有的样子。