Skip to content

[PERF] 2-runtime: rwir 指令与参数全 id 化(三表 quickening,消除热路径字符串匹配) #255

Description

@miaobyte

动机

当前一条 int64·add 在主循环最坏要几百次 strcmp + 一次 kvspace 往返:op_is_control(≤4) → IsNativestrip_num_kind + myrwircaps 线性 ~100) → Native再扫一遍 ~100) → isothersrwir(kvspace 读) → 算子内读两操作数 head langtype 字符串归约。瓶颈是「处处字符串」。本 issue 把一条 rwir 指令与其参数在 decode 期一次性 id 化,运行期纯跳表 + 指针 + 整数 tag,消除热路径全部字符串匹配。

设计模型:三表 = 三正交维的 runtime 私有 id 化

head 是 ref × storetype × langtype(见三正交维 head 模型)。runtime 把每一维投影成本进程私有的整数

kvspace 事实(跨 runtime 唯一契约) runtime 内部表(私有) 表形态
opcode(动作) opcode 字符串 rwirtable native 稀疏登记 + user/extern 归一
ref wire 字节 (enum,免表) INLINE/PTR/EXT 常量
storetype(物理布局) wire 字节 storetypetable 闭集 → 静态数组
langtype(语义类型) kindexpr 串 langtypetable 开集 → 运行期 intern

不变量 IV-0(runtime-local id)

rwirtable / storetypetable / langtypetable 及 decode-once 缓存均为单 runtime 进程私有。其 id 不写入 kvspace、不经 handoff/vthread/网络传递、不与同机他进程共享。其它 runtime 不认这些 id;跨 runtime 的唯一契约是 kvspace 的 opcode 字符串、langtype kindexpr 串、storetype 字节。runtime-c 把 "add" intern 成 id=5、runtime-rs intern 成 id=7,二者读同一条 kvspace 指令、各跑各的表、互不知情。

两层彻底分离:数据模型/wire 层ref×storetype×langtype)跨 runtime 一致,是唯一契约;runtime 层三张表是对这三维的私有 id 化。

精度前缀保留(推翻早期「删 specialize」的方向)

C/C++ 原生算术只覆盖 int8..int64 + fp32/fp64。int4、fp8(E4M3/E5M2)、bf16、int2/int1 这些量化/混精类型,C 的 + 表达不了,各需专门实现体(打包/解包、饱和、软件模拟)。所以 int64·add/fp8·add/int4·add 本就是不同实现体,前缀 {langtype}·{op} 是选实现体的键。

  • specialize 保留(数值算子精度前缀 = 选实现体,非冗余)。
  • 废 strip_num_kind——它把精度从 opcode 抹掉、逼所有精度挤进一个 C 原生 kvlangBuiltinAdd,正是 int4/fp8 支持不了的病根。

rwirtable key = 完整 {langtype}·{op}(方案 A)

lookup 语义(两级,稀疏 intern):

  1. 先查完整 opcode(命中 = 有专精实现,如 fp8·add → 专用 fn);
  2. 未命中则拆末段前缀查裸算子(命中 = C 原生通用实现,如 int64·addkvlangBuiltinAdd,精度经内置 langtype_id 传入,不重读 head);
  3. 两级都 miss → 非本 runtime native → 按精度粒度 handoff 给实现它的扩展 runtime(如 gpu-compute 的 fp8·matmul)。

前缀白拿两个好处:能力边界按精度表达(runtime 可声明「有 int64·add,没 fp8·add」→ 后者自动 handoff);稀疏登记(不是 ops×精度 稠密笛卡尔积,实现了哪个登记哪个,扩展 runtime 只登记自己的组合)。与「融合归扩展编译器」不矛盾:选实现体(前缀→精度 fn)核心 runtime 做;算子融合(多条合成 fused kernel)归扩展编译器。

一条指令全 id 化后的形态

kvspace 事实(不变):  [addr0,0]="int64·add"  reads: head.langtype="int64", storetype=ATOM

decode 一次后(进程内缓存,永不失效):
  op_id       = rwirtable("int64·add")               // 完整 opcode intern
  reads[i]    = { ptr, ref, storetype_id=ATOM, langtype_id=INT64 }  // ref=0 → 0copy 指针

运行期:  caps[op_id].fn(&f)                            // 统一跳表,零分支
运行期全程: 零字符串、零 kvspace 重读、零拷贝

三条不可变性(地基)

  1. 指令 XValue layout 后冻结(runtime 只读指令、只读写数据槽)→ decoded 缓存永不失效
  2. 只 decode 一次:进程内按指令坐标缓存 {op_id, params[]};循环体重复执行命中缓存。崩溃重启缓存重建、PC 仍从 kvspace 恢复。
  3. 0copy 仅读参:读参(ref=0)以 kvspace 借用指针零拷贝喂 fn,生命周期 = 单指令执行期;写参照旧WriteInPlace/NewPlace,不 0copy。

P0 裁决:固化 + 整数 guard

decode 期固化 langtype_id,执行时 cached_id == slot_id 整数 guard——静态类型场景恒相等(零感知成本),动态换型则 re-intern 更新。不必现在把 kvlang 类型语义钉死为纯静态,又拿到静态全部性能。

子任务

  • P1 三表内部约定:各 runtime 内部约定 langtype 内置 numkind 预留 id(int8..float64、fp8/int4 保留位)+ control/copy/call/handoff 保留 id;storetype 内部静态表。无跨 runtime 共享/对齐
  • P2 runtime-c 落地kvlangRwirInst_top_idkvlangParam_t{ref, storetype_id, langtype_id, ptr};建 rwirtable(完整 opcode → id,两级 lookup)、langtypetable(intern)、storetype 静态表;废 strip_num_kind;decode-once 进程内缓存(按指令坐标);主循环改 caps[op_id].fn;读参 0copy 指针;热点算子按 op_id/langtype_id 直选实现体。
  • P3 runtime-rs 对称:自建三表 + decoded 缓存 + tag 化 param,行为等价(IV-0:id 各自私有)。
  • P4 验收:三后端 kvlang tutorial 全量仍绿(当前基线 195/195);benchmark.csv 算术热循环(prime_sieve/gcd 等)kvlang_ms 显著下降;代码审查确认主循环与热点算子无 strcmp/strstr;kvspace CLI 确认指令 body 仍 opcode 串、langtype 仍 kindexpr 串、storetype 字节(id 未泄漏)。

边界(不做)

不改 wire、不改 kvspace 唯一事实、id 不持久化、写参不 0copy、不引入编译期类型选核与融合(归扩展编译器)。

依赖

保留 specialize(撤销 #202 中「剥离 specialize」一条);本 issue 废 strip_num_kind。

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    PERF性能:测量、回归或优化

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions