-
-
Notifications
You must be signed in to change notification settings - Fork 108
perf: make methods synchronous and prevent closure creation #4269
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
|
A lot of these techniques can be applied to other areas. |
|
This sounds like a good saving! AsyncConverter probably can be improved. Initially wanted to move it to the source generator to reduce as much as possible, but the logic is just way more complicated than runtime checks |
SummaryPerformance optimization that eliminates redundant closures and state machines in hook execution, saving ~180MB (10% of total) on TUnit.TestProject. Critical IssuesNone found ✅ Suggestions1. Missing using directive in new codeThe diff shows
If the annotation isn't necessary for the AOT scenario, consider removing it to keep the change minimal. 2. Consider ValueTask optimization for no-timeout pathIn return ExecuteHookWithPotentialCustomExecutor(hook, context, cancellationToken).AsTask();Since This is a minor point - the current change is already excellent. Just noting for future optimization. Observations✅ Excellent alignment with TUnit Rule #4 (Performance First): This change demonstrates deep understanding of async state machine allocations and closure capture Verdict✅ APPROVE - Excellent performance optimization with no correctness issues |
Largest memory saving, I reckon I'll be able to make by eliding state machines and removing redundant closures.
Directly return a task and remove the async keyword to avoid allocating a state machine
Methods like
CreateStaticHookDelegateAsyncwere creating aFunc<Task>viaCreateTimeoutHookActionbefore immediately invoking and awaiting it. I changed it to directly return aTaskas the defered execution was never used.Get
int timoutMsbefore passing it intoCreateTimeoutHookActionAsync, this makes the resulting state machine 8 bytes smaller because it can pack the 4 byte integer with the state machinestateinteger.Move
HookTimeoutHelper.ExecuteHookWithPotentialCustomExecutorto a different method to prevent closure creation.hook.ExecuteAsync, the compiler will still eagerly generate and allocate the closures even when they aren't needed.This saves around 180MB on
TUnit.TestProjectaround 10% of total memory usage.Before
After
Note that
TUnit.Engine.Helpers.HookTimeoutHelper+<<CreateTimeoutHookAction>g__CreateTimeoutHookActionAsync|0_0>d<TestContext>is large because it replaces aFunc<Task>, a closure forCreateTimeoutHookActionand an async state machine costing around 150MB total.