web-font/_p_perTable2.ts
崮生(子虚) 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

38 lines
1.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import fs from 'node:fs';
import * as TTFReaderNS from './vendor/fonteditor-core/lib/ttf/ttfreader.js';
const TTFReader: any = TTFReaderNS.default.default ?? TTFReaderNS.default;
const supportNS: any = await import('./vendor/fonteditor-core/lib/ttf/table/support.js');
const support: any = supportNS.default.default ?? supportNS.default;
const buf = fs.readFileSync('/mnt/d/字体资源/初夏明朝/初夏明朝-Regular.ttf');
const ab = buf.buffer.slice(buf.byteOffset, buf.byteOffset+buf.byteLength) as ArrayBuffer;
const cps = Array.from(',。!?、;:“”‘’').map(c => c.codePointAt(0)!);
// monkey-patch 每个表类的 read累加耗时
const stats: Record<string, number[]> = {};
for (const tn of Object.keys(support)) {
const TableClass: any = support[tn];
if (!TableClass || !TableClass.prototype || !TableClass.prototype.read) continue;
const orig = TableClass.prototype.read;
TableClass.prototype.read = function(reader: any, ttf: any) {
const t0 = performance.now();
const r = orig.call(this, reader, ttf);
const dt = performance.now() - t0;
(stats[tn] ??= []).push(dt);
return r;
};
}
function median(a: number[]) { return a.slice().sort((x,y)=>x-y)[Math.floor(a.length/2)]; }
// 多次跑 readBuffer 累加统计
for (let i = 0; i < 25; i++) {
const r = new (TTFReader as any)({ subset: cps, kerning: true });
r.readBuffer(ab);
}
console.log('=== 初夏标点 各表 read 耗时25次中位数===');
const rows = Object.entries(stats).map(([n, a]) => ({ n, med: median(a), min: Math.min(...a) }));
rows.sort((a,b)=>b.med-a.med);
for (const r of rows) console.log(` ${r.n}: ${r.med.toFixed(3)}ms (min ${r.min.toFixed(3)}, ${stats[r.n].length}次)`);