-
Notifications
You must be signed in to change notification settings - Fork 2.5k
macOS: Use @autoreleasepool in event pump to fix GC stutter #14757
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
base: main
Are you sure you want to change the base?
Conversation
Immediately release temporary objects to prevent memory pressure and unpredictable GC pauses during high-frequency input (e.g. rapid mouse movement).
|
Maybe the autorelease pool should be outside the for loop? |
|
The callers of Cocoa_PumpEventsUntilDate() already wrap the invocation in an autorelease pool. |
How many events have to be processed at once in order to trigger the GC pause? |
|
The GC pause happens each time execution leaves the autorelease pool. How long the pool takes to drain depends on how many events have built up in the loop, so the pause is not a fixed cost. Adding an @autoreleasepool inside the loop releases each event’s temporary objects right after processing, avoiding unpredictable drain times for the outer pool. |
|
It seems that if you add up the total autorelease time for each event with this patch and compare it to the autorelease time for all events with the existing code, that they would total about the same, is that correct? |
|
Yes, the total release time across all events should be roughly the same. The difference is that the cost is spread more evenly across events instead of happening in larger, less predictable chunks. |
|
But it all happens inside a single call to SDL_PollEvents(), right? e.g. existing code vs your change: Your change may have more overhead because of starting GC after every event, and delay event delivery while previous event GC is happening. What am I missing? |
|
The difference really comes down to when temporary objects from nextEventMatchingMask() and sendEvent() are destroyed. The total overhead is the same either way. With batched destruction, fast mouse movement on a high polling rate mouse can cause hundreds of objects to be released at once when the outer autorelease pool drains, at an unpredictable time. |
|
It's not an unpredictable time, it's at the end of SDL_PumpEvents(), right? |
|
BTW, I'm not objecting to your PR, I'm just trying to understand how it benefits applications. |
|
Yes, the pool is drained at the end of SDL_PumpEvents(), but the timing is not deterministic. You do not know how many events each call ends up processing, and the gap between consecutive SDL_PumpEvents() calls can vary. |
|
If the time to drain at the end equals the sum of the time to drain after each event, doesn't that end up with the same behavior? |
|
The difference is really just the timing jitter between one SDL_PumpEvents() call and the next. |
|
So let's say the work for one event is with the new code, the timing would be: The first pump events would take 2x GC and the second pump events would take 3x GC in both cases. I feel like I must still be missing something. Do you have timing logs that show the difference between the old code and your patch? |
Immediately release temporary objects to prevent memory pressure and unpredictable GC pauses during high-frequency input (e.g. rapid mouse movement).
Add an @autoreleasepool to the Cocoa_PumpEventsUntilDate loop to immediately release NSEvent objects.