-
-
Notifications
You must be signed in to change notification settings - Fork 879
Fix async image load #2006
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix async image load #2006
Conversation
…e subsequent image loading operations can safely use synchronous IO
…ons after preloading the stream, rather than async actions (since the async actions all ultimately operate synchronously anyway)
Everything looks good so far from an implementation perspective. We'll need to figure out a strategy now to compare the new Async performance with Main. |
@antonfirsov I just pushed a change to Allocation blocks match this scale.
Once the total allocation within the stream hits our threshold we immediately switch to allocating larger chunk sizes. I chose the the the values for the following reasons
I'm not precious about any of these values to if you feel like they should change then please suggest alternatives. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm approving this but want a second opinion before merging.
I want to take a look next week. Quite distracted from everything programming-related thanks to the ongoing Fourth Reich experiment on my continent, right in the neighborhood. |
Of course mate. Absolute horror show over there! |
@kroymann can you please give me permission to push to your branch? (Thought it is always allowed for contributors for PR branches.) As an alternative, feel free to cherry pick it. |
I did before / after runs of asnchronous load testing:
We should try to address it. Will take quick look at the code changes now. BeforeAfter |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I have no instant idea to improve this.
If you guys both agree that 25% extra memory footprint is an acceptable price for correct async, I'm fine merging this. We can open an issue to track the sync/async memory gap.
Just please remember to merge my load test addition!
Btw @kroymann thanks for discovering the problem, and pushing through the fix, really great job! |
@antonfirsov Your permissions issues were likely due to Git LFS issues with GitHub. There's a workaround that should allow you to push to the fork.
I'm assuming the memory overheads come from my buffer allocation? Would a drop to 2MB segments be useful? |
@antonfirsov I think @JimBobSquarePants is right about the github permissions, but I went ahead and cherry-picked your commit just to expedite things. Thank you for adding those tests! |
2MB logical allocations lead to 4MB actual allocations since buffers are uniform. Actually, there might be a way to create a smarter buffer growing strategy. This is how subsequent chunks sizes are allocated currently if I get it right.
This stressing the 128K ArrayPool unnecessarily, and often leads to a wasteful allocation in the end. Instead, I would try to do something like:
This would keep most of the buffers rented from |
Yeah, that's how it's allocated currently. Shouldn't be too hard to update it to follow your pattern. |
Here is a closed formula to get the i-th chunk size according to my logic, assuming you increment private static int GetChunkSize(int i)
{
const int _128K = 1 << 17;
const int _4M = 1 << 22;
return i < 16 ? _128K * (1 << (i / 4)) : _4M;
} Tomorrow is the last day I have access to my benchmark machine to redo the benchmarks, I will leave for two weeks afterwards. |
It's always tomorrow in Aus! That's the changes pushed. I added a check to ensure we always use the min of the allocator capacity or the calculated size, in case we change things in the future or someone implements their own allocator. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks for the patience!
Co-authored-by: Anton Firszov <antonfir@gmail.com>
Prerequisites
Description
This addresses the issue outlined in #1997 where
Image.LoadAsync(stream)
would incorrectly use synchronous IO if the stream is seekable. The fix is simply to remove the optimization that avoids prebuffering the stream into an in-memory buffer if the stream is seekable, and instead always prebuffer the stream. This ensures that async IO is always used to read the stream.