崮生(子虚)
|
f0a5ac175f
|
chore: 删除误提交的临时 profile 脚本
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-24 15:14:45 +08:00 |
|
崮生(子虚)
|
b17d5a3700
|
perf(gsub): lookup 级全空预扫描跳过逐子表序列化
subsetGSUB 对每个 supported lookup 预扫描所有子表是否都 coverage 全子集外
(isSubtableSkipableByCoverage)。全空 lookup 序列化结果必然是 N 个空 subtable
(与逐子表 serializeSubtable 失败后 writeEmptySubtable 逐字节相同),直接在 lookup 级
批量写空,跳过 N 次 serializeSubtable 函数调用 + 预检 + rollback 开销。
初夏 lookup[5] type6 268 子表(小子集全不命中)是典型受益场景。
安全性:allEmpty 当且仅当所有子表 isSubtableSkipableByCoverage===true,而 serializeSubtable
内部对 skipable 子表直接 return false(→空 subtable),故输出逐字节相同(含 FiraCode 连字)。
format2 class 驱动子表不预检(返回 false),含 format2 的 lookup allEmpty 必为 false 走原路径。
subCount 不变、lookup 不删(区别于已证危险的 GSUB lookup 删除)。
subsetGSUB 初夏 0.215→0.178ms(-17%),全基准 SSIM 与输出字节完全不变(diff 验证 hash 一致)。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-24 15:14:00 +08:00 |
|
崮生(子虚)
|
8a7efea9d0
|
perf(gpos/gsub): read 零拷贝 subarray 替代 readBytes slice
GPOS/GSUB 表类 read 原用 reader.readBytes (= new Uint8Array(view.buffer, off, len).slice()),
.slice() 拷贝整个表字节(初夏 GPOS 68KB、GSUB 31KB)。V8 中 68KB slice 耗 ~40μs,
而 subarray 零拷贝仅 ~0.3μs(130× 差距)。
GPOS/GSUB 是原始字节透传:subsetGPOS/subsetGSUB 只读 OTReader + 写全新 OTWriter,
write 只 writeBytes 只读,optimize 不碰,整个 read→optimize→subset→write 生命周期
从不原地修改底层字节,故可安全返回共享 ArrayBuffer 的 subarray 视图。
初夏 full read 0.124→0.063ms (-49%),readBuffer 0.165→0.098ms。
全基准 SSIM 与输出字节完全不变。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-24 15:07:18 +08:00 |
|
崮生(子虚)
|
ee7b6ec230
|
perf(gpos): 全空 lookup 折叠为 subCount=1 + subtable 偏移槽消除闭包
优化330: 预扫描 supported lookup 的 subtable coverage 命中,全无命中的 lookup
折叠为单个空 subtable(feature 按 lookup index 引用,subCount 改变语义等价,
浏览器查空 coverage 即跳过)。大字体小子集场景(初夏 GPOS lookup[10] 283 个
SinglePos subtable 全空、lookup[7] 285 个仅 3 命中)原先逐空 subtable 序列化
是 subsetGPOS 主热点。unsupported lookup 同理折叠。
subsetGPOS 初夏纯标点 570→380μs(-33%)、思源 8 字 85→26μs(-70%)。
附带 woff2 体积下降(空 lookup 不再逐 subtable 输出):思源 8字 2632→2536B、
初夏纯标点 6940→6912B。SSIM 全部不变。
优化329: lookup 循环 subtable 偏移槽用 writeUint16 占位 + writeInt16At 统一回填,
替代 reserveOffset16 的 per-slot 闭包分配(短命闭包虽 V8 近乎免费,但简化代码)。
|
2026-07-24 14:57:02 +08:00 |
|
崮生(子虚)
|
852f0d2f21
|
perf(ot-bytes): OTWriter 初始容量 256→2048 + 内联容量检查消除热路径函数调用
subsetGPOS 思源 36→33μs、subsetGSUB 13→11μs;writeUint16 是序列化第一热点
(思源 207次/call),原 per-call ensure() 函数调用在 V8 class private method
不内联;内联为容量判断 + grow,并预分配 2048 避免小输出多次扩容拷贝
|
2026-07-24 14:40:05 +08:00 |
|
崮生(子虚)
|
04bf5c6077
|
perf(os2): size 固定返回 96 跳过通用 struct 查表(version 恒 0x4)
|
2026-07-24 14:33:54 +08:00 |
|
崮生(子虚)
|
82c1e42108
|
perf(name): subset 字体 name 表白名单,仅保留渲染必需 6 个 nameId
subset 字体核心目的是小体积下载 + 正确渲染,但 name 表保留了全部 19 个 nameId
(含版权/商标/URL/版本/描述等元数据)。思源 8 字 ttf 8.8KB 里 name 占 3.9KB(44%),
多为这些 web 渲染无用的元数据,徒增 brotli 输入与下载体积。
size 阶段加 KEEP_NAME_IDS 白名单,只保留浏览器字体匹配/渲染必需的:
1 fontFamily / 2 fontSubFamily(CSS font-family 与 weight/style 匹配核心)
4 fullName / 6 postScriptName(全名与 PS 名)
16 preferredFamily / 17 preferredSubFamily(变体/typographic 匹配)
体积收益(SSIM 全部不变,渲染像素不受 name 内容影响):
思源 8 字 woff2 4448→2632B(-41%)、思源千字文中段 19100→17156B(-10%)
FiraCode 11636→10828B(-7%)、思源标点 4864→3048B(-37%)
令东千字文 -0.5%(name 占比本就小)。brotli 输入减小附带压缩提速。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-24 14:22:11 +08:00 |
|
崮生(子虚)
|
089ae7c0a7
|
perf(name): read 单遍扫描定 platform,消除全部中间 nameRecord 对象
原 read 先建 count 个 {platform,encoding,language,nameId,length,offset} 中间对象,
再两遍遍历它们。改为两趟直扫 view:
pass1 只读 platform/encoding/language 三字段比较定 platform(windows english 优先),
不读 nameId/length/offset、不建对象;
pass2 头开始只对匹配记录读 nameId/length/offset + readBytes + 解码,直接产出 names。
思源 56 条记录中间对象 56→0,view 读次数减半。字节 sha256 完全一致,
5 轮交替 readBuffer median 稳定 -3~-5%(对象分配本身 V8 近零成本,收益小但一致)。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-24 12:53:04 +08:00 |
|
崮生(子虚)
|
ba17974e1d
|
perf(name): read 延迟 readBytes,按需只解码选中 platform 的记录
原 name.read 第一遍循环对全部 count 条记录都 readBytes(每次 slice 一份字节),
但最终第三循环只对匹配 platform+encoding+language 且 nameId 有用的记录解码字符串,
其余记录的 .name 字节从不被消费。思源 56 条记录只解码约 15 条,浪费 41 次 slice。
改为删除第一遍全量 readBytes,在第三循环里对匹配记录按需 readBytes,
N 次 slice 降到「有用记录数」次。字节 sha256 完全一致(思源/令东验证),
思源 readBuffer median 0.021→0.014ms(-34%),令东持平(name 表小本就无浪费)。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-24 12:50:28 +08:00 |
|
崮生(子虚)
|
d6d94e201e
|
perf(os2): read 改用直接 DataView 批量读取
OS/2.read 原走 struct 通用 read(逐字段 switch 分发 + reader.read 调用),
与已优化的 write(优化176 直接 view)不对称。改为手写每个字段的 view 直读,
按 version(0/1/2+)决定读到哪,补默认值逻辑不变。
字段值完全一致(version/achVendID/sxHeight 验证),OS/2.read 微基准
思源 6.2→1.7μs(-73%)、令东 5.5→0.6μs(-89%),端到端约 -1%
(readBuffer 占比小),与 write 对称后可推广到其他 struct 通用 read 表。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-24 12:44:50 +08:00 |
|
崮生(子虚)
|
d575d55540
|
perf(name): 合并 UTF-8+UCS-2 编码 + ASCII 快路径
name 表 size 阶段对每条记录都要 UTF-8(mac)+ UCS-2(windows)各一份,
原两次独立编码各做一遍 stringify 扫描 + 编码循环。新增 toUTF8AndUCS2Bytes
合并为单次扫描:纯 ASCII(含拒绝 \0)走超快路径——UTF-8 直接取字节、
UCS-2 大端序 [0,ch],省掉多字节分支与两次扫描;非 ASCII 回退原逻辑。
字节 sha256 完全一致(思源/令东验证),思源 8 字 woff2 端到端 -7%
(name.size 占 dump 44%),令东千字文持平(name 占比 0.3% 在噪声内)。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-24 12:38:40 +08:00 |
|
崮生(子虚)
|
bcd4574b3f
|
perf(woff2): triplet 编码无分支 abs + 符号位提取
transformGlyfAndLoca 的 y+triplet 循环每点原先 4 次三元判断(absDx/absDy/xSign/ySign),
中文字体 dx/dy 正负近似 50/50 为不可预测分支,致流水线冲刷。
改用 Int32 算术右移统一提取符号:
- dxSgn = dx >> 31(0 或 -1)
- absDx = (dx ^ dxSgn) - dxSgn(无分支 abs)
- xSignBit = dxSgn + 1(等价 dx >= 0 ? 1 : 0)
令东 74.6% 点走 case3,收益最大:woff2 端到端 2.197→2.078ms(-5.4%),
思源 0.662→0.653ms(-1.4%)。sha256 字节级一致,全基准 SSIM 零变化。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-24 12:08:48 +08:00 |
|
崮生(子虚)
|
60db8d226b
|
perf(woff2): triplet 编码 case2/3/4 去掉冗余的轴非零判定
case1 排除 dx===0、case2 排除 dy===0 后,走到 case3/case4 时两轴必非零,
故 case3/case4 的 'dx!==0 && dy!==0' 是冗余判定。令东 74.6% 点命中 case3,
每点省 2 次比较。case2 的 'dx!==0' 同理冗余(case1 未命中且 dy===0 则 dx 必非0)。
cmp 字节一致,逻辑等价已证明。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-24 11:55:24 +08:00 |
|
崮生(子虚)
|
72c6afef92
|
perf(woff2): 移除 simple glyph 的 bbox 计算,由解码端从轮廓点重建
WOFF2 规范:bboxBitmap bit=0 时解码端计算点的 min/max 重建 bbox,bit=1 读显式存储值。
原编码对 simple glyph 计算 calcBbox 并与原始 bbox 比对决定 bit——但置 1 时存的也是
calcBbox,故无论 bit 值解码端都得 calcBbox,该计算与比对无功能意义。
移除后 simple glyph 永远 bit=0(解码端自算),省掉 x/y 循环每点 3 次 bbox 比较 + bboxSet
判定 + Pass2 写入。复合 glyph 仍显式存 bbox(raw 数据剥离了 glyph 头,解码端无法重建)。
令东千字文 woff2 write 2.449→2.237ms,输出体积 -20B~60B,全基准 SSIM 零变化。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-24 11:51:29 +08:00 |
|
崮生(子虚)
|
f945e1aedb
|
perf(woff2): triplet 编码各分支内累加 gsbi,消除 TRIPLET_DATA_SIZES 查表
令东千字文 woff2 write -12%(2.785→2.449ms),输出字节完全一致(cmp sha256 验证)。
原 gsbi += TRIPLET_DATA_SIZES[flag & 0x7F] 每点查表(Uint8Array 索引+位运算),
改为各 case 分支内 adv=1/1/1/2/3/4 常量累加,省掉查表。思源 -4%。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-24 11:48:12 +08:00 |
|
崮生(子虚)
|
aeb2622a57
|
perf(gsub-reachable): format3 失败路径跳过 contextGids 收集
format3 triggerable=false 是常态(初夏纯标点 280 个 format3 首轮全 false)。
失败时只需找首个不在 reachable 的 gid 记 failGid——此刻 contextGids 收集
无意义:break 前已检查的 gid 都在 reachable(inSubset=reachable.has),
调用方对其 reachable.add 是 no-op。改用 coverageFirstExcludedGid(复用
readCoverageGids 带 cache + 遍历短路)分离失败/成功两遍,失败路径省掉
contextGids.add 调用。仅 triggerable=true(coverage 全在子集、量小)时
第二遍收集 contextGids。
reachable 输出集合逐元素一致(初夏 23/FiraCode 89),全基准 SSIM 不变。
初夏 reach 0.265→0.245ms(-8%)。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-24 11:28:34 +08:00 |
|
崮生(子虚)
|
3103dd5db1
|
perf(gsub): ScriptList/FeatureList 整块拷贝快路径(同 GPOS)
subsetGSUB 复用 scriptListSpan/featureListSpan,span 自洽且不越过相邻 list
header offset 时整块 subarray 拷贝。交错判定用 SL span≤featureListOff、
FL span≤lookupListOff(LookupList subtable 散落,header offset 不能代表其
字节范围,故不用「下一更大 offset」作上界)。霞鹜文楷 GSUB 物理交错
(LL<SL<FL 且 ScriptTable 跨越 FL) 自动降级 serialize,字节与优化前完全一致。
收益:初夏 GSUB 11474→8474B(-26%)、FiraCode 15504→14878B(-4%),
保留 fontTools FeatureTable 去重。霞鹜降级路径 cmp 逐字节一致。全基准 SSIM 不变。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-24 11:23:06 +08:00 |
|
崮生(子虚)
|
ccc2e995c8
|
perf(gpos): ScriptList/FeatureList 整块拷贝跳过逐字段序列化
两表不含 glyphId(仅引用 lookup index),绝大多数字体其子表紧凑排列在
[listOff, listOff+span) 内、与下一表无物理交错,字节块本身即合法表。
新增 scriptListSpan/featureListSpan 计算跨度并校验自洽,满足则 subarray
整块拷贝,否则降级 serializeScriptList/serializeFeatureList。
收益:初夏 subsetGPOS 0.270→0.226ms,纯标点 0.240→0.165(-31%),
思源 0.071→0.036(-49%)。顺带保留 fontTools 的 FeatureTable 去重
(serialize 重排丢失致初夏 FeatureList 1840→3728B),输出 GPOS 字节
初夏 12064→10176(-16%)、思源 1194→978(-18%)。全基准 SSIM 不变。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-24 11:16:21 +08:00 |
|
崮生(子虚)
|
8c311768f6
|
perf(gsub-reachable): format3 失败 gid 跨轮跳过冗余扫描
不动点迭代中 format3 triggerable=false 的 subtable,记录使其失败的第一个
coverage gid。下一轮若该 gid 仍未进 reachable,本 subtable 必定仍 false,
直接跳过 collectChainRefs 重扫。
原 settledChain 只记忆稳定 subtable(format2 / format3 triggerable=true),
format3 triggerable=false 每轮都重扫。初夏纯标点 280 个 format3 全 false,
3 轮 × 280 = 840 次 collectChainRefs;改后 chainCalls 280→(第 2 轮起全跳过),
-67%。失败 gid 进 reachable 时重扫(可能仍 false 则更新失败 gid,可能变 true
则转 settledChain)。
reachable 集合字节级一致(初夏/得意黑/思源全 cmp 通过),SSIM 全程不变。
初夏 reach 0.33→0.29ms(-13%,collectChainRefs 非 reach 全部开销故收益有限)。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-24 11:05:52 +08:00 |
|
崮生(子虚)
|
65e238cdca
|
perf(cmap): subset 模式 format4 延迟解析,跳过 4×segCount 数组构建
subset 模式下 format4 不再急切构建 endCode/startCode/idDelta/idRangeOffset
共 4 个 segCount 项数组,只记录各段在 view 的偏移;lookupFormat4 二分时
按需从 view 读(mid*2 偏移)。原 subset 模式仍执行 4×segCount 次 getUint16
+ 4 个数组分配,得意黑 segCount=3929 → 1.5 万次读,占 readSubTable 0.101ms。
延迟后 view 读次数 = O(S × log(segCount)),远小于 4×segCount。
lookupFormat4 新增 _lazySegs 分支,非延迟路径(全量模式)保持急切数组不变。
idDelta 仍用 getUint16 读(与原急切模式一致),依赖 % 0x10000 处理符号。
字节逐字节一致(令东/思源/初夏/得意黑/otf 全 cmp 通过),SSIM 全程不变。
cmap: 初夏 0.075→0.009ms(-88%),得意黑→0.004ms(-94%),思源 0.063→0.014(-78%)。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-24 10:57:36 +08:00 |
|
崮生(子虚)
|
b7dbe3fe1d
|
perf(hmtx): subset 模式紧凑存储,消除 numGlyphs*2 大对象分配
subset 模式下 hmtx 改为按 subsetGids 顺序紧凑存储 Int32Array(S*2),
下标用 gi*2(subsetGids 内位置)替代 gid*2。原实现分配 Int32Array(numGlyphs*2),
CJK 字体 numGlyphs 达 3.5 万→284KB 大对象,V8 大对象分配+zero-fill 单次 ~54μs。
resolveGlyf subset 分支同步改用 gi*2 索引。OTF 路径不变(表顺序 hmtx 在 CFF 前,
subsetGids 未就绪,仍走全量数组)。
字节逐字节一致(令东/思源/初夏/得意黑/otf 全 cmp 通过),SSIM 全程不变。
初夏 hmtx 0.056→0.002ms(-96%),create -15%,fontSubset 总 -7%。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-24 10:52:30 +08:00 |
|
崮生(子虚)
|
aa2818b13e
|
perf(gsub): gidLookup 改 Int32Array,大数组 fill 快 3×
GidLookup(原gid→新gid 查找表)原用 number[].fill(-1), TypedArray 的 fill
是 native memset,比 number[].fill 快约 3×(35515 项:219μs→67μs)。
初夏明朝 subsetGids 仅十余个但 maxOrigGid 达 3.5 万(reachable 的高 gid target),
number[].fill(-1) 耗时 ~200μs,占 subsetGSUB 总耗时 ~47%。Int32Array.fill
降至 ~67μs,索引访问速度实测与 number[] 一致(FiraCode 密集查询场景同 8μs)。
初夏 rewrite 0.663→0.501ms(-24.5%),总 fontSubset -9.2%;FiraCode 略快 -2.8%。
GSUB 输出字节级一致(cmp 通过),30 项基准 SSIM 零变化。
推翻记忆 gsub-subset-perf-coverage-cache 中「number[] 比 Int32Array 快 2×」结论
(旧 V8 或不同测试条件),当代 V8 下两者访问速度相同,TypedArray fill 显著更快。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-24 10:38:27 +08:00 |
|
崮生(子虚)
|
6d897f1987
|
perf(gsub-reachable): collectChainRuleRefs 消除 3 个临时数组分配
ChainSubRule 解析原先读 backtrack/input/lookahead 到 3 个 number[] 再两遍遍历
(先 inSubset 校验再 contextGids.add),format1 每 rule 分配 3 数组
(FiraCode 424 次/call × 3 = 1272 次数组分配 + GC 压力)。
改为两遍扫描同一段字节,不分配中间数组:
- 第一遍仅 inSubset 校验全部 gid(遇子集外即 return,放弃规则)
- 通过校验后再第二遍收集 context gid + 读 subst records
reachable 输出字节级一致(FiraCode 132 / 初夏 63 均通过 cmp),
FiraCode reach 0.368→0.343ms(-6.8%),30 项基准 SSIM 零变化。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-24 10:30:05 +08:00 |
|
崮生(子虚)
|
dd4f7ba55a
|
perf(gsub-subset): format3 预检用 readCoverageRemapped 保证判定一致
opt317 的 format3 预检用 coverageAllOutOfSubset 内联判定,其 COV_RANGE
累积超限逻辑与 parseChainFormat3 实际用的 readCoverageRemapped 不一致,
导致 FiraCode 13 个 format3 预检未跳过却深度解析失败(0.328ms/call 浪费)。
预检改用 readCoverageRemapped(与深度解析同一判定函数 + 共享 covCache),
精确保证「预检跳过 ⟺ 深度解析失败」,输出完全一致(都是空 subtable)。
readCoverageRemapped 触碰 covCache 无副作用(gids 留 EMPTY_GIDS 占位,
readCoverageGids 命中按 miss 重算,已有逻辑)。
另:writeEmptySubtable 的 coverageOffset 恒为 6,改直接写常量,
省 reserveOffset16 的 patches push + 闭包分配。
FiraCode subsetGSUB 1.049→0.768ms(-27%),fontSubset 2.49→2.27ms(-9%)。
GSUB/woff2 字节 cmp 全绿,30 项基准 SSIM 零变化(FiraCode 0.9923、
千字文 0.9986、初夏纯标点 0.9920、otf 0.9681/0.9310 均不变)。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-24 10:14:38 +08:00 |
|
崮生(子虚)
|
1da81eb0c0
|
chore(gsub-subset): 清理 profiling 残留的 __sp 插桩
上一轮 opt317 提交时误带入了 format1/format3 序列化路径上的 __sp 计时
插桩(globalThis 属性读取 + performance.now 调用)。热路径每个 type6
subtable 都执行,属无关生产代码。删除并移除无用的 perf_hooks import。
GSUB 字节输出零变化(cmp 一致),性能持平。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-24 10:02:46 +08:00 |
|
崮生(子虚)
|
4c9022adb6
|
perf(gsub-subset): format3 预检判定修正跳过不可能触发的规则
subsetGSUB 真 hot path(FiraCode 2.2ms)是 type6 format3 失败路径占 69%
(16 次×0.094ms)。根因:isSubtableSkipableByCoverage format3 旧判定
「整组 coverage 全子集外」语义过强,当一组内部分 coverage 全子集外、
部分含子集内 gid 时预检不跳过,但 parseChainFormat3 遇到那个全子集外的
coverage 即返回 null 失败,白白深度解析。
format3 规则触发需三组 coverage 的 gid 全在子集内,故任一 coverage 原非空
且全子集外(coverageAllOutOfSubset===true,等价 readCoverageRemapped===null)
即不可能触发,预检直接跳过。
FiraCode fontSubset 3.751→2.029ms(-46%)。GSUB 字节 cmp 完全一致,
woff2 端到端字节 cmp 全绿,SSIM 0.9923 不变。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-24 09:55:49 +08:00 |
|
崮生(子虚)
|
56e8b6db4e
|
perf(gsub-reachable): format3 闭包消除 + 固定点迭代稳定性记忆
collectChainRefs 在固定点迭代中高频调用(初夏纯标点 280 个 format3 subtable ×
多轮),每次创建 readCovGidsChecked 闭包有分配开销。
优化315: format3 分支消除闭包,改显式三段循环手动推进 p,保留 triggerable 短路。
优化316: collectChainRefs 返回稳定标志(format2 总稳定 / format3 triggerable=true
稳定),主循环用 settledChain 记忆已稳定 subtable 偏移,后续轮直接跳过。
稳定测量(N=300 预热):
FiraCode 3.757 → 3.529ms (-6%)
初夏-纯标点 1.847 → 1.548ms (-16%)
初夏-汉字标点 1.503 → 1.260ms (-16%)
reach 阶段(单测): FiraCode 0.449→0.318ms, 初夏 0.544→0.315ms
无 GSUB 字体(令东/思源)无影响。所有用例 reach 输出与黄金基准逐字节一致。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-24 09:43:55 +08:00 |
|
崮生(子虚)
|
a1c7312722
|
perf(glyf): _origGlyfRef 子对象展平为 _origBuf/_origOff/_origLen
subset 快路径每个 simple 字形原本分配 glyfObj + _origGlyfRef 两个对象,
展平后 _origGlyfRef 的 {buffer,byteOffset,length} 直接存为 glyfObj 的三个属性,
省掉每字一个子对象分配 + 下游解引用间接寻址。
改 glyf.js(声明+component 守卫)、write.js、sizeof.js、optimizettf.js。
千字文 ttf 0.246→0.234ms(-5%),ttf/woff2 字节输出 cmp 完全一致,SSIM 全部不变。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-24 09:31:43 +08:00 |
|
崮生(子虚)
|
6b28ba3d74
|
perf(glyf): subset 快路径删 endPtsOfContours 数组分配,直接读最后 endPt
优化310 快路径下 endPtsOfContours 数组仅用于算 _totalPoints(供 maxPoints metrics),
下游 optimizettf 快路径分支、sizeof/write 原始字节拷贝均不消费它。
直接读最后一个 endPt(vOff+10+(numContours-1)*2)算 _totalPoints,
省掉每个 simple 字形的 Array 分配 + numContours 次 getUint16 循环。
千字文 ttf 0.252→0.246ms,ttf 字节输出 cmp 完全一致,SSIM 全部不变。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-24 09:27:19 +08:00 |
|
崮生(子虚)
|
308df8ef4d
|
perf(woff2): transformGlyfAndLoca 合并 y 解码与 triplet 编码为单循环
原 3 次遍历(x 解码→y 解码→triplet 编码)+ yCoords Int32Array 中转;
现 2 次遍历(x 解码→y 解码+triplet 编码合并)。
关键洞察:triplet delta 语义 = TTF delta(都是相对前一点的差),
所以解码 y 的同时用已存 xCoords[i] 配对编码 triplet,无需 yCoords 数组。
bbox_y 的 min/max 在合并循环同步计算,bbox bitmap 判定拆为 x/y 两段。
千字文 woff2 2.87ms→2.59ms(-9.6%),字节输出与 clean 版 cmp 完全一致,
SSIM 全部不变。删除 _reuseYCoords 模块级缓冲区。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-24 09:23:06 +08:00 |
|
崮生(子虚)
|
ece6eeca2f
|
perf(buffer): toBuffer ArrayBuffer→Buffer 用 Buffer.from 零拷贝替代逐字节循环
千字文 ttf 0.396ms→0.252ms(-36%),woff2 不受影响(不走 node Buffer 路径)。
Writer 的 ArrayBuffer 精确分配为 ttfSize(offset=0),getBuffer 返回完整 buffer,
Buffer.from 共享底层内存无 over-exposure 风险。SSIM 全部不变。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-24 09:15:17 +08:00 |
|
崮生(子虚)
|
69dc5e343e
|
perf(glyf): simple 字形原始字节快路径,千字文 ttf -80%/woff2 -35%
子集化 simple 字形经 parse→optimizettf→write 往返后产出的 glyf 字节
与原始字体完全一致(实测 73/73),直接拷贝原始字节跳过三段往返。
- glyf.js subset read: simple 字形存 _origGlyfRef 引用 + 读 header/endPts
供 metrics,跳过坐标解码;compound 及 component 走完整 parse
- optimizettf: 检测 _origGlyfRef 只收集 metrics 跳过 ceilReduce
- sizeof: glyfSize = 原始字节长度
- write: fullView.set 原始字节段跳过 encode
额外保留原始 hinting instructions(原非 hinting 模式丢弃),渲染更精确。
SSIM 全部不变(千字文 0.9986/FiraCode 连字 0.9923/初夏明朝 0.9920)。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-24 09:08:22 +08:00 |
|
崮生(子虚)
|
8f0964ce54
|
perf(parse): OS/2 表类按 format 缓存 + 清理 dead write,千字文 -5%
OS/2 read 原每次 struct.slice + _table.create 动态建类(_createClass +
Object.assign prototype),是 OS/2 parse 主开销(prof 稳态 ObjectAssign 4.2%)。
format 仅 0/1/2+ 三种,表类按 format 模块级缓存复用;去掉 Object.assign
(os2Fields, tbl),直接在 tbl 上补默认字段。
附带清理:ceilReduceAndSizeFromTypedArrays/Flat 的 _preXLen/_preYLen 是
全库零读取点的 dead write(subarray.length 已携带长度),删除;
optimizettf 后补 _yArr=null(悬挂内存,唯一消费者因 _xArr=null 守卫进不去)。
千字文 woff2 A/B:4.47→4.26ms(-5%),字节完全相同,SSIM 全部一致。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-24 08:51:44 +08:00 |
|
崮生(子虚)
|
78e8f798e8
|
perf(woff2): Brotli 质量 q3→q2,再省 8% 时间,体积仅 +0.09%
实测千字文 woff2 各 quality 端到端时间 + 体积(同文本):
q3=4.65ms/42712B q2=4.26ms/42752B q1=4.21ms/46432B q0=4.12ms/47240B
q2 是时间/体积最优拐点:比 q3 再省 8% 时间,体积仅 +40 字节(+0.09%)。
q1/q0 体积陡增 +8.7%/+10.6%(下载/解析代价),不划算。
基准测试全部 SSIM 与 ink 计数一致(FiraCode 0.9923、初夏明朝纯标点 0.9920)。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-24 08:42:36 +08:00 |
|
崮生(子虚)
|
4fb4679636
|
perf(woff2): Brotli 质量 q6→q3,千字文 -26%/FiraCode -13%,SSIM 不变
WOFF2 是无损容器,Brotli 质量只影响压缩率不影响解码结果。
实测 glyf 变换数据:q6=3.66ms/45935B(54.0%) → q3=1.20ms/46168B(54.3%),
时间 -67%,体积仅 +0.5%(持平)。q3 是时间/体积最优点,再降体积显著增大。
端到端 A/B(esbuild bundle):千字文 woff2 6.31→4.65ms(-26%),
FiraCode woff2 11.80→10.27ms(-13%)。基准测试全部 SSIM 与 ink 计数完全一致。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-24 08:37:55 +08:00 |
|
崮生(子虚)
|
8fd11fc859
|
perf(woff2): calcTripletAndWrite inline 到主循环,消除每点函数调用
千字文 woff2(54350 点)transformGlyfAndLoca 的 calcTripletAndWrite 占 31.8% CPU
(V8 --prof 实测)。手动 inline 到 triplet 循环消除 54350 次/call 调用开销,
让 V8 做循环内寄存器分配与公共子表达式消除。原独立函数删除(避免死代码)。
输出字节逐字节完全一致(千字文/思源黑体/FiraCode 三组 IDENTICAL 验证)。
微基准 encodeTTFToWOFF2 千字文 4.84→4.38ms(-9.5%)。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-24 07:27:09 +08:00 |
|
崮生(子虚)
|
d68551d23e
|
feat(stats): 统计计数跨重启持久化 + 依赖升级
- 新增 stats_store.ts:防抖写盘 font/.stats.json,热路径零磁盘 IO
- shared.ts 暴露 initStats/markStatsDirty/snapshotStats
- app.ts 启动恢复累计计数 + 退出前尽力落盘
- 路由热路径打脏标记(防抖 30s 批量落盘)
- 清理未用变量/导入/常量
- 升级依赖:vue 3.6.0-beta.17、typescript 7.0.2、vite 8.1.5 等
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-23 21:43:12 +08:00 |
|
崮生(子虚)
|
f7a2a4dc86
|
perf(gsub-reachable): collectChainRefs format3 短路 + 去闭包/中间数组
固定点迭代中 collectChainRefs 高频调用(初夏纯标点 840 次/call)。format3 原实现:
读完全部 backtrack/input/lookahead coverage 把 gid 收进 allGids 中间数组,任一不在
子集才置 triggerable=false,且每次调用分配 readCovGids 闭包 + allGids 数组。
优化:遇到不在子集的 gid 立即短路返回(triggerable=false 时 contextGids/refs 本就不
收集,后续 coverage 无需再读);去掉闭包与 allGids,triggerable 时 gid 直接 add 进
contextGids。逻辑完全等价(triggerable=false 时原代码也不 add contextGids)。
基准 29 用例 SSIM/ink/字节全无回归。初夏纯标点 2.34→1.86ms(-20%),FiraCode 3.7→3.4ms。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-23 20:45:08 +08:00 |
|
崮生(子虚)
|
7d62bce1df
|
perf(gsub): readCoverageRemapped format2 range clamp 到 numGlyphs
承接 fda7ab8(format1 损坏 coverage 跳过)。插桩定位剩余 miss 热点:format2
(range) 仅 11 次 miss,但 439 个 range 的 end >= numGlyphs(1652),逐 gid 展开
浪费 ~320 万次 gidLookup 索引(全部 g>=numGlyphs 越界跳过),是 readCoverageRemapped
剩余 55% self time 的绝大头。
将每个 range 的 end clamp 到 numGlyphs-1:start..numGlyphs-1 段与原代码逐 gid 处理
完全相同,numGlyphs..end 段原代码全越界跳过、clamp 后省去空循环。整个 range 越界
(start>=numGlyphs) 时保留 origNonEmpty=true 语义(→ outOfSubset → null),与原代码
逐 gid 遍历全空结果完全等价。
基准 29 用例 SSIM/ink/字节全无回归,FiraCode fontSubset 6.8ms→3.75ms(累计较
优化前 12.2ms -69%)。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-23 20:39:12 +08:00 |
|
崮生(子虚)
|
fda7ab8902
|
perf(gsub): readCoverageRemapped 跳过损坏 coverage 的空循环
FiraCode subsetGSUB 的 readCoverageRemapped 占 70.5% self time。插桩定位:
77 次 format1 miss 中有 8 次 count 高达 15460(远超字体 glyph 总数 1652),
这些是 ChainContextSubst format3 指向错误偏移读到的垃圾 count,原代码循环
count 次全部 gidLookup[g] 越界返回 undefined 被跳过,浪费 107852 次迭代
(占 format1 miss 总工作量的 95%)。
count > numGlyphs 时跳过必然全空的循环,仅保留 origNonEmpty=count>0 语义
→ newGids 空 → outOfSubset=true → 返回 null,与原代码循环全空结果完全等价。
基准 29 用例 SSIM/ink/字节全无回归,FiraCode fontSubset 12.2ms→6.8ms(-45%)。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-23 20:34:10 +08:00 |
|
崮生(子虚)
|
d3d96d1735
|
perf(loca): subset 模式 Proxy 按需读,跳过全量 30907 项解析
subset 模式下 glyf.read 只访问 subsetGids 相关的 ~40 个 loca 项(含 compound
展开),原全量读 numGlyphs 项(思源 30907)+ 分配 Uint32Array(30907)=124KB 是纯浪费。
loca 表读取顺序在 glyf 之前,subsetGids 尚未构建,无法像 hmtx 那样按已知 gid 列表读。
改用 Proxy 拦截 glyf.read 的 loca[index] 访问,首次访问某 gid 时按需从 view 读并缓存。
实测 loca.read 从 profile 12.2% 降至 0%(思源标点),千字文 fontSubset -6.5%。
非 subset 路径保持原 TypedArray(全量访问下 Proxy trap 反慢)。基准 SSIM/ink/字节全无回归。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-23 20:09:18 +08:00 |
|
崮生(子虚)
|
055425e852
|
perf(gsub): readCoverageRemapped format1 用 Uint16Array 批量读
coverage format1 的 gid 列表是连续 count 个大端 u16,原 DataView.getUint16
逐次调用有边界检查 + 大端组装开销。gid 数组 2 字节对齐时改用 Uint16Array
view 共享 buffer 读取 + 内联翻转 ((raw&0xff)<<8)|(raw>>8)(与 hmtx/loca 同思路),
未对齐回退 DataView。
readCoverageRemapped 是 FiraCode subsetGSUB 第一大热点(75.5%),miss 路径
sum 遍历 ~26000 gid。实测 FiraCode fontSubset 中位数 13.65→12.43ms(-8.9%),
5 轮稳定。基准 SSIM/ink/字节全无回归。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-23 20:03:40 +08:00 |
|
崮生(子虚)
|
b4f8d7a522
|
perf(hmtx): subset 模式按需读 subsetGids 项,跳过全量 30888 项解析
subset 模式下 glyf.read(表顺序在 hmtx 之前)已构建 subsetGids,
resolveGlyf 也只访问 subsetGids 对应位置。原实现全量解析 numOfLongHorMetrics
项(思源 30888)对小子集是纯浪费。改为只读 subsetGids 需要的项,
其余位置保持 0(不被访问)。
实测 hmtx.read 0.21→0.032ms(6.5×),基准 SSIM/ink/字节全无回归。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-23 19:46:42 +08:00 |
|
崮生(子虚)
|
6ea19550a1
|
perf(gsub-reachable): collectReachableGsubTargets 单 Set inSubset + 复用临时 Set
初夏明朝纯标点(最慢 CJK 用例 4ms)profile 显示 collectReachableGsubTargets 占 19.2% +
collectChainRefs 7.8%(合计 27%,超过 subsetGSUB 本身 6.4% 的 3 倍)。单次 1.22ms。
优化:
1. inSubset 闭包原为 seedGids.has(g) || reachable.has(g) 两次 Set 查询(热路径每 subtable
多次调用)。改为 reachable 初始即含 seedGids,inSubset 只查 reachable 一个 Set。
返回的 reachable 可能含 seed gid——调用方注入 extraSubsetGids 后 Font.create 去重,无害。
2. 每个 type6 subtable 原 new Set() × 2(refs + ctxGids),多轮迭代 × 51 lookup 累积 GC 压力。
改为循环外复用 + clear。
实测初夏明朝 1.22→1.02ms(-16%),FiraCode 0.75→0.69ms(-8%)。
基准测试 29 用例 SSIM/ink/输出字节全部无回归(初夏纯标点 4.4→3.6ms)。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-23 19:15:50 +08:00 |
|
崮生(子虚)
|
bbc3d8b88a
|
perf(hmtx): LongHorMetric 段改 Uint16Array view 批量读+内联翻转
hmtx.read 原用 DataView.getUint16/getInt16 逐次调用读 LongHorMetric 段(每项 u16 advW + i16 lsb),
思源黑体 numOfLongHorMetrics=30888,占 fontSubset 约 8.7%(profile 仅次于 brotli/subsetGSUB)。
改用 Uint16Array view 共享 buffer 按下标读取后内联大端翻转(与 loca 优化同思路),实测快 2×
(198→98μs/call)。offset 需 2 字节对齐,未对齐回退 DataView。Last 段(lsb only)同样优化,
起始必然 2 字节对齐(前段是 4 字节倍数)。
基准测试 29 用例 SSIM/ink/输出字节全部无回归。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-23 19:10:18 +08:00 |
|
崮生(子虚)
|
44f84e5659
|
perf(gsub-subset): serializeSingle/Multiple/Alternate/Ligature 改用 gidLookup 数组查找
serializeSingleSubst/MultipleSubst/AlternateSubst/LigatureSubst 原用 remapGid(origToNew Map)
对每个 coverage gid + 分量 gid 做哈希查询。subsetGSUB 入口已构建 gidLookup 数组
(下标=原gid,值=新gid/-1,比 Map.get 快 ~2×),但这四个函数未使用,仍传 origToNew Map。
serializeLigatureSubst 是 CJK ligature 子集化热点(50gid 子集占 subsetGSUB 65%,
每条 ligature 对全部分量密集 remapGid)。改为收 gidLookup 参数,remapGid(Map.get)
→ gidLookup[gid](数组索引,-1 即子集外)。
四个函数签名 origToNew: Map → gidLookup: GidLookup,serializeSubtable 调度相应更新。
ChainContext format1 的两处 remapGid(serializeChain/parseChainRuleFormat1or2)暂未改
(FiraCode 路径 serialize 占比小,readCoverageRemapped 是主瓶颈)。
验证:基准测试 29 用例 SSIM 全部无回归;4 用例 sha256 输出字节逐字节等价。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-23 18:45:39 +08:00 |
|
崮生(子虚)
|
51f969d3f0
|
perf(ot-bytes): OTWriter 改 Uint8Array 缓冲 + writeBytes 批量复制
OTWriter 原用 number[] + push 累积字节,每个 writeUint8/16 触发数字装箱与数组扩容;
gsub/gpos-subset 逐字节 writeUint8 循环复制 ScriptList/FeatureList/PairSet 字节块极慢。
重构 OTWriter 底层为 Uint8Array 容量缓冲 + size 指针:
- writeUint8/16 索引写入(无装箱),ensure 按 2× 扩容
- 新增 writeBytes(Uint8Array) 用 TypedArray.set 批量复制
- toUint8Array 返回 subarray 的拷贝(避免后续写入污染,subarray 语义曾有隐患)
gsub-subset/gpos-subset 的 5 处逐字节 writeUint8 复制改 writeBytes。
关键 Bug 修复:原 writeInt16 依赖 number[] 索引赋值到 length 位置【隐式扩展数组】,
Uint8Array 版需显式 ensure + 推进 size(否则 writeInt16 不增长 size,后续 write 覆盖,
GPOS 的 SinglePos 坐标值丢失——GPOS 输出从 1942B 错误缩到 1448B)。writeInt16At 仅覆盖
不扩展(pos 已在 reserveOffset16 的 ensure 保证范围内)。
验证:基准测试 29 用例 SSIM 全部无回归;GSUB/GPOS 独立输出 + fontSubset 完整输出
(思源千字文/标点/FiraCode/ttf)sha256 与重构前逐字节等价。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-23 18:39:04 +08:00 |
|
崮生(子虚)
|
d793e22d92
|
perf(loca): TypedArray 批量读+内联翻转替代 DataView 循环,loca 解析快 39%~46%
loca 偏移是大端,原 DataView.getUint16/32 逐次调用含边界检查开销。改用
Uint16/32Array 直接 view 共享 buffer + 内联字节翻转,微基准实测:
- format0(Uint16):157→84μs(-46%)
- format1(Uint32):152→93μs(-39%)
(思源 30907 条 loca)
返回 Uint32Array 替代普通 Array,glyf.js 仅按下标 loca[index] 只读访问,
与 TypedArray 兼容(已确认 loca 仅被 glyf.js:22 读取、ttfreader.js:216 置 null)。
对齐保护:Uint16Array 需 2 字节对齐、Uint32Array 需 4 字节对齐,loca offset
来自表目录不保证对齐。检测 srcByteOff 对齐情况,未对齐回退 DataView 路径。
验证:基准测试 29 用例 SSIM 全部无回归;4 用例(思源千字文/标点/FiraCode/ttf)
sha256 输出字节逐字节等价。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-23 18:25:39 +08:00 |
|
崮生(子虚)
|
6f96e2b1dd
|
perf(post): subset 模式跳过 glyph name 解析降级 format 3,CJK 子集化提速 45%~50%
subset 模式下 post glyph name 对 web 字体渲染无用(浏览器靠 cmap→gid→glyf 渲染,
glyph name 仅用于 PDF 嵌入/编辑器)。原实现 subset 模式保存 pascalString 区
readBytes(思源 278KB)+ view 引用,resolveGlyf 再按需读 nameIndex + 算 name,
实测 post 段占 Font.create 的 69%(思源 56 glyph 子集 1.19ms)。
优化:subset 模式直接降级 post.format=3,跳过 nameIndex 解析、pascalString
readBytes、resolveGlyf 按需 name 读取。resolveGlyf 的 `2 === format` 条件不成立
整段跳过;write/size 走 format 3(32 字节,无 nameIndex/names)。
收益(CJK Font.create 是 fontSubset 主体):
- 思源千字文中段 3.057→1.673ms(-45%)
- 思源标点 2.705→1.361ms(-50%)
- FiraCode 22.2→21.0ms(-5.5%,瓶颈在 GSUB 不在此)
体积:FiraCode 8724→8704B(post 无 name 更紧凑)
验证:基准测试 29 用例 SSIM 全部无回归(千字文 0.9986、思源标点 0.9977、
初夏纯标点 0.9920、FiraCode 0.9923、otf-思源 0.9310 均不变)。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-23 18:16:56 +08:00 |
|
崮生(子虚)
|
2c56d2cbb2
|
perf(font): 轻量 GSUB probe 跳过 glyf 解析,CJK 子集化提速 17%~56%
fontSubset 原先对 probe 阶段也调用完整 Font.create(subset 模式),
它会解析子集 glyph 的 glyf 轮廓(parseSimpleGlyf)。但 probe 只需要
GSUB(原始字节透传)和 cmap(codepoint→gid),根本不需要轮廓。
实测 CJK 字体(思源黑体/令东齐伋)两次 Font.create 占总耗时 36%~63%。
新增 gsub-probe.ts:直接从字体字节解析表目录,提取 GSUB 字节切片 +
cmap 的 codepoint→gid 查找(format4 BMP + format12 补充平面二分,
与 fonteditor-core readWindowsAllCodes 优先级一致),完全跳过 glyf。
三种路径(与原 Font.create probe 行为严格等价):
- otf / ttf 无 GSUB:直接判无 reachable(otf 的 fonteditor probe 本就
origGSUB=undefined),连 probe Font.create 也跳过
- ttf 有 GSUB 且 cmap 含 fmt4/12:轻量 probe 算 reachable
- ttf 有 GSUB 但 cmap 无 fmt4/12(极罕见):回退 Font.create probe
验证:
- seedGids / GSUB字节 / reachable 与原 probe 逐项等价(FiraCode 87 target 等)
- 5 个代表字体 woff2 输出与优化前逐字节一致(cmp 通过)
- pnpx tsx 基准测试.test.ts 全部 SSIM 无回归:
思源黑体-千字文中段 7.8→4.5ms(-42%)、千字文前段 11.9→8.9ms(-25%)、
otf-思源 2.9→1.9ms(-34%)、霞鹜文楷-汉字标点 5.0→2.2ms(-56%)、
FiraCode 18.5→17.2ms,SSIM 全部不变
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-23 17:41:16 +08:00 |
|