Skip to content

Razor TagHelperDescriptor Hashing #24551

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

Merged
merged 5 commits into from
Aug 4, 2020
Merged

Conversation

TanayParikh
Copy link
Contributor

@TanayParikh TanayParikh commented Aug 3, 2020

1/2 PRs for https://github.com/dotnet/aspnetcore/issues/23170

  • I was running into quite a few hash-collisions so decided to revamp the hashing logic throughout the TagHelperDescriptor to minimize collisions.
  • Added (collision) testing.
  • Added a TagHelperDescriptor memory cache.

The other PR utilizes these changes: dotnet/razor#2307

1/2 PRs for https://github.com/dotnet/aspnetcore/issues/23170

The other PR will be in aspnetcore-tooling to utilize these changes.
@@ -5,7 +5,6 @@
using System.Collections.Generic;
using Microsoft.AspNetCore.Razor.Language;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
Copy link
Contributor Author

@TanayParikh TanayParikh Aug 4, 2020

Choose a reason for hiding this comment

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

Shared file update from tooling.

TanayParikh added a commit to dotnet/razor that referenced this pull request Aug 4, 2020
2/2 PRs for https://github.com/dotnet/aspnetcore/issues/23170

Other PR: dotnet/aspnetcore#24551

- Used the project for a short period of time
	- Created a file, navigated between files, made some edits.
	- I ran into 238 cache misses (unique taghelper allocations) and 4612 cache hits
	- 95%+ cache hit
	- Scales up incredibly well. Number of TagHelperDescriptors unlikely to change unless
		- New files added
		- New assemblies / packages added

### Benchmarks
|                   Method |     Mean |    Error |   StdDev |    Op/s | Allocated |
|------------------------- |---------:|---------:|---------:|--------:|----------:|
| 'TagHelpers GetHashCode' | 0.137 ms | 1.279 us | 1.196 us | 7,306.8 |  17.93 KB |

|                                    Method          |     Mean |     Error |    StdDev |  Op/s |   Gen 0 |   Gen 1 |   Gen 2 | Allocated |
|----------------------------------------------------|---------:|----------:|----------:|------:|--------:|--------:|--------:|----------:|
| 'Cached Razor TagHelper Roundtrip Serialization'   | 3.243 ms | 0.0634 ms | 0.0593 ms | 308.4 | 42.9688 | 39.0625 | 35.1563 |   1.95 MB |
| 'Uncached Razor TagHelper Roundtrip Serialization' | 4.891 ms | 0.1082 ms | 0.0959 ms | 204.4 | 78.1250 | 54.6875 | 39.0625 |   3.85 MB |

 Note `GetHashCode` has minimal perf overhead in comparison to the underlying serialization/deserialization cost. As a result we get 33% faster roundtrip serialization and half the memory utilization.

|                                    Method |     Mean |     Error |    StdDev |  Op/s |   Gen 0 |   Gen 1 |   Gen 2 | Allocated |
|------------------------------------------ |---------:|----------:|----------:|------:|--------:|--------:|--------:|----------:|
|    'Before Razor TagHelper Serialization' | 1.782 ms | 0.0353 ms | 0.0378 ms | 561.3 | 35.1563 | 35.1563 | 35.1563 |   1.11 MB |
|     'After Razor TagHelper Serialization' | 1.932 ms | 0.0385 ms | 0.0632 ms | 517.6 | 35.1563 | 35.1563 | 35.1563 |   1.13 MB |
|  'Before Razor TagHelper Deserialization' | 4.198 ms | 0.0173 ms | 0.0161 ms | 238.2 | 39.0625 | 15.6250 |       - |   3.28 MB |
|   'After Razor TagHelper Deserialization' | 4.279 ms | 0.0215 ms | 0.0201 ms | 233.7 | 39.0625 | 15.6250 |       - |   3.29 MB |

Note, marginally higher CPU/Memory for unidirectional serialization/deserialization due to cost of hashing. Note this benchmark would not benefit for caching.
@TanayParikh TanayParikh marked this pull request as ready for review August 4, 2020 01:17
@TanayParikh TanayParikh changed the title Razor TagHelperDescriptor Hashing and Caching Razor TagHelperDescriptor Hashing Aug 4, 2020
@ghost
Copy link

ghost commented Aug 4, 2020

Hello @TanayParikh!

Because this pull request has the auto-merge label, I will be glad to assist with helping to merge this pull request once all check-in policies pass.

p.s. you can customize the way I help with merging this pull request, such as holding this pull request until a specific person approves. Simply @mention me (@msftbot) and give me an instruction to get started! Learn more here.

@Pilchie Pilchie added the area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates label Aug 4, 2020
@TanayParikh TanayParikh merged commit 29ceed2 into master Aug 4, 2020
@TanayParikh TanayParikh deleted the taparik/taghelper_caching branch August 4, 2020 20:06
TanayParikh added a commit to dotnet/razor that referenced this pull request Aug 5, 2020
* TagHelperDescriptor Hashing and Caching

2/2 PRs for https://github.com/dotnet/aspnetcore/issues/23170

Other PR: dotnet/aspnetcore#24551

- Used the project for a short period of time
	- Created a file, navigated between files, made some edits.
	- I ran into 238 cache misses (unique taghelper allocations) and 4612 cache hits
	- 95%+ cache hit
	- Scales up incredibly well. Number of TagHelperDescriptors unlikely to change unless
		- New files added
		- New assemblies / packages added

### Benchmarks
|                   Method |     Mean |    Error |   StdDev |    Op/s | Allocated |
|------------------------- |---------:|---------:|---------:|--------:|----------:|
| 'TagHelpers GetHashCode' | 0.137 ms | 1.279 us | 1.196 us | 7,306.8 |  17.93 KB |

|                                    Method          |     Mean |     Error |    StdDev |  Op/s |   Gen 0 |   Gen 1 |   Gen 2 | Allocated |
|----------------------------------------------------|---------:|----------:|----------:|------:|--------:|--------:|--------:|----------:|
| 'Cached Razor TagHelper Roundtrip Serialization'   | 3.243 ms | 0.0634 ms | 0.0593 ms | 308.4 | 42.9688 | 39.0625 | 35.1563 |   1.95 MB |
| 'Uncached Razor TagHelper Roundtrip Serialization' | 4.891 ms | 0.1082 ms | 0.0959 ms | 204.4 | 78.1250 | 54.6875 | 39.0625 |   3.85 MB |

 Note `GetHashCode` has minimal perf overhead in comparison to the underlying serialization/deserialization cost. As a result we get 33% faster roundtrip serialization and half the memory utilization.

|                                    Method |     Mean |     Error |    StdDev |  Op/s |   Gen 0 |   Gen 1 |   Gen 2 | Allocated |
|------------------------------------------ |---------:|----------:|----------:|------:|--------:|--------:|--------:|----------:|
|    'Before Razor TagHelper Serialization' | 1.782 ms | 0.0353 ms | 0.0378 ms | 561.3 | 35.1563 | 35.1563 | 35.1563 |   1.11 MB |
|     'After Razor TagHelper Serialization' | 1.932 ms | 0.0385 ms | 0.0632 ms | 517.6 | 35.1563 | 35.1563 | 35.1563 |   1.13 MB |
|  'Before Razor TagHelper Deserialization' | 4.198 ms | 0.0173 ms | 0.0161 ms | 238.2 | 39.0625 | 15.6250 |       - |   3.28 MB |
|   'After Razor TagHelper Deserialization' | 4.279 ms | 0.0215 ms | 0.0201 ms | 233.7 | 39.0625 | 15.6250 |       - |   3.29 MB |

Note, marginally higher CPU/Memory for unidirectional serialization/deserialization due to cost of hashing. Note this benchmark would not benefit for caching.


* Add duplicate key safeguard in memory cache

https://dev.azure.com/dnceng/public/_build/results?buildId=757405&view=ms.vss-test-web.build-test-results-tab&runId=23507082&resultId=100079&paneView=debug

> System.ArgumentException : The key already existed in the dictionary.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants