GetRawImage() allocated a fresh JFJochReaderRawImage per frame, and on a
miniCBF sweep its buffer holds the whole decoded image: 72.6 MB on a 4150 x
4371 detector. That is over glibc's 32 MB mmap ceiling, so the block is mmapped
and munmapped every image and the decoder faults in 17 700 untouched pages as it
writes them. Measured on one 18.1 Mpx frame, decoding into a fresh buffer takes
61 ms against 16 ms into one that has been written before - the allocation costs
nearly three times what the decode does, and the per-image loop pays it twice
per sweep.
ReadRawImage() fills a raw image the caller owns, so a worker declares one
outside its loop and keeps the pages. GetRawImage() stays as the allocating
wrapper for the single-image callers. The two loops that hand the image to the
process-file writer keep a shared_ptr and recycle it only while the writer
thread is not still reading the previous frame's pixels.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>