Skip to content

[性能回归] 0.1.193 长会话本地耗时从 1.3s 升至 3.2s:无用 SimHash 计算与重复历史转换 #2824

Closed

Description

@kuviki

问题

bili 从 0.1.192 自动更新到 0.1.193 后,同一长会话每轮 local 从约 1.3 秒升至约 3.2 秒;已定位到两项请求入口新增开销,离线 A/B 可消除大部分回归且保持待转发 body 完全一致。

线上证据

时间 2026-10-12 00:13 更新。仍为同一会话、同一 k3-256k 模型,入站仅从 24408→24410 条消息,大小均约 31.9 MiB。更新前最近 10 请求 local 中位数 1336 ms,更新后最近 10 请求为 3175.5 ms(约 2.38 倍,增加 1839.5 ms)。新版第一请求 3986 ms,其余 16 请求仍为 3072–3370 ms。

local 是读取 body 前到转发前的本地阶段,尚未进入上游生成,因此本次回归不能用上游推理慢或首轮冷启动解释。

根因 1:chainFingerprint 无条件计算不用的 SimHash

server/handle.ts 的已识别会话分支调用 chainFingerprint。#2807 改成 wire-neutral 域后,该方法调用 neutralFingerprints(turns),后者无条件计算每个 turn 的 sketchForCanonical,但 chainFingerprint 返回值完全不包含 sketches,identified note 也不保存 sketches。

affinity-simhash.ts 的 SKETCH_MEMO_CAP=8192。重建真实长历史有 24447 个 neutral turns:每轮调用 sketch 24447 次,首轮真正计算 SimHash 22431 次,后续仍为 22391 次。顺序扫描超过缓存容量的输入使 LRU 持续淘汰下一轮需要的项,无法暖起来。

同输入交替顺序 8 组 A/B,去掉前 2 组,chainFingerprint 中位数:

  • 0.1.192:521.24 ms
  • 0.1.193:1939.74 ms
  • 临时原型(仅 chainFingerprint 调用 neutralFingerprints 时不生成 sketch):602.81 ms

8 组原版与原型返回值均 deepEqual。setSimhashAdoptionEnabled(false) 也无法避免这部分计算:仍有 22391 次 SimHash、约 2040 ms。

建议将确定性 hash 与相似度 sketch 的需求分开;不改变 wire-neutral 身份语义,不通过扩大 LRU 掩盖无用计算。其他只使用 .hashes 的 neutralFingerprints 调用方也需一起审计;匿名相似度收养所需的 sketches 必须保留。

根因 2:无图片请求也额外转换两次完整历史

旧版图片索引受 stripImages 条件保护。新版常规请求先 buildIncomingImageIndex,准备后再 refreshIncomingImageIndex(内部再次 build);每次 build 都重新 wire→core 全历史转换后才发现没有图片。

在无图片 fixture 的完整请求暖轮中:旧版 openaiToCore 1 次/166 ms;新版 3 次/518 ms。其中两次图片索引构建合计约 392 ms,包含转换耗时,不能重复相加。新增转换约 351 ms。

建议复用 prepare 已产生的 core 消息或只在确有图片时建立索引,保留图片 ref 刷新和恢复契约。

完整请求 A/B

采用真实历史近似重建、同一状态副本、模拟 HTTP 入口,固定时钟;禁止真实上游转发与持久化,跳过 preflight。fixture 24463 条消息/42.2 MiB,reasoning 和部分 tool-result 前缀未逐字还原客户端策略,不是逐字 HTTP 重放,绝对耗时不等于线上预测。

临时原型仅跳过上面的无用 sketches,并针对已确认没有图片的 fixture 返回空图片索引(验证用途,尚不是生产补丁)。暖轮:

请求 新版 local 原型 local
第 2 轮 3363 ms 1943 ms
第 3 轮 3862 ms 1946 ms

三轮最终待转发 body 的 SHA256 都是 95a62eb6684d98451c14d46a959b393725196be921cf1b523b5abf54142fbe16。kernel 本身仅有几十毫秒级附加成本,未显示秒级回归。

复现方向与回归覆盖

在 v0.1.192 和 v0.1.193 分别创建含 >8192 个不同 turn 的全历史请求,多次原样重发并计时 new PrefixAffinityResolver().chainFingerprint(messages)。输入应包含足够不同的 canonical 内容,避免所有 turn 共用一个 memo key。加入无图片、明确会话 ID 的真实请求入口场景,检查每轮转换次数和输出一致性。

