Repository navigation
Conversation
MinElf reads ELF fields a few bytes at a time and moves back and forth between the headers, the dynamic section and the string table. ElfZipFileChannel served each of those reads straight from the entry's InputStream, so resolving one library's dependencies took hundreds of tiny stream reads. Serve reads from an 8 KiB buffer instead. This speeds up resolving library dependencies in both DirectApkSoSource and DirectSplitSoSource. It also fixes latent issues in read(ByteBuffer, long), which MinElf doesn't trigger today: - It ignored short reads and skips from the underlying stream. - It copied into the backing array at offset 0 instead of at the buffer's position. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
MinElfreads ELF fields a few bytes at a time, and library names one byte at a time.ElfZipFileChannelpassed each of those reads straight to the entry'sInputStream, so resolving the dependencies oflibreactnative.sotook 178 stream reads and 85 skips.This serves reads from an 8 KiB buffer and only touches the stream to refill it. The same lookup now takes 20 reads and 18 skips.
DirectSplitSoSourceuses the same channel, so it benefits too.Since
read(ByteBuffer, long)is rewritten anyway, it now also:InputStream.readorskipreturn fewer bytes than asked;Neither case is reachable today. Both callers only open stored entries, whose streams return full counts in practice, and
MinElfalways reads into a fresh buffer at position 0.Test plan
Same setup as #152. Median time to full display, from one run with all four builds side by side (R8 off, the template default):
mainAgainst
main, this PR is −3.6% (−6.7% to −0.3%) on the small APK and −1.5% (−3.7% to +0.9%) on the large one. On top of #152 it's −4.0% (−7.5% to −0.6%) and −1.0% (−3.8% to +2.1%). On the large APK, the repeated central-directory parse that #152 removes dominates, so this change mostly shows on the small one. These are estimated over all launches with 95% confidence intervals.Repeating the run with R8 on gave the same picture: both PRs together measured −5.3% (−8.3% to −2.5%) and −13.4% (−16.3% to −10.7%) against
main.On the JVM, I fuzzed
read(ByteBuffer, long)with 8,000 random reads over stored and deflated entries, and 1,200 more against streams that never skip and return at most 7 bytes per read. Every byte, return value and position matched the entry; the current code fails this.MinElfreturns the same dependencies for all 10 libraries in the APK, stored and deflated, matchingllvm-readelf -d.🤖 Generated with Claude Code