perf(font): lazy-load CJK fallback fonts to cut ~106MB idle RSS#20
Merged
Conversation
Resolving the ~18 curated CJK fallback names at startup faulted whole .ttc files into the page cache (Hiragino Sans GB 44.8MB, Hiragino Kaku Gothic W3 30.0MB, AppleGothic 29.2MB, ...), keeping ~104MB of clean file-backed font pages resident even when no CJK glyph is ever drawn. Measured idle RSS: 239MB -> 133MB; phys_footprint unchanged (the pages never counted there), closing the ~100MB RSS gap vs Ghostty. Drop the eager CJK loop from load_font_stack_with_primary and resolve a CJK codepoint on first stack miss instead: cjk_fallback_face_for walks the same PostScript-name-then-family priority list the eager stack used (so glyph selection is unchanged), gated by cmap coverage, ahead of the generic CoreText cascade. Resolution uses the existing no-slurp CoreText->mmap path, so even after CJK is drawn only touched pages become resident (Hiragino W3: 0.5MB vs a constant 30MB before). Verified end-to-end in the bundled app: Japanese kanji/kana render identically via the lazy path, with vmmap confirming no CJK font is mapped at idle.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
noa's idle RSS ran ~100MB above Ghostty while phys_footprint was nearly equal. Attribution via
footprint/vmmapshowed the gap was almost entirely clean file-backed font pages: resolving the ~18 curated CJK fallback names at startup faulted whole.ttcfiles into the page cache (Hiragino Sans GB 44.8MB + Hiragino Kaku Gothic W3 30.0MB + AppleGothic 29.2MB ≈ 104MB) — resident even when no CJK glyph is ever drawn. Ghostty lazy-loads the same fonts via CoreText and keeps ~0.4MB resident.This PR drops the eager CJK loop from
load_font_stack_with_primaryand resolves CJK on first stack miss instead.cjk_fallback_face_forwalks the exact priority order the eager list used (PostScript names, then families), gated by cmap coverage, ahead of the generic CoreText cascade — so which font wins for a given codepoint is unchanged. Resolution goes through the existing no-slurp CoreText→mmap path, so even after CJK is drawn only touched glyph pages become resident.Test plan
cargo test --workspacegreen (noa-font 65, noa-app 949, ...),cargo clippy --workspaceclean,cargo fmt --checkclean.vmmapconfirmed no CJK font mapped at idle and only partial residency after drawing.