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

Perf improvements to AcquireTokenForClient flow #2261

Merged
merged 10 commits into from
Dec 3, 2020
Merged

Conversation

pmaytak
Copy link
Contributor

@pmaytak pmaytak commented Dec 2, 2020

Issue #2204

Changes include:

  • Update GetAllAccessTokens method to return IEnumerable instead of a List.
  • Use IEnumerable.Where instead of FilterWithLogging, in ITokenCacheInternal.FindAccessTokenAsync.
  • Add checks if the serialization cache delegates were set, before calling them.

Added a BenchmarkDotNet performance test project to test the AcquireTokenForClient. Tested with cache size of 100, 1k, 10k, and 100k items. Also ran the test multiple times. There was some spread in mean data points between the runs (although I'm not sure why). (The spread was wider pre-fixes and much narrower post-fixes, except for .NET 4.8 which basically had no spread.) .NET 5 seems to be slightly faster than .NET Core 3.1 which is slightly faster than .NET 4.8. Below is the summary data.

.NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203)

Items in cache Mean (pre-fixes) Mean (post-fixes) Improvement
100 71 - 91 μs 64 - 73 μs 10 - 20 %
1000 674 - 854 μs 400 - 571 μs 34 - 41 %
10000 7.5 - 10 ms 4.6 - 6.2 ms 38 %
100000 122 - 176 ms 83 - 117 ms 32 - 34 %

Using in-memory token serialization cache yielded very similar results post-fix.
With in-memory token serialization cache:

Items in cache Mean (post-fixes)
100 66 - 71 μs
1000 407 - 530 μs
10000 5.2 - 6 ms
100000 85 - 114 ms

.NET Core 5.0.0 (CoreCLR 5.0.20.51904, CoreFX 5.0.20.51904)

Items in cache Mean (pre-fixes) Mean (post-fixes) Improvement
100 67 - 89 μs 54 - 62 μs 20 - 31 %
1000 421 - 684 μs 292 - 482 μs 30 %
10000 5.5 - 8.9 ms 4.8 - 5.4 ms 13 - 40 %
100000 111 - 165 ms 69 - 98 ms 38 - 41 %

.NET Framework 4.8 (4.8.4250.0 runtime)

Items in cache Mean (pre-fixes) Mean (post-fixes) Improvement
100 111 - 113 μs 84 - 88 μs 23 - 25 %
1000 593 - 614 μs 515 - 531 μs 14 %
10000 12.3 ms 7.3 ms 41 %
100000 134 - 137 ms 105 ms 22 - 24 %

.NET Framework 4.6.1 (4.8.4250.0 runtime)

Items in cache Mean (pre-fixes) Mean (post-fixes) Improvement
100 105 - 110 μs 78 - 81 μs 26 %
1000 591 - 602 μs 476 - 499 μs 18 - 20 %
10000 12.3 - 12.4 ms 7.4 - 7.9 ms 37 - 40 %
100000 135 ms 100 ms 26 %

Machine specs:

BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19042
Intel Core i7-9850H CPU 2.60GHz, 1 CPU, 12 logical and 6 physical cores
.NET Core SDK=5.0.100

.NET Framework 4.6.1 (4.8.3928.0 runtime)

Items in cache Mean (pre-fixes) Mean (post-fixes) Improvement
100 124 μs 89 μs 29 %
1000 712 - 726 μs 574 - 577 μs 20 %
10000 14.7 ms 8.5 ms 43 %
100000 159 - 162 ms 118 ms 25 - 28 %

.NET Framework 4.6.1 (4.6.1055.0 runtime)

Items in cache Mean (pre-fixes) Mean (post-fixes) Improvement
100 146 - 149 μs 105 μs 29 %
1000 829 - 838 μs 655 μs 21 %
10000 18 - 18.8 ms 10.9 - 11.1 ms 40 %
100000 200 - 205 ms 151 ms 26 %

Machine specs:

BenchmarkDotNet=v0.12.1, OS=Windows 8.1 (6.3.9600.0), VM=Hyper-V
Intel Xeon Platinum 8272CL CPU 2.60GHz, 1 CPU, 8 logical and 4 physical cores
.NET Framework 4.6.1 (4.6.1055.0)

@henrik-me
Copy link
Contributor

henrik-me commented Dec 2, 2020

Would really like to see numbers for .net 4.6.1 runtime to be able to compare with 4.8 runtime

@henrik-me
Copy link
Contributor

Wondering if we should add a hashmap to make lookup faster?

@pmaytak pmaytak marked this pull request as ready for review December 3, 2020 07:44
pmaytak and others added 8 commits December 3, 2020 17:15
… Add a check for existing cache delegates before calling them.
Using normal Where instead of FilterWithLogging.
Add checks if the cache delegates were set, before calling them.
Add performance test project. Update TokenCacheHelper to be able to add N tokens.
// if only one cached token found
if (filteredItems.Count() == 1)
if (filteredItems.Count == 1)
{
Copy link
Collaborator

Choose a reason for hiding this comment

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

this is much better.

}

return metadata;
return _appMetadataDictionary.Select(kv => kv.Value);
Copy link
Collaborator

Choose a reason for hiding this comment

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

+1 to removing code.

Copy link
Collaborator

@jennyf19 jennyf19 left a comment

Choose a reason for hiding this comment

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

:shipit:

}

return rts;
return _refreshTokenCacheDictionary.Select(kv => kv.Value).ToList();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@bgavrilMS As discussed, added ToList in these methods, since we need to investigate what the impact of returning an IEnumerable is.

@pmaytak pmaytak merged commit cf6ccaf into master Dec 3, 2020
@pmaytak pmaytak deleted the pmaytak/GetAllAT branch December 3, 2020 22:04
@pmaytak pmaytak restored the pmaytak/GetAllAT branch December 5, 2020 03:35
@pmaytak pmaytak deleted the pmaytak/GetAllAT branch January 14, 2021 03:03
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.

4 participants