Skip to content
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

Allocation cleanup #508

Merged
merged 9 commits into from
Oct 30, 2024
Merged

Allocation cleanup #508

merged 9 commits into from
Oct 30, 2024

Conversation

rossgrambo
Copy link
Contributor

Why this PR?

We noticed we were allocating a lot of memory in v4 compared to v3. This PR resolves many instances of extra allocations or memory and resolves some issues that existed in v3 as well.

Now- the allocations are just the EvaluationEvent object (which could be improved more for the boolean and missing defintion case), async closures, and enumerators only when needed.

Additionally-

  • Resolves some spelling issues
  • Adds a pull request template
  • Bumps vulnerable packages in examples and test projects

Visible Changes

No changes are visible to developers using the library. They may notice allocation wins.

@rossgrambo rossgrambo requested a review from zhenlan October 28, 2024 22:54
@rossgrambo
Copy link
Contributor Author

@avanigupta @zhiyuanliang-ms @zhenlan This is blocking v4 release If you have time to review!

@@ -1976,4 +1976,51 @@ public async Task CustomIFeatureDefinitionProvider()
Assert.True(called);
}
}

public class PerformanceTests
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use the tool like benchmark .net to verifiy this change can improve the performance?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we create an issue to track this? It doesn't need to block v4 release.

Copy link
Contributor Author

@rossgrambo rossgrambo Oct 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created issue: #512

In the meantime- I created a repo to run BenchmarkDotNet tests against multiple versions of this library. Here's a link to the results/repo (Same results as the screenshot shared in another comment): https://github.com/rossgrambo/FeatureManagementBenchmark/blob/main/BenchmarkDotNet.Artifacts/results/FeatureManagementBenchmark.Benchmarks-report-github.md

@zhiyuanliang-ms
Copy link
Contributor

@rossgrambo Could please explain why storing task in the dictionary can save memory?

@rossgrambo
Copy link
Contributor Author

rossgrambo commented Oct 29, 2024

The single line that caused a developer to write in was:

return Task.FromResult(
                _definitions.GetOrAdd(
                    featureName,
                    (_) => GetMicrosoftSchemaFeatureDefinition(featureName) ?? GetDotnetSchemaFeatureDefinition(featureName)));

The problem with this function is that the lambda/delegate/func syntax of:

(_) => ...

Creates a Func. Although it's not called in the case we hit the cache- it still allocates memory for the func every time this line is hit. This is because it happens before the GetOrAdd method is called actually called, as the parameters are resolved first before the method can be called.

This line also uses Task.FromResult. This creates a unique Task object on each request- even when the item is found in cache. By adjusting the cache to include the Task, we're able to keep a 1:1 relationship between Task and FeatureDefinition- rather than a 1:1 between Task and number of calls to IsEnabledAsync().

@zhiyuanliang-ms
Copy link
Contributor

Discussed offline with @rossgrambo, this PR looks good to me.

@rossgrambo
Copy link
Contributor Author

Most benchmarking was done in VS- but it doesn't have a great way to compare. BenchmarkDotNet does! Here's the result (4.0.0/4.9999.9999 includes these changes):

image

@rossgrambo
Copy link
Contributor Author

Ran test again using .net8 (previous screenshot was .net6). This version is actually the most performant when using .net 8.
image

@rossgrambo rossgrambo merged commit e1e98b5 into main Oct 30, 2024
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants