Skip to content

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions