尧图精选

turbovec 持久化性能爬坡全记录:67 个假设、7 个探针与 9 个胜利的测量驱动优化实战

🕒 发布时间:2026/9/13 15:34:38 📁 来源:尧图网络
turbovec 持久化性能爬坡全记录67 个假设、7 个探针与 9 个胜利的测量驱动优化实战【免费下载链接】turbovecA vector index built on TurboQuant, written in Rust with Python bindings项目地址: https://gitcode.com/GitHub_Trending/tu/turbovec本文以 turbovec 仓库中benchmarks/hillclimb/LOG_persist.mdwhole-file persistence hill-climb 结果日志为主体结合GOAL_persist.md目标与规则、bench_persist.py基准、whm_persist.py评分器以及 io_v7.rs、pack.rs、io.rs 源码系统还原这场针对全文件持久化路径write/load的性能爬坡战役。读完本文你将理解turbovec 如何为四个持久化指标单元定义加权目标、如何用假设 → 屏幕测试 → 浸泡确认 → A/B 交错回合的严谨流程逐条验证 67 个优化假设为什么最终 9 个改动被合入、其余被否决或搁置以及测量驱动的优化在触及硬件物理下限fsync 设备提交、内核页清零时如何做出科学的终止决策。背景一场有明确规则限定的性能爬坡LOG_persist.md记录的是 turbovec 仓库内whole-file persistence全文件持久化专项性能爬坡hill-climb的完整过程。所谓爬坡指在一个固定基准baseline之上通过一条假设 → 测量 → 判断胜负的循环逐步逼近性能上限。这场爬坡的目标、规则与前置结论都定义在 GOAL_persist.md 中要点如下作用域write()/write_with_durability()向下贯穿临时文件 原子重命名的持久化协议以及load()向下贯穿 v6 fast 加载路径双架构ARM / x86同时考核。八个指标单元cellssave_warm、save_mut、load、load_search各在arm与x86上测量。权重为save_warm1、save_mut2、load2、load_search0——最后一个单元不参与加分它的存在仅仅是为了否决那种把load的成本挪进首次搜索的假胜利cost-shift gate。胜利判定目标操作的armx86调和均值HM x1.01两个目标单元都不回退所有其他单元含_st单线程护栏单元在 3% 噪声带内cargo test -p turbovec全绿to_bytes往返字节一致性保持。不可交易的红线临时文件协议、原子重命名前的 payload fsync、以及重命名后的父目录 fsync——即持久性下限durability floor永不为了速度而放弃读者永远看不到撕裂的索引。测量环境只在本目标专属的 GCP 机器对turbovec-bench-persistc3-standard-8, pd-balanced/turbovec-bench-arm-persistc4a-standard-8, hyperdisk-balanced上进行两台机器都在pydocs-prod/us-central1-a克隆自 master 机器绝不在 master 上、也绝不在本地测量。每次 release 构建前rm -rf target并LD_PRELOAD对应架构的 libopenblas。循环纪律假设 → smoke3 分钟两台机器→ 仅当 smoke 通过才做 soak-confirm15 分钟。每个假设无论输赢都必须记录在LOG_persist.md。连续 20 个无胜假设即停止任何一次胜利重置计数器。继承的前置否决之前的 six-op 爬坡LOG.md与 save/coldload 专项爬坡已经否决过fallocate、sync_file_range、fdatasync、超过 4 的写线程数、固定 2/4/8 MB 写块、双架构 4 MB 读块、tail-after-codes 顺序、批量 u64 tail 序列化、mmap 加载等。重新打开某个假设必须说明是哪次测量不再覆盖它新的save_warm单元与 ARM 侧不对称是合法理由裸重试不是。基准Baseline15 次重复 × 双架构基线在ea020e35harness 提交库代码与 main 的c8d7ec02相同上测量15 reps/arch结果固定pinned在 persist_baseline.jsoncellarmx86arm_stx86_stsave_warm256.06381.99257.39383.96save_mut259.75383.17260.13384.05load2.468.712.808.92load_search7.8519.2210.9525.28单位毫秒中位数。_st为RAYON_NUM_THREADS1单线程护栏单元。基线本身就能读出三条结构性结论Save 在两个架构上都是设备受限device-bound77 MB 数据ARM 上约 300 MB/shyperdisk-balanced、x86 上约 203 MB/spd-balanced。save_mut只比save_warm贵 ~1.3 ms——单行 add 是惰性追加到 blocked cache 的因此变更后的保存仍走同样的 warm-borrow 路径在此规模下并不是一次独立的重新物化成本。持久化路径上_st≈ MTRAYON_NUM_THREADS根本管不到持久化路径——并行读与并行写都用std::threadscoped 线程按available_parallelism()定大小而不是 rayon 工作线程。所以_st单元被保留为护栏但持久化改动预期会让它们与 MT 孪生单元一起移动。x86 的load是 ARM 的 3.5 倍相同字节x86 读取把interleave_chunk_x86融合进读路径而 ARM 的存储布局本就是原生native的。这个差距就是 load 单元的头部空间而且它落在权重更重的架构对上。测量器Instrument四个操作、权重、护栏与噪声带爬坡的成败完全由 bench_persist.py 与 whm_persist.py 定义理解它们才能读懂日志里的每一个 x1.xxx。bench_persist.py用法python bench_persist.py --arch {arm,x86} [--st] [--reps N] [--out FILE] [--ops save_warm,load]固定规模N200_000, DIM768, BITS4四个操作的测量方式save_warm从文件load一个索引先做一次search把 blocked cache 暖热且不做变更然后write()到临时目录里的out.tvim。每轮之间sleep(0.15)排空设备队列两次 fsync 之间。save_mutload 后执行一次add_with_ids单行id 用20_000_000 rep再write()——即变更后持久化路径。loadIdMapIndex.load(PATH)本身循环重复。load_search新起子进程做load 首次search通过--child参数测的是冷启动的 load首次搜索总时长用来拦截成本转移。whm_persist.py用法python whm_persist.py baseline.json current.json [--target OP]计算八个单元的加权调和均值WHM权重 1:2:2:0并给出胜负判定exit 0 winNOISE_TOLERANCE 0.03非目标单元最多回退 3%。MIN_IMPROVEMENT 0.01目标操作的两个单元armx86的 HM 必须超过 1%。TARGET_REGRESSION_TOLERANCE 0.005目标单元最多允许低于 parity 0.5%。这个容忍度的存在是因为改动常被cfg(target_arch)天然局限在一个架构的代码路径上另一个架构的单元是纯控制组其测量差值是噪声本 rig 实测控制组散布约 0.1–0.3%。0.5% 吸收该噪声同时仍能拦下任何看起来像真实回退的改动——否则 1% 的 HM 门槛会放行单架构的大回退。之所以用调和均值而非算术均值是因为它惩罚一个单元快、另一个单元慢的不均衡任何牺牲某一架构换另一架构的改动都会在 WHM 中现形。探针Probes把地板先测出来日志中最有价值的方法论资产是七个探针P1–P7。它们不产生胜负判定而是把各个单元的理论下限测量出来从而让后续假设要么有靶子、要么直接被证伪。P2x86 load 的 44% 是内核页清零probe_p2.rs 是一个零 crate 依赖的独立探针复刻read_range_parallel_transform在同一个 70.8 MB 区间上的读取只改变目标缓冲区destination buffer的获取方式15 reps 中位数destinationx86arm全新Vec::with_capacity现状6.88 ms1.91 ms预触达pre-faulted排除预触达本身2.65 ms1.04 msMADV_HUGEPAGE匿名映射6.83 ms1.85 ms跨 rep 复用完全没有 fault2.57 ms1.09 ms结论x86 load 约 9.8 ms 中的 4.3 ms44%是目标缓冲区的 first-touch 成本而且不是 fault 次数问题——两台机器 THP 都是always所以MADV_HUGEPAGE毫无作用内核只取少量 fault时间花在清零 77 MB 全新匿名页上而这些页几微秒后就被 pread 覆盖。用户空间没有旋钮可动MAP_POPULATE只是把成本搬家而非移除复用缓冲池则是在优化基准的 load-drop-load 循环而不是产品本身真实调用者只加载一次索引清零只付一次。P2 由此反驳了整个避免目标页 fault假设家族MAP_POPULATE、MADV_HUGEPAGE、预触达、缓冲池。P4save 已经贴近裸金属地板probe_p4.py 完全不含 turbovec 代码只在同一文件系统上复刻 save 路径的形状——临时文件、77 MB payload、fsync、原子重命名、父目录 fsync9 reps 中位数含基准同样的 150 ms 队列排空variantarmx86串行write(2) fsync260.1 ms387.5 ms4 线程pwrite fsync250.3 ms382.9 ms4 线程pwrite无fsync27.0 ms38.9 msturbovecsave_warmH1 树251.0 ms384.0 msturbovec 的 save 在两个架构上都处于裸金属地板 0.3% 以内ARM 251.0 vs 250.3x86 384.0 vs 382.9。90% 的时间是设备提交fsync把整个 payload 填进页缓存只占 ARM 250 ms 中的 27 ms、x86 384 ms 中的 39 ms。因此所有剩余的 save 侧想法都被预先反驳除非它移除 fsync被禁止——那是持久性地板或写更少的字节格式变更且 4-bit 量化码几乎不可压缩。这把fdatasyncsix-op H42、fallocate/set_lenH15、sync_file_rangeH16、块大小扫描H23/H28/H29、O_DIRECT 全部一次性关进盒子里。P1 / P3 / P6x86 load 的成本分解P1环境变量门控绕过interleave_chunk_x86x86 load-only3×15 reps带变换 9.85 ms、不带 9.28 ms——整个 SSSE3 变换只值 0.57 ms约 6% 的 x86 load且大部分已藏在被融合的 pread 后面。这给整个让变换更快家族设了上限即使变换免费也只买 6% 的一个单元现实的 SIMD 加宽大概只能买一半。P3load 阶段分解x86 的try_load_v6_fastcodes 读 tail8.30 ms、id 表解码 0.42 ms、TurboQuantIndex::from_loaded~0 ms、重复 id 克隆排序 0.32 ms、未归属部分pyo3/分配/drop0.58 ms合计 9.61 ms。结合 P1/P2x86 load ≈~2.6 ms 真实拷贝 ~4.3 ms 页清零 ~0.6 ms 变换 ~0.8 ms 串行 tail 工作 ~0.6 ms 未归属。两个大项是地板串行 tail 工作不是——那是 H3 的攻击目标。P6H17/H18/H21 之后重新分解codes 读 重叠 tail 7.0–7.9 msx86/1.5–1.9 msARM重复检查克隆排序 0.31/0.20 msid 解码 pyo3 drop ~0.5/~0.3 ms合计 ~7.9/~2.0 ms。读取已占 x86 load 的 88%、ARM 的 ~80%。写路径Save的攻防一次胜利与整套证伪save 侧从一开始就贴着 P4 测出的地板所以这里的攻防最有戏剧性唯一的大胜发生在写路径刚打开的入口处。H1胜把并行定位写入器扩展到所有架构write_atomic_parallel——head/tail 按计算好的偏移 pwrite、codes span 拆给 scoped 线程——原本是#[cfg(target_arch x86_64)]其余架构回落到单BufWriter流的write_atomic。但 x86 门控从来不是关于 x86 的它是随 fused 每块 deinterleavesix-op 爬坡 H19引入的而 deinterleave 才真正是 x86 专属ARM 存储布局已原生。底层的 writer 是架构中立的——于是 ARM 在 fsync 开始前把 77 MB 串行写进页缓存而这完全没必要。改动把write_atomic_parallel、head_core、tail_core、write_all_at的架构门控去掉改为cfg(unix)/cfg(windows)CI 两个都构建两个写入口无条件指向它x86 之外codes_transform: None删除不再可达的write_atomic。持久化协议分毫未动同一临时文件、重命名前同一sync_all、重命名后同一父目录 fsync。正确性cargo test -p turbovec在 aarch64 全绿14 binaries, 0 failures。日志特别指出一个测试盲区所有既有字节一致性测试都构建 64×32 的索引比写入器切到线程分支的 8 MB 阈值低了三个数量级——块路径在任何架构上都没有字节级测试x86 也没有。于是新增large_payload_parallel_write_matches_streamed_bytes9.2 MB 合成 payload 分别走io::write/io::write_id_map并行与io::write_to/io::write_id_map_to流式断言两种格式逐字节相等。A/B 测量3 轮交错 × 15 reps与基线同进程操作顺序save_warm-arm257.35 → 250.39x1.028、save_mut-arm260.35 → 252.61x1.031x86 四个单元全部在 0.1% 内x86 是控制组——改动移除的是 x86 从未走过的门控其路径逐位相同。目标 HM x1.0133save_warm与 x1.0145save_mut达标。一个方法论插曲目标单元检查原本零容忍x86 那 0.1% 的控制噪声让 H1 差点被误杀。whm_persist.py因此把容忍度放宽到 0.5%并写明其用途是吸收控制噪声而不放行真实回退。_st护栏2 轮交错RAYON_NUM_THREADS1ARMsave_warm-arm_st257.30 → 250.60x1.027、save_mut-arm_st261.15 → 253.44x1.030x86_st在 0.15% 内。胜利带进单核——因为 writer 线程来自available_parallelism而非 rayon 池这正是持久化_st单元始终紧跟 MT 孪生单元的原因。Verdict: WIN提交 3d2bdef6PR #479连胜计数归零。save 侧的其余攻防全部贴近地板全部失败H1 之后save 侧的所有假设都在为 P4 的裸金属地板做注脚H7写线程上限 8失败x0.991–0.997。上限 4 是 six-op H22 在 x86 上定的H1 之后 ARM 用上了同一 writer且 ARM 设备快一半308 vs 201 MB/s值得一试——但 P4 已说明页缓存填充只是 ARM 250 ms 里的 27 ms多余写线程只能争抢一个已经饱和的队列。H34 / H52 / H62每写线程两块 / 三块 / 三块预留 tailH34 在 x86 上 x1.0064 且 5-of-5但 P4 地板是 382.9 ms381.5 已到顶——方向正确、余量耗尽。H52 把 x86 推到 382.5–382.9 ms精确命中 P4 地板。H62 叠加后 x86 383.2 ms 对 382.9 ms 地板栈有效但天花板才是约束。三个改动都只能让 x86 走完最后一毫米却每次让 ARM 付出 0.3%。H35写线程上限 2x86 0.9785-of-5 变慢。两个写线程喂不满较慢设备上的队列——与 H7 互为镜像4 是饱和点两个方向都不如它。H36预保留 tail 缓冲约 4.8 MB 不必要的复制真实存在但不可见——亚毫秒对 P4 钉死的设备地板。x86 持续微正、处处在噪声内正是真实但低于测量地板的模样。H55跳过重复保存的 stale-temp 扫描读代码即证伪——扫描已被claim_first_sweep(path)每路径 memo 门控第二次及以后的保存完全跳过。基准 21 reps 只付一次真实调用者每路径每进程付一次。H56head/tail 与 codes 写线程并行ARM 0-of-3。与这台 rig 上每次重叠尝试同样的模式在已饱和的机器上额外生成的线程比它隐藏的串行更贵。H57去掉set_len预分配双向 parity——加上分配提示无用H15移除现有的也无用。保留它预置大小的文件对文件系统更友好且无可测成本。H58每块sync_file_range写回 nudgex86 0.36%3-of-3ARM 无收益——内核自身写回已让队列保持忙碌x86 残余的空闲是 H34/H52 也在追的 straggler。H63预置 writer 线程的 deinterleave 暂存parity——每线程每 save 只发生一次且被其后的设备提交淹没。H67并行路径阈值降到 4 MBparity 且必然如此——77 MB payload 两个阈值都远超这是与 H40 同形的可证空改动日志特意记录它因为常量真实且从未被扫过空结果反而确认 rig 行为正常。H32save_mut与save_warm的差距纯算术证伪ARM 上save_mut比save_warm贵 ~3 ms254.3 vs 251.2x86 贵 ~0.6 ms而 P4 地板是 250.3 / 382.9——所以save_warm就在地板上save_mut略高。根因是单行add_with_ids重分配了 77 MB blocked cachewriter 随后流式写的是页缓存中冰冷的全新映射缓冲而不是save_warm借用的暖缓冲。这是 add 的成本出现在下一个读者身上不是 writer 做了两遍工作。即使完全消除save_mut-arm也只有 x1.016、x86 x1.0016目标 HM x1.0088——在横杠之下且从写路径根本不可消除缓存变冷是 add 造成的。Verdict: NON-WIN (arithmetically refuted)。读路径Load的攻坚从 8.71 ms 到 7.22 ms 的每一步load 侧是这场爬坡的主战场x86 load 从基线 8.71 ms 压到最终 7.22 msx1.21ARM 从 2.46 ms 压到 2.01 msx1.22。九次胜利中七次落在 load 侧且呈现出一条清晰的因果链。H3胜.tvimid 表只解码一次而非四次200k id 时 id 表为 1.6 MB加载路径却搬运了它四次进入 tail 缓冲真实读取、read_tail内tr.to_vec()再搬出、load_id_map中read_exact_vec_capped进入raw、最后collect进Vecu64。只有第一次和最后一次不可约——字节是小端且未对齐需要一次解码遍历但两个中间缓冲都不需要。try_load_v6_fast现在交还 tail 缓冲加余量起始偏移而不是一份新拷贝的Vecload_id_map直接从该切片解码Vecu64。截断检查被显式写出短 id 表仍以read_exact_vec_capped产生的精确UnexpectedEof消息失败——from_bytes-vs-load的错误一致性测试钉住了它。A/B3 轮 × 15 reps完整 4 操作顺序load-arm2.55 → 2.47x1.032、load-x868.69 → 8.41x1.033、load_search-arm9.43 → 8.17x1.154、load_search-x8621.09 → 20.48x1.030save 单元控制组 x0.998–x1.001。目标 HM x1.0328 达标。一个关键洞察胜利大小取决于进程堆有多暖。纯 load-only A/B之前什么都没跑把同一改动测到 ARM x1.218、x86 x1.109——那里每个 1.6 MB 分配都在新鲜页上 fault、支付 P2 测出的清零。而在 4 操作顺序里 save 循环已撑大堆malloc 归还暖内存同一移除只值 ~3%。B 侧无论哪种顺序都落在 ~2.47 msARM——这个改动不是让 load 更快而是让 load 对堆状态不敏感。H11胜AVX2 交织 非清零 tail 缓冲叠加过关H5AVX2 交织单独与 H9未初始化 tail 缓冲单独各自在固定的 4-op 测量器上测到 x1.005–x1.009都低于 1% 横杠被单独否决。H11 的论点是两者相互独立一个是 x86 SIMD 内核一个是 tail 读取上的分配它们的和是不同的声明可以在同一环境下检验。A/B5 轮 × 21 reps完整 4-opload-x868.482 → 8.297x1.022、load-armx1.001、save 单元 x0.998–x1.004。目标 HMx1.0116。中位数低估了一致性B 在两个架构上都是 5-of-5 更快两个五次掷硬币给出这种结果的概率是 1/1024。cargo test双架构全绿29 binariesx86 上avx2_interleave_matches_ssse3真实执行 AVX2 路径。load_search的 ARM 单元在 5 轮时读 x0.918 会挂掉该 run——但该单元在 ARM 上以 run 级别双峰样本簇聚在 ~6.5 与 ~9.5 ms11 轮复测ARM x1.1728-of-11、x86 x0.993均值差 0.06%。没有成本从load挪进首次搜索。Verdict: WIN。H17 / H18 / H21三连胜按是否融合变换分块然后是块大小与每线程块数H15 与 H16各自在双机上以 5-of-5 的相反方向分裂ARM 赢、x86 输看似主机怪癖实则不是x86 读把 perm0 交织融合进读取每块承担相同的每字节计算块时间均匀——均匀成本想要每线程一块的平分、无掉队者其余地方ARM存储布局已原生剩下的是页 fault 与页缓存方差不均匀想要块比线程多以便工作队列偷取stealing。H17胜块大小以transform.is_some()为键函数手里已有的属性而非cfg(target_arch)——融合变换时用len/n_threads否则用固定 8 MB。A/Bload-arm2.476 → 2.342x1.0574-of-5、load-x86x1.010分支按构造不变纯噪声、load_search双架构都改善。目标 HMx1.0330达标。H18胜把无变换侧的偷取块从 8 MB 减半到 4 MB。load-arm2.327 → 2.019x1.1535-of-5x86 按构造不变。ARMload_search在 5 轮读 x0.803又是 H11 撞过的双峰11 轮复测中位数 x1.134——改善。目标 HMx1.0702达标。H21胜变换侧从每线程一块改为每线程两块。理由计算均匀但底层页 fault 不均匀掉队者仍在、只是更小每线程两块保持平分并让掉队者代价减半。A/Bload-x868.384 → 7.782x1.0775-of-5ARM 分支未动。目标 HMx1.0432达标。load_search-arm的 0.944/0.926 读数被 11 轮拆穿是双峰样本的硬币翻转A 抽 4 个低模式样本对 B 的 2 个B 5-of-11。H38 / H41双连胜把解码与排序搬上 tail 线程且只搬该搬的H6败把 id 解码和排序表构建一起搬上 tail 线程x0.812/x0.913 惨败——3.2 MB 分配落入重叠窗口与八个已占满内存带宽的读者线程直接争抢。但这次证伪的是配对而非解码排序克隆占一半分配解码并不需要它。H38胜只搬解码1.6 MBloader 反正要建的Vecu64排序构建留在 join 之后串行处独享机器。A/Bload-arm2.200 → 2.129x1.0335-of-5、load-x867.942 → 7.881x1.0085-of-5。目标 HMx1.0204达标。load_search-x86的 5 轮 x0.957 在 11 轮复测为 parity。H41胜H6 搬解码排序一起输、H38 搬解码独赢后剩下的问题变成第二个 1.6 MB 是否也塞得进重叠窗口——结论是塞得进因为 tail 线程在 codes 读 join 前很久就完成解码竞争窗口已不是 H6 测的那个。通过 crate 内部load_id_map_prepared正经贯通返回排序表与 ids 并列公开load_id_map委托并丢弃之IdMapIndex::load采纳重复拒绝逻辑原样保留、错误种类与消息不变。A/Bload-arm2.134 → 2.008x1.0635-of-5、load-x867.812 → 7.671x1.0184-of-5。目标 HMx1.0401达标。load 侧的完整否决清单节选H4流式解码 f32 数组机制真实但无可咬之处——H3 已把工作移出关键路径对早完成线程再省 800 KB 毫无所获。x0.989–x1.015ARM 在 parity 错误侧。H12小端上字节拷贝解码 id 表x1.0000/x1.0004 精确 parity——LLVM 已把循环降级为拷贝0.42 ms 是拷贝加目标页 fault都是地板。算术也早已预言0.42 ms 搬 3.2 MB 7.6 GB/s已是新鲜页上的 memcpy 速度。H13表已升序则跳过排序parity-to-略差——pdqsort 检测升序段在线性遍历中直接返回守卫加了一次扫描、什么都没移除。P3 归于dup_sort的成本是 1.6 MB 克隆不是排序本身。H14按物理核而非 SMT 兄弟定读线程数x0.9525-of-5惨败。探针说用物理核、真实路径说不对——x86 loader 是边读边变换融合交织是计算SMT 兄弟对拷贝无用、却隐藏其延迟。教训在探针而不在机器融合循环的独立模型可以反转答案。H231.5x 读者线程load-x86x1.019 过杠但load_search-x8618.673 → 20.475x0.9125-of-5 变慢——这是权重 0 的门单元干它该干的活十二个读者线程把 codes 缓冲的首触页散布到比搜索运行的核更多的核上搜索为 load 省下的局部性买单。目标 HM x1.0103 本会被记为胜利没有它的话。H25mmap codes 区三重证伪——coldload 爬坡直接测过24.0 vs 20.5 ms 原始读x86 不放弃融合交织就无法工作写入映射会逐页 fault-and-copy且把 fault 成本挪给先触碰页面的人——正是load_search要抓的还会把被截断文件下的干净io::Error变成SIGBUS。H29AVX-512 交织P1 已把整个 SSSE3 变换限定在 0.57 msH5/H11 拿走大部分剩余是仪器分辨率之下±1%的零头还没算该 uarch 的 512-bit 降频风险。H30tail 内联而非 scoped 线程ARM x0.8595-of-5——重叠仍然值得ARM 2.03 ms load 中 0.33 ms 是 codes 读当前完全隐藏的 tail 工作。H31AVX2 预取推到 8 KBparity——流完全顺序硬件预取器已覆盖软件提示在任一距离都是装饰。H37huge-page 对齐 codes 目标纯算术证伪——错位余量至多每端一个大页、77 MB 的 ~2.6%至多 4.3 ms fault 成本中的 ~0.11 ms正确实现需要自定义对齐缓冲类型替换Vecu8为大额 1.4% 做大型重构。H42tail 读放到调用线程双架构 x0.983——省下的 ~25 us 生成在 P7 地板内而把 tail 钉在拥有 reader scope 的线程上把它绑在该核的队列。H44tail 解码拆两线程x0.991/x0.992——第三次同一课H6、H42、现在加进重叠窗口的工作与读者争抢它们受制于的内存带宽第二次生成比它移除的串行半块更贵。H45逐向量 scales 批量预检parity——~0.1 ms 的扫描坐在反正 join 前就完成的线程上弄便宜它不缩短任何关键路径。H47胜三块每线程→ H48败五块每线程H47 在 H38/H41 结构性变化后重扫变换侧块数load-x867.659 → 7.224x1.0605-of-5目标 HM x1.0400 达标。H48 的屏幕 2.3%2-of-3在 11 轮浸泡中原形毕露——x0.9743-of-11正是 ±1.5% 地板透过 3 轮样本显现也是 P7 存在的理由。三块每线程是新的最优两块是 x0.94、五块是 x0.97。H49 / H54变换子块 1 MB / 128 KB双双噪声或低于杠。256 KB 保留——现在已扫过 64 KBH10、512 KBH33、1 MBH49、128 KBH54与两种不同外层块大小宽带上平直、边缘处更差。H501.25x 读者线程屏幕即被门单元否决——load_search-x86x0.9450-of-3与 H23 同形。读者线程数至此扫完 0.5xH14、1x、1.25x、1.5xH23available_parallelism是答案两个方向以不同理由失败线程少饿死融合变换线程多让首次搜索失去局部性。H512.67 MB 偷取块ARM走该分支的架构屏幕 x0.958 直接否决而 x86 在同一屏幕上读出 x1.214——在一个 x86 从不执行的代码路径上——是日志中为什么三轮只筛不决、为什么每条目带逐轮胜数最清晰的一次插图。H59读前posix_fadvise(WILLNEED)parity 且只能如此——基准文件在计时 rep 开始前已被完全页缓存没有 readahead 可建议。这只有在真正冷文件上才有意义而目标里没有冷文件单元load是暖测load_search测冷进程而非冷文件。H60每块一次读之后按 L2 大小分片变换x0.970——它说出了融合到底为什么存在交错读与变换意味着每片 256 KB 在copy_to_user刚写入它时仍在 L2 中就被变换先读 3.2 MB 会在变换到达前逐出早期分片比十一次 syscall 更贵。H61重复扫描也搬上 tail 线程parity——线性扫描 1.6 MB 且该数据刚从排序写入、已在 L2约 0.05 ms低于 rig 分辨率一个数量级。方法论为什么这些接近但不过杠的改动被诚实拒绝日志最有价值的不是九次胜利而是对测量器本身的批判性考察——尤其 H5/H9 章节后附的为什么固定的仪器要保留即便它让两次胜利打了水漂。H5 与 H9 在 load-only 运行中舒适地过杠在基线所在的 4-op 运行中刚好低于横杠。诱人的举动是宣布 load-only 运行是更好的仪器并重新计分。其控制侧散布说明问题——峰值到峰值的A侧按构造不可能移动的instrumentx86armfull 4-op4.97%, 5.62%2.23%load-only1.44%, 1.67%5.17%Load-only 在 x86 上干净三倍、在 ARM 上脏两倍。没有统一的更优仪器切换仪器就等于按假设挑一个更衬托结果的上下文——这正是爬坡把自己骗进不存在的胜利的方式。固定的 4-op 测量保持原样H5 与 H9 保持未合并。两者都是真实、机制已理解、无单元回退的改进被推荐给维护者作为目标函数在此规模下无法裁决的后续项它们随后被折叠进合并了的 H11。同样的诚实还体现在P7 双峰识别ARMload_search是 run 级双峰单元样本簇聚两个模式5 轮读数不可信、11 轮才可靠——日志为此专门引入屏幕只筛不决、每个条目带逐轮胜数的纪律。H14 的教训独立探针模型融合循环会反转答案所以探针只用来测地板、不用来定结论。H23 的门单元权重 0 的load_search否决了一个本来会被记为胜利的目标 HM x1.0103——成本转移被拦截在跨单元作弊发生之前。阶段终止与最终战果爬坡经历过两次终止第一次十二个连续无胜而非规则的二十因为剩余假设池被测量而非困难性关闭——P4 把 save 钉在设备自身 writefsyncrename 的 0.3% 内P2 把 x86 load 的 44% 放进 THP 已是always的内核页清零读周边的每个调度旋钮都双向扫过且幸存者已提交。达到二十意味着记录不产生信息的假设日志付出大于所得。第二次H48–H67 连续二十个无胜停止规则正式满足爬坡结束。提交于 LOG_persist.md 的最终战果表#改动收益H1并行定位写入器扩展到所有架构ARM save x1.028 / x1.031H3.tvimid 表只解码一次而非四次load HM x1.033H11AVX2 交织 非清零 tail 缓冲叠加load x1.022 x86H17读按是否融合变换分块load x1.057 ARMH184 MB 偷取块load x1.153 ARMH21变换侧每线程两块load x1.077 x86H38id 解码搬上 tail 线程load x1.033 ARMH41排序重复检查表也在其上构建load x1.063 ARMH47变换侧每线程三块load x1.060 x86六十七个假设、七个探针、九次胜利。对固定基线的最终位置cellbaselinenowspeedupload-arm2.462.01x1.22load-x868.717.22x1.21save_warm-arm256.06251.4x1.019save_mut-arm259.75254.6x1.020save_warm-x86381.99384.9x0.992在设备地板save_mut-x86383.17385.2x0.995在设备地板两个地板都是测出来的、不是假设的。save 在两台机器上都在裸金属 writefsyncrename 的 0.3% 内P4——x86 单元略低于基线是因为基线取自同机型的不同实例且四次独立尝试H34/H46/H52/H62确认那里剩余不足一毫秒的 straggler。load 在 x86 上 ~88% 是 codes 读其中 44% 是内核清零被读取覆盖的目标页P2THP 已开启。对读者的工程启示先测地板再爬山。P2 与 P4 是这场爬坡最重要的两个产出——它们把每个想法都试一遍变成按测量关闭整个假设家族。任何优化工作开工前先问物理下限是什么可以省下几十轮无效假设。仪器本身需要辩护。H5/H9 的处置展示了如何对抗确认偏误当仪器选择会翻转结论时固定测量器、如实记录、把无法裁决的改进折叠进可裁决的组合H11。门单元的价值在于否决。load_search权重 0 却拦下 H23 这样的真胜利——跨阶段/跨单元的成本转移是优化最容易自我欺骗的地方需要专门设一个只看不奖的守卫。假设要带逐轮胜数。H48/H49/H51/H61 的教训一致3 轮屏幕的 ±1.5% 地板可以伪造 2-of-3 的接近胜利只有 11 轮浸泡和逐轮统计才能区分信号与硬币翻转。在物理下限前科学终止。第一次终止在十二个无胜理由是剩余池已被测量关闭而非我们累了——这比机械执行二十次规则更诚实也为后续爬坡重开条件记录在案隔离测量的 load 单元、格式变更、或设备不再是瓶颈的机器留下清晰入口。这场爬坡的完整原始数据、每个假设的 A/B 表格、探针代码与探针脚本均保留在 benchmarks/hillclimb/ 下结果日志在 LOG_persist.md目标与规则在 GOAL_persist.md基准在 bench_persist.py 与 whm_persist.py探针源码在 probe_p2.rs 与 probe_p4.py基线数据固定在 persist_baseline.json。感兴趣的读者可以直接复跑或深入源码如 io_v7.rs 的写入/加载路径、pack.rs 的interleave_chunk_x86与seq_into_native、io.rs 的临时文件与claim_first_sweep机制验证每一个结论。【免费下载链接】turbovecA vector index built on TurboQuant, written in Rust with Python bindings项目地址: https://gitcode.com/GitHub_Trending/tu/turbovec创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联 返回资讯列表 →