代码结构与构建

1. 单文件设计哲学

colibrì 的整个运行时引擎就是一个 C 文件 c/glm.c(约 2547 行)加几个 header-only 头文件。所有第三方库(safetensors 读取、JSON 解析、tokenizer)都是头文件形式内联进来的,编译产物是一个零依赖的可执行文件。c/Makefile 的注释明确写道:默认构建”remains pure C and keeps the original zero-dependency runtime”。

这带来两个直接后果:

  • 极致可移植:一条 gcc -O3 -march=native -fopenmp glm.c -lm 就能编译整个引擎,没有 CMake、没有 vendored 库、没有 pip install
  • env-var 驱动:因为没有复杂的配置系统,几乎所有运行时行为都由环境变量控制,集中在 main 里解析(SNAP/PROMPT/SERVE/DRAFT/PIN 等)。

代码注释混用意大利语和英语——作者的工作语言是意大利语,较新的补充带有意/英双语注释。


2. 顶层目录

colibri/
├── Makefile               根构建入口(4 行,全部转发给 c/)
├── README.md              主文档(26.5 KB,含 benchmark 与设计哲学)
├── ref.json               OLMoE oracle:prompt + prompt_ids/full_ids
├── assets/colibri.svg     logo
├── .github/               issue/PR 模板
├── c/                     引擎本体(全部 C / CUDA / Python)
└── web/                   浏览器 UI(React + Vite,社区维护)

c/ 目录里,运行时路径刻意保持扁平、可读:

文件 行数 角色
glm.c 2547 单文件 GLM-5.2 引擎(本分析的主角)
olmoe.c 390 Stage-A 参考引擎(OLMoE,验证流式核心的前身)
iobench.c 58 磁盘微基准(19 MB 随机读,模拟专家读法)
st.h 233 safetensors 读取器(pread + fadvise,非 mmap)
json.h 149 极简 JSON 解析器
tok.h 278 GLM-5.2 byte-level BPE tokenizer
tok_unicode.h 162 Unicode 属性表(由脚本生成)
tier.h 31 专家分层/固定的热度换入换出
compat.h 50 跨平台垫片(Linux 上全是 no-op)
backend_cuda.h / .cu 49 / 230 可选 CUDA 层
coli 面向用户的 Python CLI 调度器(chat/serve/plan/convert…)
openai_server.py 605 OpenAI 兼容 HTTP 网关
resource_plan.py 216 RAM/磁盘/VRAM 资源规划器
setup.sh / scripts/ / tools/ / tests/ 安装、转换、基准、测试(均非运行时依赖)

Python 与 shell 工具刻意分组隔离,永远不是引擎的运行时依赖——它们只在离线转换、基准、CLI 包装时用到。


3. 构建系统

3.1 根 Makefile — 纯转发

根 Makefile 只有 4 行,每个目标都转发进 c/

.PHONY: all glm portable test check cuda-test clean
all glm portable test check cuda-test clean:
	$(MAKE) -C c $@

3.2 c/Makefile — 平台分流

c/Makefile(99 行)按 uname -s第 1 行)分流:

macOS / Apple Silicon第 3–17 行):用 clang,探测 Homebrew 的 libomp 来启用 OpenMP;注释说 arm64 上不加 -march——NEON 是基线,__ARM_NEON 内核自动生效。

Linux x86-64第 20–29 行):用 gccARCH ?= native,可选 x86-64-v3(可移植,需要 AVX2)或 x86-64(最大兼容,标量回退)。核心编译标志:

CFLAGS = -O3 -march=$(ARCH) -fopenmp -Wall -Wextra ...
LDFLAGS = -lm -fopenmp

CUDA opt-in第 31–48 行):默认 CUDA ?= 0(关闭)。CUDA=1 时加 -DCOLI_CUDA,用 nvcc 编译 backend_cuda.cu,链接 -lcudart -lstdc++。在 macOS 上 CUDA=1 会直接 $(error ...)

关键点:SIMD ISA 是编译期选择,不是运行期分发。具体走 AVX512-VNNI / AVX2 / NEON / scalar 哪条路,由 glm.c 里的 #ifdef在编译时决定——所以要发挥某台机器的性能,需要用 -march=native 为它重新编译。

常用目标glm(主引擎)、portable(= make glm ARCH=x86-64-v3)、cuda-testtest(C + Python 测试)、check(clean + portable + test,本地验证)。

3.3 setup.sh — 一条命令上手

c/setup.sh(48 行):检查 gcc/clang + OpenMP,make -s glm ARCH=native 构建,跑一个 tiny-oracle 自检(期望输出 32/32),打印 RAM 和下一步命令。注释警告:模型要放在快速 NVMe/ext4 上,绝不能放 /mnt/c 或网络挂载。


4. glm.c 的分区结构

虽然是一个文件,glm.c 逻辑上分区非常清晰。下表是按行号的地图(每个区段对应后续的一篇或几篇文档):

行范围 区段 对应文档
1–18 文件头 / 架构摘要 01
19–51 includes、平台 #if、AVX2/NEON hsum256 02
53–144 核心结构体:QTCfgESlotLayerModel 03/04
145–199 CUDA 全局与助手、now_s/rss_gb/falloc 09
200–296 F32/dequant-on-use 矩阵乘:matmul/_q/_i4/_i2 03
298–455 IDOT 整数点积内核:dot_i8i8/dot_i4i8/matmul_*_idot 03
456–491 matmul_qt 分派器(CUDA / IDOT / 标量回退) 03
492–582 量化器 quantize_rows/pack_int4/pack_int2、env 标志 03
583–610 数学:rmsnorm/layernorm/softmax/rope_interleave 03/06
611–705 配置与张量加载:load_cfg/qt_from_disk/ld 04
706–846 model_init(大加载器) 04
847–955 embedding 与专家 I/O:embed_row/expert_load/expert_prefetch 04/07
956–1141 注意力:attention(MLA + DSA indexer + 吸收) 06
1142–1275 moe(5 阶段路由)、dense_mlp 07
1276–1347 投机预取:la_predict(LOOKA)、pilot_prefetch(PILOT) 07/08
1348–1425 前向:layer_forward/layers_forward/step/step_all 05
1427–1507 投机解码起草:ngram_draft/mtp_draft/mtp_absorb 08
1508–1628 采样:dist_build/pick_tok/spec_decode 05/08
1629–1783 运行模式:forward_all/run_score/generate/run_text 05
1784–1937 SERVE + 热 repin + KV 落盘 06/07/10
1938–2091 多 slot 服务:ServeCtx/run_serve 10
2091–2382 资源预算与学习缓存:cap_for_ram/usage_load/pin_load 04/07
2384–2547 main:env-var 解析、模式分派 05

5. 头文件

5.1 st.h — safetensors 读取器

st.h 是 colibrì 磁盘流式的基石。头注释(1–6 行)点明了一个关键设计:pread + posix_fadvise(DONTNEED) 而不是 mmap,专门为了修复 “mmap-rss-bug”——让常驻内存保持稠密可控。

一条设计注释(36–38 行)解释了为什么要建哈希表:GLM 有约 12 万个张量(256 专家 × 78 层 × 3 × 2),线性扫描每 token 要花几十秒。O_DIRECT 双 fd 的动机在另一处注释(93–94 行):VHDX 里的 ext4 缓冲读只能到 ~0.8 GB/s,O_DIRECT 能到 2.3+ GB/s。

5.2 json.h — 极简 JSON 解析器

json.h(149 行)是递归下降解析器,用于读 safetensors 头和 ref.json。支持 \uXXXX 和代理对,但不追求完整 spec。核心:jval 结构json_parsejson_get

5.3 tok.h / tok_unicode.h — tokenizer

tok.h(278 行)是忠实实现 GLM-5.2 的 byte-level BPE(cl100k/tiktoken 风格,ignore_merges=true,ByteLevel 预分词,320k merges)。关键函数:tok_load(解析 tokenizer.json)bpe_piece(BPE 合并循环)pretok_chunk(cl100k 正则,7 个分支)tok_encodetok_decode

tok_unicode.htools/gen_unicode.py 生成的 Unicode 属性表(字母/数字/空白范围 + 二分查找),供预分词正则使用。

5.4 tier.h — 专家分层换入换出

tier.h(仅 31 行)实现热度驱动的固定专家换入换出:

5.5 compat.h — 跨平台垫片

compat.h(50 行)在 Linux 上是完全的 no-op——所有平台差异都收拢在这里,让 .c 保持干净。逻辑全在 #ifdef __APPLE__ 里:把 posix_fadvise(WILLNEED) 映射到 F_RDADVISEDONTNEED 映射到 no-op,把 O_DIRECT 映射到 F_NOCACHE


6. 其他 C 文件

  • olmoe.c(390 行)是 Stage-A 参考引擎:一个更简单的纯 C OLMoE 推理引擎,头注释说它的目标是复现 ref.json 的精确 token id,用来在扩展到 GLM-5.2 之前验证”磁盘流式 + 注意力”的核心。它是 glm.c 的前身——同样的专家流式思想,但没有 CUDA、KV 落盘、HTTP 服务。详见 10-服务与工具链
  • iobench.c(58 行)是磁盘微基准:用 N 个线程并行 pread 专家大小(~19 MB)的随机块,测量随机读带宽——正是引擎读专家的方式。README 里教用户先跑它来预测自己机器的 token 速度。

7. 小结

设计选择 出处 意义
单文件 + header-only 库 glm.c 全文 gcc glm.c 即可编译,零依赖
env-var 驱动配置 main 无配置系统,行为全在环境变量
编译期 SIMD 选择 glm.c:302, Makefile:26 -march=native 解锁本机指令集
pread+fadvise 而非 mmap st.h:1 RSS 稠密可控,修复 mmap-rss-bug
Python/shell 严格隔离 tools/ 永不成为运行时依赖

This site uses Just the Docs, a documentation theme for Jekyll.