-
Notifications
You must be signed in to change notification settings - Fork 816
Shrink StringValues #1283
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
Shrink StringValues #1283
Conversation
885f326
to
6cc0698
Compare
@davidfowl we've tried this before. Why did we abandon it last time? |
The last time we made the struct bigger by adding and encoding and a This change is good! I still want to look at what it would take to store utf8bytes as well. |
Follow up would be to drop the |
@davidfowl @benaadams @JunTaoLuo Back then we experimented with that, we tried changing the StringValues struct to include only a single _value object and type-checking to determine if _value was null, string, string[] or StringsAndEncodedValues. Basically what this PR does. It improved perf significantly in our benchmarks. Then we tried naively leaving three typed fields (string _value, string[] _values and byte[] _encodedValues) and changing StringValues to a class. This yielded just-as-good-if-not-better performance than making StringValues a single-object StringValues, and also made the code a bit simpler since it checked if each field was set instead of type-checking a single _value object. I think the reason we never made the change to make StringValues a single-object struct before is the fact that we had the "better" fix of changing StringValues to class that was too breaking ready to go. Now that we're approaching 3.0, can we just make the breaking change and make StringValues a class? We still wouldn't need to allocate for null (since the StringValue could actually be null), and in the other cases your generally allocating strings or string arrays anyway. If you're using cached strings/string arrays, you could instead use cached StringValues. |
If you wanted to add Nullability annotations it would make it horrible as every callsite would have to be Also it pushes null up into every usage e.g. |
Another expression of this is you can happily do var charCount = RequestHeaders["random-header"].ToString().Length;
var elementCount = RequestHeaders["random-header"].ToArray().Count(); Whereas if it was nullable then it should be more like? var charCount = RequestHeaders["random-header"]?.ToString()?.Length ?? 0;
var elementCount = RequestHeaders["random-header"]?.ToArray()?.Count ?? 0; |
Even without nullability annotations, it's probably too big a change to be worth trying this late in the 3.0 dev cycle. I also cannot guarantee that a StringValues class still benchmarks better than a single-object StringValues struct, but that's how I remember things from over three years ago before 1.0 when we first looked into it, and I don't have any specific reason to suspect this has changed. I just figured I'd bring it up the possibility, so everyone remembers making StringValues a class might be an option. Who knows, maybe the change is easier than I think it would be. |
Also, if we're making breaking changes you could make a ToArray() extension method that allows for null. You're probably SOL for ToString() though 😉 |
Commit migrated from dotnet/extensions@2f8e1fb
Commit migrated from dotnet/extensions@2f8e1fb
Commit migrated from dotnet/extensions@2f8e1fb
Commit migrated from dotnet/extensions@2f8e1fb
Commit migrated from dotnet/extensions@2f8e1fb
Commit migrated from dotnet/extensions@2f8e1fb
* Reorganize source code In preparation for merging many other projects into this repo, this establishes a new source code organization which groups projects together based on subject matter. Commit migrated from dotnet/extensions@7ce647c * Merge branch 'release/2.1' into release/2.2 Commit migrated from dotnet/extensions@18fcffb * Merge branch 'release/2.2' Commit migrated from dotnet/extensions@34204b6 * Reorganize source code in preparation to move into aspnet/Extensions Prior to reorganization, this source code was found in https://github.com/aspnet/DependencyInjection/tree/7a283947c231b6585c8ac95e653950b660f3da96 Commit migrated from dotnet/extensions@689c4a8 * Reorganize source code in preparation to move into aspnet/Extensions Prior to reorganization, this source code was found in https://github.com/aspnet/DependencyInjection/tree/12eef5e86e965b9611221c72c169002e6f3038ee Commit migrated from dotnet/extensions@04e957b * Reorganize source code in preparation to move into aspnet/Extensions Prior to reorganization, this source code was found in https://github.com/aspnet/DependencyInjection/tree/d77b090567a1e6ad9a5bb5fd05f4bdcf281d4185 Commit migrated from dotnet/extensions@9a4c61b * Reorganize source code in preparation to move into aspnet/Extensions Prior to reorganization, this source code was found in https://github.com/aspnet/Logging/tree/f7d8e4e0537eaab54dcf28c2b148b82688a3d62d Commit migrated from dotnet/extensions@f3cd14a * Reorganize source code in preparation to move into aspnet/Extensions Prior to reorganization, this source code was found in https://github.com/aspnet/HttpClientFactory/tree/cf7cf83ee869ed50a41852f5e880d073386b7fe7 Commit migrated from dotnet/extensions@c38f9c1 * Use the SharedSourceRoot variable in project files Commit migrated from dotnet/extensions@888bcba * Allow caching of IEnumerable services (dotnet/extensions#575) Commit migrated from dotnet/extensions@c89a5b5 * Reduce event source logger allocations (dotnet/extensions#870) Commit migrated from dotnet/extensions@091ee13 * Use Arcade (dotnet/extensions#586) Use arcade Commit migrated from dotnet/extensions@f045899 * Cleanup conversion to Arcade (dotnet/extensions#1014) * Remove obsolete targets, properties, and scripts * Replace IsProductComponent with IsShipping * Undo bad merge to version.props * Update documentation, and put workarounds into a common file * Replace usages of RepositoryRoot with RepoRoot * Remove API baselines * Remove unnecessary restore feeds and split workarounds into two files * Enable PR checks on all branches, and disable autocancel Commit migrated from dotnet/extensions@f41cfde * Shrink StringValues (dotnet/extensions#1283) Commit migrated from dotnet/extensions@2f8e1fb * Disable transitive project references in test projects (dotnet/extensions#1834) Commit migrated from dotnet/extensions@e7d5bea * Fix HTTP client benchmarks Commit migrated from dotnet/extensions@8f0f7fa * Add typed client creation benchmark Commit migrated from dotnet/extensions@20ce03a * Support netcoreapp3.1 TFM (dotnet/extensions#2336) * Support netcoreapp3.1 TFM * Unpin SDK for source build * Update to preview1 branding Commit migrated from dotnet/extensions@32cc816 * Normalize all file headers to the expected Apache 2.0 license Commit migrated from dotnet/extensions@cec6e75 * Switch file headers to the MIT license Commit migrated from dotnet/extensions@321a30c * Moves Microsoft.Extensions.* perf tests over * Using the Open key to fully sign assembly - Needed to later get InternalsVisibleTo on DI * Apply suggestions from code review Make batch commit using suggestions in PR feedback Co-authored-by: Adam Sitnik <adam.sitnik@gmail.com> * Fix compile + other feedback * Apply suggestions from code review Co-authored-by: Nate McMaster <nate.mcmaster@microsoft.com> Co-authored-by: Pavel Krymets <pavel@krymets.com> Co-authored-by: Ryan Brandenburg <rybrande@microsoft.com> Co-authored-by: Nate McMaster <natemcmaster@users.noreply.github.com> Co-authored-by: Ben Adams <thundercat@illyriad.co.uk> Co-authored-by: Ryan Nowak <rynowak@microsoft.com> Co-authored-by: John Luo <johluo@microsoft.com> Co-authored-by: Sam Harwell <Sam.Harwell@microsoft.com> Co-authored-by: Adam Sitnik <adam.sitnik@gmail.com>
Use a single field to shrink by 8 bytes; shrinking ResponseHeaders by 272 bytes and RequestHeaders by 352 bytes; or 624 bytes total (e.g. per connection).
Before

After

Resolves #1290