-
-
Notifications
You must be signed in to change notification settings - Fork 1k
perf(core): Performance fixes in GameProfilingSystem and ChromeTracingProfileWriter #1953
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
Conversation
…gProfileWriter - Fix busy-wait in `GameProfilingSystem` and make surrounding code clearer. - Add manual flushing to the JsonWriter, so the internal buffer doesn't grow indefinitely and put it on the fast path by skipping validation.
GameProfilingSystem - Would it be possible to separate receiving messages and updating strings into two separate, concurrent loops? I feel like there's a lot of complexity in reading the update method because it behaves one way in Fps mode, and differently in the other modes.
I don't think semaphore slim will add too much overhead on top of async here, but of course would be good to verify it doesn't change the perf much. |
Adding the semaphore adds about 80ns (~400ns -> ~480 ns) per event for me, I guess that would be okay? Alternatively, how about splitting into one task for fps display and a second task for detailed stats and then changing the active task depending on the active state.
That way the complexity in the update method is also removed from the update method and we don't have to worry about synchronization. But I'm fine with your suggestion too, if you prefer it. |
I want it to be readable most of all (you're suggestion is ok). |
if (asyncUpdateTask != null && !asyncUpdateTask.IsCompleted) | ||
{ | ||
stringBuilderTask.Wait(); | ||
asyncUpdateTask.Wait(); |
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.
Any long-running operation should have a TaskCancellationSource
and pass the associated CancellationToken
everywhere. Destroy()
should not hang on the next RefreshTime
tick.
if (eventReader != null) | ||
{ | ||
Profiler.Unsubscribe(eventReader); | ||
writerTask?.Wait(); |
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.
Why does it need to wait after Stop()
has been called. Can't it just signal a cancellation and return immediately?
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 think it would be good to wait here in order to observe any exception which may have been thrown
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.
This also need a CancellationTokenSource
to stop the task at the earliest opportunity. There should also be a protection against calling Start()
or Stop()
multiple times on the same instance.
Continued in #2050 |
PR Details
I took another look at the profiler changes I made, as @manio143 mentioned a perf issue.
I misunderstood how Utf8JsonWriter works - it won't flush to the underlying stream automatically, so there were constant reallocations. And in
GameProfilingSystem
checking if it is time to update the output turned into a busy-wait while not subscribed to the Profiler.Description
GameProfilingSystem
and make surrounding code clearer.Types of changes
Checklist