回归覆盖应确保 identified 路径不计算不用的 sketches、匿名路径仍能相似度收养、超过 8192 的重发不会再次全量计算 sketch、无图片请求不做两次额外 wire→core;保留实际图片恢复/ref 刷新场景。

重复问题筛查

已检索 open/closed 的 simhash/perf、neutralFingerprints、affinity/性能、0.1.193/耗时、SKETCH_MEMO_CAP、图片索引/performance,未找到相同回归。#2791/#2807 是跨协议连续性修复,本问题是其 identified 指纹调用产生的 CPU 回归;#2817 的模型切换子会话 fold 继承问题不同。调查时 master 的 prefix-affinity.ts 与 v0.1.193 相同,仍存在该无用计算。

Activity

  1. ranxianglei commented on Oct 11, 2026

    @ranxianglei
    Owner

    🤖 Powered by ework · qwen3.8-27b

    [bot] 🏷

    两个根因均已独立复现并修复,PR #2828 已开:https://github.com/ranxianglei/billion-context/pull/2828(3 commits:fix RC1 / fix RC2 / test,基于 master 47386e6)

    结构化结论(八问)

    1. 是什么问题:0.1.193 起长会话(24K 消息 / 32MiB)每轮请求 local 阶段从 ~1.3s 升至 ~3.2s——请求入口新增的两项 CPU 开销,与上游推理速度无关(local 在转发前结束)。
    2. 什么原因导致的:
    3. 影响范围与严重程度:所有跑 0.1.193 的长会话用户,会话越长越重(随 turn 数线性增长);纯性能退化,无功能/正确性影响——待转发 body 逐字节一致(issue A/B 三轮 SHA256 相同;本修复同样不触碰任何产品字节)。
    4. 怎么修复的:
    5. 是否有回归问题:无。逐项审过既有行为:identified 指纹语义不变(hashes-only 产品逐字节一致);匿名相似度收养在 depth>2048 仍工作(via simhash,coverage≥0.9,测试钉住);暖重发零重算(memo 不再被无用条目冲刷);全部可索引图片 shape 仍被索引(非空洞验证:每个 fixture 同时断言 build 出 ≥1 条);负例保持空索引;guarded ≡ unconditional 全语料 deep-equal。定向套件 prefix-affinity/simhash/image-restore/fold-images-archive 58/58 + orphan 5/5 + typecheck 绿;全量套件交 CI。
    6. 是否破坏缓存:否。sketch memo 的键(item hash)与 LRU 淘汰策略未动,只是不再写入注定丢弃的条目;图片索引持久化/逐出(pruneRetrieveImgExports)路径未动。
    7. 是否改了设计方向:否。保持 dsh anthropic-messages lane bypasses native-intercept fetch patch: anonymous pfa-* session, fold ledger orphaned, silent ~182s re-fold on cross-protocol switch #2791/fix(sessions): wire-neutral affinity hashing for cross-protocol continuity (#2791) #2807 的 wire-neutral 身份语义不变,没有扩大 LRU 掩盖无用计算。审计过的边界:openai 单对象 content {type:"image_url"}(非数组)会触发预检但 kernel 从不为非数组 content sidecar 图片——两种构建都返回 ∅,属 kernel 既有行为,不在本 PR 范围(已在 PR 描述标注 audited-safe)。
    8. 是否引入了新的配置:无。没有新 env/config/CLI flag,纯内部优化。

    行为变更披露(CPU-only):identified 路径 SimHash/请求 ~22K→0;匿名冷 resolve sketch N→≤2048(note() 原本就 slice 到 2048、alignment 从不读 stored cap 之外,可证等价);无图请求额外 wire→core 转换 2→0;有图请求完全不变。

    回归测试 tests/issue2824-regression.test.ts(7 个用例)钉住 issue 要求的性质:identified 路径零 sketch、>8192 重发零重算、cap 外收养仍有效、无图请求零额外转换、有图场景保留。判定:两个根因都在源头修掉(计算需求分离 / 转换前预检),不是症状层打掩码;CI 绿后可合。

  2. added a commit that references this issue on Oct 12, 2026
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

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions