Chrome 用 jxl-rs 上线 JPEG XL
这是 Chrome 团队关于在浏览器里解码 JPEG XL 的说明。从 Chrome 155 起,Chrome 开始解码 .jxl。文章作者是 Moritz Firsching 和 Philip Jägenstedt,发布日期 2026-10-06。
JPEG XL 相对 JPEG 的压缩率高 30% 到 50%,支持无损压缩、HDR,以及把 JPEG 无损转成 JPEG XL。文章建议同时试 AVIF 和 JPEG XL。JPEG XL 的位置是高保真或无损压缩,尤其是照片,以及需要细粒度渐进解码的场景。
解码器用的是 jxl-rs,一套纯 Rust 的 JPEG XL 解码器。图片解码器处理来自网络的二进制结构,跑在渲染进程里。Chrome 把 jxl-rs 接进浏览器,用来处理 C++ 解码器里常见的越界读、堆溢出和 use-after-free。
SIMD 使用已经稳定的 target_feature_11,调用 SIMD 指令时不用再写 unsafe。上面有一层 jxl_simd,思路来自 C++ 的 Highway。unsafe 限制在少量经过检查的位置。性能优化沿用 libjxl,包括跨区域边界的处理管线,并减少数据拷贝。性能数字记在 jxl-rs performance dashboard。文章写到,fuzzing 和 AI review 没有在 jxl-rs 的实现历史上发现内存安全缺陷。
JPEG XL 是 Interop 2026 的热门提案。Chrome 参与了 Interop 2026 JPEG XL Investigation,补浏览器侧的测试覆盖。jxl-rs 和 Chrome 集成的主要贡献者包括 Helmut Januschka、Martin Bruse、Zoltan Szabadka、Sami Boukortt、Wonwoo Choi。
原文链接:https://developer.chrome.com/blog/jpeg-xl-in-chrome
1.99.0 的 FFI bool 返回值缺了掩码
这是 rustc 的误编译问题,编号 rust-lang/rust#163911,报告人 wezm。标签包括 I-miscompile、P-critical、A-LLVM、A-codegen、A-ABI、C-bug、T-compiler。问题仍开放,assignee 是 saethlin,创建时间 2026-10-07。
复现仓库是 yeslogic/rust-bool-ffi,平台是 x86_64 Linux,gcc 和 clang 都能复现。C 侧调用 extern bool rust_fn_returning_bool(unsigned char),传入 0x10。Rust 函数是 pub unsafe extern "C" fn rust_fn_returning_bool(flags: u8) -> bool,函数体是 (flags & 0x1) == 0x1。期望打印 0,实际打印 16。
1.99.0 生成的汇编是 movl %edi, %eax; retq。1.98.0 在 ret 前还有 andb $0x1, %al。少掉的这条 and 把入参低 8 位里的高位留在返回值里。报告里的 rustc 是 1.99.0(b940084d7,2026-09-28),LLVM 23.1.1。nightly 1.101.0-nightly(ea137335b,2026-10-05)同样能复现。aarch64 和 loongarch64 上,返回前会做掩码。
评论里 asquared31415 对比了 LLVM IR。变化前是 define noundef zeroext i1,变化后是 define noundef i1。LLVM 因此可以不修改高位。现有测试覆盖 x86_64-unknown-uefi。x86_64-unknown-linux-gnu 不在这份测试里。ds84182 引用 x86-64 psABI:bool 返回值的 bit 1 到 bit 7 必须为 0,bit 8 及以上未定义,所以至少要零扩展到 8 位。相关旧问题是 aarch64 上的 #159244,以及修复 PR #159317。
原文链接:https://github.com/rust-lang/rust/issues/163911
derive(Debug) 会带上 inline
这是 yossarian.net 上的一篇说明,讲 #[derive] 展开后的实现经常带 #[inline]。参考文档用例子写出这一点,展开宏也能看到。
#[derive(Debug)] struct Widgets { foo: u32, bar: usize } 展开后,fmt 带 #[inline],函数体调用 Formatter::debug_struct_field2_finish。#[inline] 是提示。短的 Debug、Clone 实现经常会被内联。
嵌套错误类型会把体积放大。文章里的例子是 ErrorA 有 7 个 String 字段,ErrorB 包 ErrorA,ErrorC 包 ErrorB,Errors 枚举再包这三层。每一层 Debug 都标了 #[inline]。Errors 的每次 Debug 都可能把整棵实现内联进去。调试或 trace 日志会反复走到这条路径。
作者在 uv 上用自己的 proc macro 替换 derive(Debug),改成 #[inline(never)]。二进制大约小了 160KB。文章记录到,rustc 看起来没有按 Debug 实现的体积或内联次数设上限。
原文链接:https://yossarian.net/til/post/rust-s-derive-often-implies-inline/
Zizq:出队从 40 毫秒降到 4 微秒
Zizq 是用 Rust 写的任务队列服务器,当前版本 0.7。数据存在进程内的 fjall 里。fjall 是基于 LSM tree 的嵌入式键值库,没有单独的数据库进程。
最初的 ready 索引用 ready/{priority}/{id} 做有序扫描。出队删除队头键时,LSM 不原地删除,只追加 tombstone。扫描 ready/ 找下一条活键时,要从队头跳过这些 tombstone。队列在一端写入、在另一端删除,扫描又从删除的那一端开始。Raspberry Pi 5 的吞吐测试里,tombstone 堆起来之后,找下一条任务大约要 40 毫秒。每次出队都付这笔开销。
现在 ready 索引放在内存里,fjall 仍保存任务记录。同一台 Raspberry Pi 5 上,找下一条任务从大约 40 毫秒降到大约 4 微秒。持续吞吐下这个时间保持稳定。内存索引只作提示。任务可能在 worker 取键和真正领取之间被 API 删除或换队列。
worker 断线检测原先要等 TCP 超时。测试里,伪造 worker 主机消失后,连接关闭、in-flight 任务回到 ready 用了 943 秒。Zizq 现在默认把 TCP_USER_TIMEOUT 设为 30 秒,和官方客户端 30 秒无数据即重连对齐。同一套测试里,任务回到 ready 只要 30 秒多一点。
写路径上,fjall 一次只允许一个写事务。Zizq 在服务器空闲时把单次请求立刻提交。提交进行中到达的请求并进下一批,不另加固定等待。journal 的 fsync 也按同样方式合并。文章记录到超过 100,000 jobs/s 的观察值。
原文链接:https://zizq.io/blog/what-we-learnt-building-a-job-queue-on-an-lsm-tree
From Rust中文社区 Mike
社区学习交流平台订阅:
评论区
写评论还没有评论