Skip to content

perf(layout): Render only the requested page when hotloading - #533

Open
KRRT7 wants to merge 1 commit into
Unstructured-IO:mainfrom
KRRT7:perf/render-single-annotate-page
Open

KRRT7 wants to merge 1 commit into
Unstructured-IO:mainfrom
KRRT7:perf/render-single-annotate-page

Conversation

@KRRT7

@KRRT7 KRRT7 commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Summary

PageLayout._get_image hotloads a page image for annotate() when the page has neither an image nor an image path. It rendered every page of the PDF to PNG in a temp dir and then opened one of them, so its cost grew with document length. It now passes the page to convert_pdf_to_image as first_page/last_page, so only that page is rendered.

Impact

sample-docs/pdf2image-memory-error-test-400p.pdf, one call:

Before After
Page 1 19.9 s 0.07 s
Page 400 16.3 s 0.05 s
Temporary PNGs at peak ~165 MiB one page

Behavior preserved

  • Page numbers below 1 index from the end of the document (image_paths[page_number - 1]); page 0 returns the last page, which test_get_image relies on. Those still render every page.
  • A page past the end raises the same ValueError.
  • Pixels, size, mode and rotation metadata (pdf_rotation, pdf_rotation_correction) match the previous output for every page number from −n−1 to n+1. Checked on rotated-page-90.pdf, loremipsum_multipage.pdf, empty-document.pdf, layout-parser-paper.pdf, form-field.pdf, and a generated 5-page document with pages rotated 0/180/90/270/90. That covers rotation corrections that are looked up by page index when only part of the document is rendered.

Verification

  • New tests in test_unstructured_inference/inference/test_layout.py:
    • only the requested page is rendered, and its pixels match a full render (fails on main)
    • page numbers 0, −1 and −9 still index from the end
    • a page past the end still raises ValueError
  • make test: 386 passed, 1 skipped. ruff check / ruff format --check clean.

No overlap with #524, which adds pre-rendered image_paths to from_file/process_file_with_model and doesn't touch _get_image. Version bumped to 1.6.17 with a CHANGELOG entry; #530–#532 also target 1.6.17, so later merges need the next patch version.

View guided diff

PageLayout._get_image, which annotate() uses when a page has neither an
image nor an image path, rendered every page of the PDF to PNG and then
opened one. Pass the page as first_page/last_page so only that page is
rendered. Getting one page of a 400-page PDF drops from 16-20s to under
0.1s, and the temporary PNGs from about 165 MiB to a single page.

Page numbers below 1 index from the end of the document, so those still
render every page. A page past the end still raises the same
ValueError. Rendered pixels, size and rotation metadata match the
previous output for every page number from -n-1 to n+1 on the sample
PDFs and on a mixed-rotation document.

Co-authored-by: wtfyd-agent[bot] <328989958+wtfyd-agent[bot]@users.noreply.github.com>
@KRRT7

KRRT7 commented Oct 24, 2026

Copy link
Copy Markdown
Contributor Author

Combined effect of #530, #531, #532 and #533 merged together onto main (9a227e7), measured against main on the same machine with alternating runs:

main all four
Peak RSS, layout-parser-paper.pdf (16 pages) through YoloX 1014–1015 MiB 666–674 MiB
RSS after importing inference.layout + models.base 369–417 MiB 148–149 MiB
structure_to_cells, synthetic 120×12 table, 8k tokens 28.3 s 0.33 s
PageLayout._get_image, page 200 of the 400-page sample 24.5 s 0.11 s
  • The 16-page YoloX output hash (coordinates, probabilities, class ids per page) is identical to main.
  • make test passes on the combined branch: 415 passed, 1 skipped.
  • The code changes merge without conflicts. All four PRs bump to 1.6.17, so each one merged after the first needs the next patch version.
  • Timings came from a busy machine and read about 2× high in absolute terms; the memory numbers were stable across runs.

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