Skip to content

perf(ai-file): build the PPTX slide window by appending, not rewriting

변재혁 requested to merge feature/DOP-AI_성능테스트 into develop

The previous commit tuned compression per member. That was the wrong lever: on the real perf file it only reclassified 198 of 5,697 members (3.5%) and measured 1.6x, matching the null result observed on the pods (2.33s -> 2.13s, inside pod-to-pod variance).

The real file is nothing like the fixture that commit was measured against: 5,697 members, 42.76MB uncompressed -> 15.83MB (ratio 0.370), 89% of members under 16KB. Thousands of tiny compressible XML parts. zlib pays a fixed setup cost per stream - roughly 320KB of allocations including a 128KB head table it must zero - so a 200-byte member cost the same as a large one. Per read that was 11,394 zlib streams (inflate + deflate per member) and about 2GB of allocation churn, all below the 128KB mmap threshold and therefore cycling through the glibc arena. No compression setting fixes that; the stream count has to go.

zip resolves members through the central directory at the end of the file, and a later entry with the same name wins. So copy the source byte-for-byte (shutil.copyfile, which uses sendfile/copy_file_range on Linux - no user-space buffers) and append only the two rewritten manifest parts. Original members carry over with their compression, sizes and CRCs untouched, which also removes any chance of re-encoding zip64 or data-descriptor edge cases.

Measured on a fixture matching the real profile (5,697 members, 42.76MB -> 16.33MB, macOS): rewrite every member 0.880s 11,394 streams window 17.20MB per-member compression 0.544s 11,394 streams window 17.89MB append 0.024s 2 streams window 17.11MB (37x)

Risk: zip cannot delete members, so the original manifest stays in the file. If a reader picked the first entry the window would be ignored and every slide would load - peak memory scales with slide count, which the 20MB file guard does not bound. python-pptx picks the later entry (verified), and _warn_if_window_not_applied logs a warning when the resolved manifest is not ours. Production only warns and proceeds; the tests assert hard.

Tests: 10, replacing the compression-rule cases. Guards cover the appended directory shape, byte-identical carry-over of original members, the reader picking the appended manifest, only the requested slides loading, no leak of content from outside the window, and the warn-not-raise paths. Full suite 489 passed.

Co-Authored-By: Claude Opus 5 (1M context) noreply@anthropic.com

Merge request reports