Repository navigation
perf(decode): reuse component planes across decodes (system-allocator gap, remade_ffmpeg_rs#48) - #15
Merged
Merged
Conversation
A decode to RGB sized one plane per component (~3.1 MB for a 1080p 4:2:0 frame) and dropped them as soon as the image was assembled, so a caller that builds a fresh Decoder per image -- thumbnailers, MJPEG frame loops, the ArtCraft apps in remade_ffmpeg_rs#48 -- paid for those pages to be faulted in on every decode. Under rusty_alloc/mimalloc that was nearly free; under the Windows system heap it was +0.43 ms per 1080p frame and left 0.4.4 1.13-1.17x behind zune-jpeg on one core (reported by ArtCraft, reproduced 16/16). `compute_image` now borrows the planes and hands them to a small thread-local pool (`decode::plane_pool`); the next decode on the thread takes the best-fitting one before allocating. Bounded to 4 planes and 64 MB (an oversized image's planes are not kept), disabled with RUSTY_JPEG_PLANE_POOL=0, a no-op without std. Planes are refilled, never trusted: every block is written before a plane is read, which the cross-image check confirms. Byte-identical: 30-file fixture set per file, plus all 30 decoded forwards then backwards in ONE process (planes passing between images of different sizes and subsamplings), single- and multi-threaded, under both allocators: 60/60 identical to 0.4.3. Measured vs 0.4.4, default decode() pinned to 1 core, ABBA 20x20, wall: system allocator new/0.4.4 (paired) new/zune-jpeg 0.5.15 frame1080 0.863, 19/20 (z -4.02) 1.016 (zune 16/20) photo2000s 0.883, 20/20 (z -4.47) 0.978, 17/20 photo2000 0.945, 19/20 (z -4.02) 0.946, 19/20 rusty_alloc new/0.4.4 (paired) new/zune-jpeg 0.5.15 frame1080 0.964, 14/20 (z -1.79) 0.956, 17/20 photo2000s 0.986, 14/20 (z -1.79) 0.892, 20/20 photo2000 1.001, 10/20 (neutral) 0.932, 17/20 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.
ArtCraft found that 0.4.4 is still behind zune-jpeg on one core under the system allocator: 1.13–1.15x on the photo and 1.22–1.24x on the 1080p frame. My earlier numbers were all under rusty_alloc, which hid it. Reproduced here: 1.13x and 1.17x, 16/16 rounds.
Cause: with a fresh
Decoderper image, the ~3.1 MB of component planes per 1080p decode page-fault on every decode under the Windows heap (+0.43 ms).Fix:
compute_imagereturns the planes to a bounded thread-local pool, and the next decode reuses them.RUSTY_JPEG_PLANE_POOL=0disables it.Correctness: byte-identical to 0.4.3. That includes 60 decodes run in one process, so pooled planes cross between images of different sizes and subsamplings, under both allocators.
🤖 Generated with Claude Code