mirror of
https://github.com/2234839/web-font.git
synced 2026-09-12 11:45:44 +08:00
perf(gsub): emitCoverage 跳过 slice+sort,readCoverageRemapped 缓存前统一排序
原 emitCoverage 对输入 newGids 做 slice().sort()——防御性复制+排序。 但 readCoverageRemapped 的输出(fmt3/writeChainFormat2 coverage)因 原gid→新gid 映射不保序而可能乱序,必须排序;type1/2/3/4 的 entries.map(e=>from) 虽已按 from 排序故升序,却仍付出 slice+sort 开销。 将排序职责上移到 readCoverageRemapped 缓存入口(covCache 命中率极高,FiraCode 604 引用/83 独立 coverage,排序分摊几乎免费),使所有调用方输出天然升序无重复。 emitCoverage 据此改为直接扫描区间(不 slice、不 sort、不分配 ranges 对象数组), 同时两遍扫描统一为 rangeCount 计数。 FiraCode subsetGSUB 417→390μs(-6.5%),输出 sha 全字体一致,SSIM 全不变。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
f053112e44
commit
799d284d4b
@ -289,6 +289,13 @@ function readCoverageRemapped(
|
||||
}
|
||||
/** 原 coverage 非空但全部 gid 落子集外 → 失效(与原 coverage 本就空的合法空数组区分) */
|
||||
if (newGids.length === 0 && origNonEmpty) outOfSubset = true;
|
||||
/** 缓存前升序排序:原 coverage gid 升序,但 原gid→新gid 映射不保序(subsetGids 重编号),
|
||||
* 过滤后的新 gid 可能乱序。readCoverageRemapped 的输出只作为「gid 集合」传给 emitCoverage,
|
||||
* 调用方均不依赖顺序(fmt3 coverage / writeChainFormat2 coverage),故在缓存入口统一排序,
|
||||
* 使缓存数组天然升序无重复——emitCoverageSorted 据此跳过 slice+sort(fmt3 高频热路径)。
|
||||
* 排序发生在每个 coverage off 首次计算(covCache 命中率极高,FiraCode 604 引用/83 独立 coverage),
|
||||
* 分摊到所有引用几乎免费。 */
|
||||
if (!outOfSubset && newGids.length > 1) newGids.sort((a, b) => a - b);
|
||||
/** 只写 remapped 字段,不碰 gids 字段。
|
||||
* covCache 被 readCoverageRemapped(fmt3 用,产 newGids)与 readCoverageGids
|
||||
* (fmt1 ChainContext 用,需原始 gid 按 index 与 ruleSet 配对)共享。
|
||||
@ -303,38 +310,46 @@ function readCoverageRemapped(
|
||||
* 从一组(子集内的)新 gid 序列写出 Coverage 表,返回其在 Writer 中的起始偏移。
|
||||
* 自动选择 format1(列表)或 format2(区间)中更紧凑的。
|
||||
*/
|
||||
/**
|
||||
* 从一组(子集内的)新 gid 序列写出 Coverage 表,返回其在 Writer 中的起始偏移。
|
||||
* 自动选择 format1(列表)或 format2(区间)中更紧凑的。
|
||||
*
|
||||
* 输入约定:newGids **必须已升序、无重复**。所有调用方均保证:
|
||||
* - readCoverageRemapped 在缓存入口已 sort(原 coverage gid 升序,但 原gid→新gid 映射不保序)
|
||||
* - type1/2/3/4 与 fmt1 的 entries 在调用前已按 from/firstGid 升序排序,map 保持顺序
|
||||
* 直接在输入上扫描区间(不 slice 复制、不 sort、不分配 ranges 对象数组),
|
||||
* fmt3 单次子集化 ~17 万次 emitCoverage 调用的主要 GC+CPU 开销由此消除。
|
||||
* 仅读不修改输入,covCache 共享的数组实例安全复用。 */
|
||||
function emitCoverage(w: Writer, newGids: number[]): number {
|
||||
/** 升序(Coverage 要求升序)。
|
||||
* 无需去重:所有调用方传入的 newGids 逻辑上保证无重复——
|
||||
* readCoverageRemapped 按原 coverage(规范要求 gid 唯一)升序过滤,每个原 gid 映射唯一新 gid;
|
||||
* entries.map(e=>e.from) 的 from 是 entry 主键(唯一)。
|
||||
* 实测 FiraCode 单次子集化 327 次 emitCoverage 调用 0 次发现重复,去重(new Set)纯为 GC 开销。
|
||||
* slice 复制后原地排序,避免修改调用方的数组。 */
|
||||
const sorted = newGids.slice().sort((a, b) => a - b);
|
||||
const off = w.length;
|
||||
let ranges: Array<{ start: number; end: number }> = [];
|
||||
for (let i = 0; i < sorted.length; ) {
|
||||
const n = newGids.length;
|
||||
/** 第一遍:统计连续区间数(决定 format2 是否更紧凑) */
|
||||
let rangeCount = 0;
|
||||
for (let i = 0; i < n; ) {
|
||||
let j = i;
|
||||
while (j + 1 < sorted.length && sorted[j + 1] === sorted[j] + 1) j++;
|
||||
ranges.push({ start: sorted[i], end: sorted[j] });
|
||||
while (j + 1 < n && newGids[j + 1] === newGids[j] + 1) j++;
|
||||
rangeCount++;
|
||||
i = j + 1;
|
||||
}
|
||||
if (ranges.length > 0 && ranges.length < sorted.length) {
|
||||
if (rangeCount > 0 && rangeCount < n) {
|
||||
/** format2 区间更紧凑 */
|
||||
w.writeUint16(COV_RANGE);
|
||||
w.writeUint16(ranges.length);
|
||||
w.writeUint16(rangeCount);
|
||||
let covIndex = 0;
|
||||
for (const rg of ranges) {
|
||||
w.writeUint16(rg.start);
|
||||
w.writeUint16(rg.end);
|
||||
for (let i = 0; i < n; ) {
|
||||
let j = i;
|
||||
while (j + 1 < n && newGids[j + 1] === newGids[j] + 1) j++;
|
||||
w.writeUint16(newGids[i]);
|
||||
w.writeUint16(newGids[j]);
|
||||
w.writeUint16(covIndex);
|
||||
covIndex += rg.end - rg.start + 1;
|
||||
covIndex += newGids[j] - newGids[i] + 1;
|
||||
i = j + 1;
|
||||
}
|
||||
} else {
|
||||
/** format1 列表 */
|
||||
w.writeUint16(COV_LIST);
|
||||
w.writeUint16(sorted.length);
|
||||
for (const g of sorted) w.writeUint16(g);
|
||||
w.writeUint16(n);
|
||||
for (let i = 0; i < n; i++) w.writeUint16(newGids[i]);
|
||||
}
|
||||
return off;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user