Skip to content

render: stop re-indexing host fonts per fallback measurement - #1504

Merged
developer0hye merged 1 commit into
developer0hye:mainfrom
aktanazat:fix/default-font-search-paths
Sep 2, 2026
Merged

render: stop re-indexing host fonts per fallback measurement#1504
developer0hye merged 1 commit into
developer0hye:mainfrom
aktanazat:fix/default-font-search-paths

Conversation

@aktanazat

@aktanazat aktanazat commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Summary

glyph_advances_em_with_typst_fallback, best_face, and the two cached advance lookups obtained the default font search paths by calling resolve_font_search_context(&[]), which indexes every face on the host. Outside an active font context that ran once per measured run. On a 35-page DOCX with many overlong tokens, sample attributed 111 s of a 112 s conversion to index_families_from_paths under glyph_advances_em_with_typst_fallback; v0.6.7 converts the same file in 1.7 s.

default_font_search_paths now memoizes the paths (at most six directory probes, once per process) in a LazyLock, every site uses it, and resolve_font_search_context reads the same slice. The --metrics codegen stage on that file drops from 111 s to 0.3 s; the full lib test suite drops from 234 s to 28 s on this machine because the tests hit the same path.

Related issue

None filed. The per-run resolution arrived with #1456 (Related: #1454), which added the overlong-token measurement; v0.6.7 predates it. Numbers measured on an Apple M4 Pro, macOS 26.6, with Microsoft Office fonts present.

Testing

  • cargo test -p office2pdf --lib (2777 passed)
  • cargo fmt --all --check, cargo clippy -p office2pdf --all-targets (only the pre-existing effective_last_resort_family dead-code warning)
  • New tests: test_default_font_search_paths_match_the_resolved_context pins the memoized paths to resolve_font_search_context(&[]).search_paths(); test_fallback_glyph_advances_do_not_resolve_a_font_context uses a test-only counter (same pattern as AUTO_ROW_FRAME_ESTIMATE_CALLS) and fails on main with 1 resolution per call.

Visual impact

  • No rendered PDF change
  • Rendered PDF change or visual evidence added
  • Reason: the memoized paths equal the previously resolved search paths (pinned by test), so every measurement and compile sees the same font set.

Checklist

  • Commits include a Signed-off-by line
  • PR scope contains one root cause
  • Remaining visual deviations each reference an open issue (none observed)

glyph_advances_em_with_typst_fallback, best_face, and the two cached
advance lookups obtained the default font search paths by resolving a
full FontSearchContext, which indexes every face on the host. Outside
an active context that ran once per measured run: a 35-page report
with many overlong tokens spent 111 s of a 112 s conversion inside
index_families_from_paths (sampled on macOS, Apple M4 Pro), where
v0.6.7 converts the same file in 1.7 s.

Memoize the default paths, at most six directory probes, in
default_font_search_paths and use it at every site, including
resolve_font_search_context itself and the test probe's private
OnceLock. A test pins the memoized paths to the resolved context's
search paths, and a test-only counter asserts that the fallback lookup
resolves no context.

Assisted-by: LLM (Claude)
Signed-off-by: Aktan Azat <aktanaazat@gmail.com>
@aktanazat
aktanazat force-pushed the fix/default-font-search-paths branch from e1a12fb to d88af64 Compare September 1, 2026 23:28
@developer0hye
developer0hye merged commit 7eaf684 into developer0hye:main Sep 2, 2026
18 checks passed
@developer0hye

Copy link
Copy Markdown
Owner

Thank you for tracking this down, and for the sample attribution that made it unambiguous. Merged as 7eaf684.

What I verified before merging:

  • On main, the fallback at render/pdf.rs resolved a full font context on every call whenever no context was active, and the pipeline only installs a context when the document requests font families explicitly or the caller passes font paths or bytes (lib_pipeline.rs). A DOCX without explicit font requests therefore paid a full host font index per overlong token. The font data itself was already cached, so the family index was the only uncached cost, which matches your profile.
  • The per-run resolution arrived with fix(docx): wrap overlong Latin table tokens #1456 on 2026-08-31, so v0.6.7 predates it; I added that cross-reference to the description.
  • All five call sites you rerouted are behind not(target_arch = "wasm32"), matching the new function's cfg, and the WASM check passed.
  • Reproduced the effect here on a 16 GB M-series machine: the lib suite on merged main finishes in 58.7 s (2784 passed), while the same suite on the render: keep literal text from continuing an embedded expression #1503 branch, which lacks this fix, had not finished after 16 minutes. That second number is approximate because another test run was sharing the machine, but the direction is not in doubt.

The pinned-equality test and the resolution counter are exactly the right two assertions for this change. Much appreciated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants