-
-
Notifications
You must be signed in to change notification settings - Fork 108
perf: eliminate closure and Func creation
#4494
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
SummaryPerformance optimization that eliminates closure and Func allocations in hot paths by converting to static lambdas with explicit state parameters. Critical IssuesNone found ✅ SuggestionsConsider the IL2111 Suppression CarefullyThe Current approach: The PR adds the suppression with the justification "Type parameter is annotated at the method boundary." Why this is reasonable:
Recommendation: The suppression appears justified. The alternative would be to keep the closure (defeating the performance goal) or restructure the code in a more complex way. The justification message could be slightly more detailed: [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2111",
Justification = "Type parameter is properly annotated with DynamicallyAccessedMembers at both the method parameter and static lambda parameter. The trimmer warning is due to ConcurrentDictionary.GetOrAdd's internal reflection usage, but the type flows safely from the annotated method parameter.")]However, this is a minor improvement and not blocking. Verify Performance ImpactThe performance improvement shown in the screenshots looks excellent (from 1087 width to 619 width in the allocations). Consider:
Verdict✅ APPROVE - No critical issues This is a solid performance optimization that aligns perfectly with TUnit's "Performance First" principle. The closure elimination in hot paths (test discovery and context creation) will reduce allocations without changing behavior. The IL2111 suppression is reasonable given the proper annotations on both the method and lambda parameters. |
54e3f1c to
24edf38
Compare
24edf38 to
f6a4af6
Compare
SummaryEliminates closure and Func allocations by using state-passing overloads in GetOrAdd and ImmutableInterlocked.Update. Critical IssuesNone found ✅ SuggestionsMinor: Consider IL2111 suppression placementThe However, I noticed that The suppression justification is correct: the Minor: Pattern consistency verificationThis change makes The transformation is correct:
Both transformations in Previous Review StatusNo previous review comments found. Verdict✅ APPROVE - No critical issues This is a clean performance optimization that:
The closure elimination should reduce allocations during test discovery, which is particularly valuable given TUnit's focus on processing millions of tests efficiently. |
f6a4af6 to
054355b
Compare
SummaryPerformance optimization that eliminates closure and Func allocations in hot paths by using static lambdas with state-passing overloads. Critical IssuesNone found ✅ SuggestionsIL2111 Suppression Pattern - Consider Alignment with PropertyCacheManagerThe IL2111 suppression you've added to Your justification: Justification = "Type parameter is annotated at the method boundary."PropertyCacheManager pattern (line 41-42): Justification = "CreatePropertyArray is called with a type that has the required DynamicallyAccessedMembers annotation from the caller."Both are correct, but for consistency across the codebase, consider using a more explicit justification that matches the established pattern: [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2111",
Justification = "Static lambda receives type parameter with required DynamicallyAccessedMembers annotation from the method boundary.")]This makes it clearer why it's safe (the lambda receives the annotated parameter) rather than just stating that the parameter is annotated. Previous Review StatusTwo previous reviews by thomhurst already approved this PR. All points raised were informational/confirmatory rather than requesting changes. Verdict✅ APPROVE - No critical issues This is an excellent performance optimization that:
The transformation is textbook-perfect:
Great work on following #4479's pattern! |
054355b to
52e79e1
Compare
|
@TimothyMakkison if you rebase off of the latest main, is Sourcy still broken? |
52e79e1 to
cd5418d
Compare
|
Manullay updated API change tests and renamed category from "ReflectionAnalysis" to "Trimming"
I could try from the terminal or VS but it doesn't look like it was fixed 😢 |
cd5418d to
a5b55cb
Compare

Following on from #4479
Use function overloads to pass state into update methods.
I've used
UnconditionalSuppressMessageto suppress the following error,IL2111-Method with parameters or return value with `DynamicallyAccessedMembersAttribute` is accessed via reflection. Trimmer can't guarantee availability of the requirements of the method.Before
After