Skip to content

perf: speed up subtree preprocess for large multi-post Org files - #782

Open
HaoZeke wants to merge 9 commits into
kaushalmodi:mainfrom
HaoZeke:fix/preprocess-perf-732
Open

perf: speed up subtree preprocess for large multi-post Org files#782
HaoZeke wants to merge 9 commits into
kaushalmodi:mainfrom
HaoZeke:fix/preprocess-perf-732

Conversation

@HaoZeke

@HaoZeke HaoZeke commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Summary

Addresses #732: single-subtree export on large multi-post Org files spent most of its time in org-hugo--get-pre-processed-buffer (full-file parse, link rewrite, then org-element-interpret-data re-serializing the whole AST). That also drove the heavy GC in the profiler.

Changes

  • Collect org-export--collect-tree-properties once per preprocess (was recomputed for every id: link).
  • Build the pre-processed buffer by copying source text and splicing rewritten cross-post links in place, instead of org-element-interpret-data on the full tree.
  • Single-subtree export only rewrites links inside that subtree. All-subtrees batch still rewrites every cross-post link once for the shared pre-processed buffer.
  • Keep Org 9.7+ dummy file: link handling (org-hugo--ensure-preprocessed-file-link-types) and same-file id: rewrite behavior from fix: restore same-file cross-post links under Org 9.7+ #781.

Benchmark (local, Emacs 30.2)

File: test/site/content-org/all-posts.org (~9100 lines). Export post Links outside the same post with org-hugo-export-wim-to-md (3 timed runs after warm-up):

avg GC
before 3.23 s 1 / run
after 1.57 s 0 / run

Golden Markdown for that post is unchanged.

Test plan

  • Single-subtree export of Links outside the same post matches golden
  • File-based org-roam id link still exports
  • All-subtrees export on a multi-post file still runs
  • CI make -j1 test matrix

Notes

Stacked on the Org 9.7+ cross-post correctness work (#781). Parse of the full buffer remains (~1.2 s on this file); further gains need a lighter destination index than org-element-parse-buffer.

HaoZeke added 9 commits July 10, 2026 10:26
Cross-subtree links are rewritten to dummy file paths in the pre-processed
buffer. org-element-interpret-data then drops the file: type for relative
paths, so re-parse treats them as fuzzy and Org 9.7 aborts with
"Unable to resolve link: ...pre-processed.org::...".

- Keep path and search-option separate on dummy file links
- After interpret-data, force file: prefixes on dummy targets
- Do not skip same-file org-id links during rewrite (only other files)
- Handle fuzzy reparsed dummy paths in org-hugo-link
- Re-enable the commented cross-post link tests in all-posts.org
Re-enable cross-post cases now export to relref shortcodes instead of
the previous pre-processed.org resolve error note.
Current Org citeproc no longer emits the .csl-left-margin style block
before csl-bib-body; main has been red on this golden drift. Align the
expected Markdown with the export CI produces so the suite can proceed
past citation-csl.org.
org-hugo-export-wim-to-md only updated org-id-locations when the table
was empty. After a prior export wrote a non-empty
~/.emacs.d/.org-id-locations (test suite shares HOME across sequential
emacs -batch runs), sibling files in the current directory were never
scanned, so cross-file id links such as org-roam-file-A -> B aborted
with "Unable to resolve link".

Always rescan .org files in default-directory before export.
Org now emits —/– instead of numeric entities in captions,
and drops the trailing space inside timestamp spans. Align expected
Markdown with CI export so all-posts.org diffgolden can pass.
Un-comment and fill the Hyperlinks page: external vs same-post vs
cross-post links, native Org forms that export to relref, the
pre-processed.org resolve failure under Org 9.7+, and org-id tips
for id: links. Escape example shortcodes for the doc Hugo build.
org-hugo--get-pre-processed-buffer dominated single-subtree export on
large files (issue kaushalmodi#732): full AST re-serialization via
org-element-interpret-data, per-link org-export--collect-tree-properties
for id links, and rewriting every link in the file even when exporting
one post.

- Collect tree properties once for the whole preprocess pass
- Copy the source buffer text and splice rewritten links in place
  instead of interpret-data on the full AST
- For single-subtree export, only rewrite links inside that subtree;
  all-subtrees batch still rewrites every cross-post link once

On test/site/content-org/all-posts.org (~9k lines), single-subtree
export of "Links outside the same post" drops from ~3.2s to ~1.6s
with no GC in the timed runs; golden output unchanged.
Buffer-copy preprocess preserves Org source timestamp spacing;
interpret-data had normalized trailing spaces inside DEADLINE/SCHEDULED
spans. Align the golden with the source-faithful export.
Single-subtree export no longer runs org-element-parse-buffer on the
whole multi-post file.  Build a destination index with one
org-element-at-point per headline (cached on buffer-chars-modified-tick),
parse only the exported subtree for links, and splice rewrites into a
buffer copy.

All-subtrees batch keeps the full-parse path for the shared
pre-processed buffer.

Benchmark on test all-posts.org (~9k lines), single-subtree export of
"Links outside the same post": ~0.50s avg (was ~1.57s after buffer-copy,
~3.2s before).  Golden Markdown unchanged.
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.

1 participant