复用已翻译的机器代码块
QEMU TCG 用 QHT 保存 TranslationBlock 索引,帮助复用与当前客体执行状态一致的翻译结果。
相关概念
工程问题#
重复翻译相同代码会浪费时间,但只按 PC 判断相同又不够:执行模式、标志和代码页信息也会影响翻译结果。
实际实现#
tb_htable_init 初始化可自动扩容的 QHT;tb_cmp 比较 TB 的相关属性。QHT 查找需要 RCU 读侧保护,删除对象需遵守延迟释放规则。
处理流程#
- 由执行上下文形成查询键
- 在 QHT 查找并比较完整属性
- 命中后复用翻译块
- 代码失效时移除相关索引
源码片段#
固定版本 · 原文摘录accel/tcg/tb-maint.cv9.2.0 · L46–L64
46static bool tb_cmp(const void *ap, const void *bp)47{48 const TranslationBlock *a = ap;49 const TranslationBlock *b = bp;5051 return ((tb_cflags(a) & CF_PCREL || a->pc == b->pc) &&52 a->cs_base == b->cs_base &&53 a->flags == b->flags &&54 (tb_cflags(a) & ~CF_INVALID) == (tb_cflags(b) & ~CF_INVALID) &&55 tb_page_addr0(a) == tb_page_addr0(b) &&56 tb_page_addr1(a) == tb_page_addr1(b));57}5859void tb_htable_init(void)60{61 unsigned int mode = QHT_MODE_AUTO_RESIZE;6263 qht_init(&tb_ctx.htable, tb_cmp, CODE_GEN_HTABLE_SIZE, mode);64}tb_cmp / tb_htable_init
QHT 初始化显式传入完整 TB 比较函数,并启用自动扩容。哈希命中后仍比较执行标志和代码页地址;CF_PCREL 允许跳过 PC 相等检查。此片段证明索引和等价判定,RCU 查找与失效处理在其他函数中。
收益与取舍#
工程分析带来的收益
- 减少重复翻译与编译开销
- 读侧机制适配并发查询
付出的代价
- 工程分析:哈希冲突仍需做完整比较
- 失效传播与对象释放协议增加复杂度
可比较的选择
仅按 PC 的直接缓存访问路径更短,但容量、冲突和执行上下文区分需要额外处理。
版本与适用范围#
对应 QEMU TCG 动态翻译路径;KVM 执行客体代码的主要路径不依赖这套 TCG 翻译块缓存。
参考来源#
源码、官方文档与原始论文相关实现与比较#
4 个相关案例libvirt 为 Domain 对象维护 UUID 与名称两个哈希索引,两个入口指向同一个对象。
附源码片段 · 索引与查找
把上下文身份编码进块哈希,让重复请求共享已经计算的 KV cache。
附源码片段 · 缓存与复用
Redis 有序集合既要按成员查分数,也要按分数和名次遍历;较大集合通过两种索引服务这些访问方式。
附源码片段 · 索引与查找
Redis 7.2.0 的字典扩缩容保留新旧两张哈希表,逐桶迁移,降低一次性搬迁全部条目的停顿。
附源码片段 · 索引与查找