perf: stream page-source XML with exception-safe resource cleanup - #1276
Merged
Merged
Conversation
KazuCocoa
marked this pull request as ready for review
September 29, 2026 06:03
mykola-mokhnach
approved these changes
Sep 30, 2026
github-actions Bot
pushed a commit
that referenced
this pull request
Sep 30, 2026
## [16.13.5](v16.13.4...v16.13.5) (2026-09-30) ### Performance Improvements * stream page-source XML with exception-safe resource cleanup ([#1276](#1276)) ([4e8639b](4e8639b))
|
🎉 This PR is included in version 16.13.5 🎉 The release is available on: Your semantic-release bot 📦🚀 |
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.
Page-source generation builds a complete libxml2 document and then traverses it again to produce a string. Snapshot or attribute exceptions also bypass manual cleanup and leak native objects.
Write page-source XML directly to an
xmlBufferusing a memory writer, preserving indentation and escaping. Keep document construction for XPath evaluation. Use@try/@finallyaround both paths to release writers, buffers, documents, and XPath results on success, early return, or exception.This combines review finding 3 (libxml2 resource leaks) with the XML streaming optimization. Tests compare serialized output against the document-based writer and inject an attribute exception to check document cleanup.
Performance experiment
Compared the two libxml2 serialization strategies used before and after this change in a standalone C microbenchmark:
xmlNewTextWriterDoc→ build a document →xmlDocDumpFormatMemory→ free the writer/document/output.xmlNewTextWriterMemory→ write directly into anxmlBuffer→ copy the output → free the writer/buffer/output.sample & value, exercising XML escaping. Both paths produce the same UTF-8 declaration and indentation.CLOCK_MONOTONICand includes allocation, serialization, output copying/dumping, and cleanup.-O2, system libxml2 reporting version20913(2.9.13). Results below are from one local run.For 5,000 children, the isolated serialization work decreased from 21.134 ms to 3.907 ms: 5.41× faster / 81.5% less time, with identical output.
Why this improves performance, and what the measurement covers
The document-based path allocates a DOM representation of the elements and attributes, walks it again to serialize the XML, and then frees that tree. The memory writer emits the XML during the initial traversal, avoiding the intermediate DOM and its second traversal. The benchmark includes a final output copy for the memory writer so it does not gain an artificial advantage from returning a borrowed buffer.
This measures the libxml2 serialization strategies, not the full Objective-C WDA endpoint. It excludes XCTest/accessibility snapshot acquisition, AX attribute retrieval, idle waits, NSString conversion, and HTTP transport. It does not establish a 5.41× end-to-end
/sourcespeedup, and it does not measure peak memory. Device-level profiling is still needed to quantify the overall benefit on real applications. XPath evaluation continues to use a DOM; this benchmark does not claim faster XPath queries. The exception cleanup is a separate correctness improvement.Reproduce the benchmark
Save the following as
/tmp/xml-bench.c:Compile and run on macOS with Xcode command-line tools:
xcrun clang -O2 \ -I "$(xcrun --sdk macosx --show-sdk-path)/usr/include/libxml2" \ /tmp/xml-bench.c -lxml2 -o /tmp/xml-bench /tmp/xml-benchThe program prints output equality, median and mean times, and the median speedup for each fixture size. Absolute timings depend on the machine and system load.
Regression validation
All 178 native unit tests passed on an iOS 26.5 simulator using a local integration branch containing this review series, built with Xcode 27.1. The regression tests are included in this PR. The output-comparison fixture includes XML special characters, newlines, tabs, and non-ASCII text; the exception-injection test checks document cleanup.