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

Added Span support to Webencoders with direct encoding #338

Closed
wants to merge 8 commits into from
Closed

Added Span support to Webencoders with direct encoding #338

wants to merge 8 commits into from

Conversation

gfoidl
Copy link
Member

@gfoidl gfoidl commented Apr 16, 2018

Description

This PR is -- at least for me -- a better solution for https://github.com/aspnet/Home/issues/2966 than #334.
It is built on top of #334 (these commits are included in this PR, but squashed).

In #334 I didn't like the route data -> base64 -> url-chars-substitution, because it could be done in a direct way data -> base64Url. That PR was done that way, because the existing code was based on that route, and I interpreted https://github.com/aspnet/Home/issues/2966 that way.
I found some time to try the direct way, the results seem very good, and the code is cleaner.

The url chars substitution produced quite a lot of code, and encoding / decoding is done in O(2n).
In this PR the encoding / decoding is done in O(n), and no intermediate buffers are needed.
The encoding / decoding code is based on

Benchmarks

Results from Benchmark-Project

Baseline

See results in #334

This PR

BenchmarkDotNet=v0.10.11, OS=ubuntu 16.04
Processor=Intel Xeon CPU 2.60GHz, ProcessorCount=2
.NET Core SDK=2.1.300-preview3-008416
  [Host]     : .NET Core 2.1.0-preview2-26314-02 (Framework 4.6.26310.01), 64bit RyuJIT
  Job-BIURAA : .NET Core 2.1.0-preview2-26314-02 (Framework 4.6.26310.01), 64bit RyuJIT

Runtime=Core  Server=True  Toolchain=.NET Core 2.1  
RunStrategy=Throughput  
Method Mean Error StdDev Op/s Gen 0 Allocated
Base64UrlDecode_Data 724.8062 ns 2.1094 ns 1.9732 ns 1,379,679.1 0.0085 528 B
Base64UrlDecode_DataWithOffset 722.8460 ns 1.9752 ns 1.8476 ns 1,383,420.6 0.0084 528 B
Base64UrlDecode_Guid 87.1654 ns 0.4143 ns 0.3875 ns 11,472,439.7 0.0006 40 B
Base64UrlEncode_Data 1,014.2738 ns 7.3980 ns 6.9201 ns 985,927.1 0.0229 1360 B
Base64UrlEncode_DataWithOffset 1,049.5219 ns 7.4391 ns 6.9585 ns 952,814.8 0.0229 1360 B
Base64UrlEncode_Guid 96.5938 ns 0.3260 ns 0.3049 ns 10,352,631.6 0.0012 72 B
GetArraySizeRequiredToDecode 0.0474 ns 0.0049 ns 0.0045 ns 21,100,718,706.0 - 0 B
GetArraySizeRequiredToEncode 0.0000 ns 0.0000 ns 0.0000 ns Infinity - 0 B

Individual benchmarks

Project for this benchmarks

Decode Guid

BenchmarkDotNet=v0.10.13, OS=Windows 10 Redstone 3 [1709, Fall Creators Update] (10.0.16299.371)
Intel Core i7-7700HQ CPU 2.80GHz (Kaby Lake), 1 CPU, 8 logical cores and 4 physical cores
Frequency=2742187 Hz, Resolution=364.6724 ns, Timer=TSC
.NET Core SDK=2.1.300-preview3-008618
  [Host] : .NET Core 2.1.0-preview3-26411-06 (CoreCLR 4.6.26411.07, CoreFX 4.6.26411.06), 64bit RyuJIT
  Clr	 : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.2633.0
  Core	 : .NET Core 2.1.0-preview3-26411-06 (CoreCLR 4.6.26411.07, CoreFX 4.6.26411.06), 64bit RyuJIT

Method Job Runtime Mean Error StdDev Scaled ScaledSD Gen 0 Allocated
Default Clr Clr 144.07 ns 2.426 ns 2.1510 ns 1.00 0.00 0.0355 112 B
PR_334 Clr Clr 120.28 ns 1.893 ns 1.7703 ns 0.84 0.02 0.0126 40 B
New Clr Clr 64.49 ns 1.004 ns 0.9390 ns 0.45 0.01 0.0126 40 B
Default Core Core 161.53 ns 1.206 ns 1.0072 ns 1.00 0.00 0.0355 112 B
PR_334 Core Core 104.90 ns 2.161 ns 3.6103 ns 0.65 0.02 0.0126 40 B
New Core Core 52.92 ns 1.100 ns 1.1766 ns 0.33 0.01 0.0127 40 B

Decode Data

BenchmarkDotNet=v0.10.13, OS=Windows 10 Redstone 3 [1709, Fall Creators Update] (10.0.16299.371)
Intel Core i7-7700HQ CPU 2.80GHz (Kaby Lake), 1 CPU, 8 logical cores and 4 physical cores
Frequency=2742187 Hz, Resolution=364.6724 ns, Timer=TSC
.NET Core SDK=2.1.300-preview3-008618
  [Host] : .NET Core 2.1.0-preview3-26411-06 (CoreCLR 4.6.26411.07, CoreFX 4.6.26411.06), 64bit RyuJIT
  Clr	 : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.2633.0
  Core	 : .NET Core 2.1.0-preview3-26411-06 (CoreCLR 4.6.26411.07, CoreFX 4.6.26411.06), 64bit RyuJIT

Method Job Runtime DataSize Mean Error StdDev Scaled ScaledSD Gen 0 Allocated
Default Clr Clr 10 113.56 ns 2.3357 ns 4.4439 ns 1.00 0.00 0.0303 96 B
PR_334 Clr Clr 10 130.38 ns 2.6556 ns 2.4840 ns 1.15 0.05 0.0126 40 B
New Clr Clr 10 57.09 ns 1.0639 ns 0.8884 ns 0.50 0.02 0.0126 40 B
Default Core Core 10 132.83 ns 2.7128 ns 6.1785 ns 1.00 0.00 0.0303 96 B
PR_334 Core Core 10 83.82 ns 0.4884 ns 0.4569 ns 0.63 0.03 0.0126 40 B
New Core Core 10 44.06 ns 0.4275 ns 0.3790 ns 0.33 0.02 0.0127 40 B
Default Clr Clr 50 367.18 ns 3.2591 ns 3.0486 ns 1.00 0.00 0.0758 240 B
PR_334 Clr Clr 50 206.31 ns 3.3799 ns 3.1615 ns 0.56 0.01 0.0253 80 B
New Clr Clr 50 103.92 ns 1.4526 ns 1.2877 ns 0.28 0.00 0.0254 80 B
Default Core Core 50 352.06 ns 3.4024 ns 3.1826 ns 1.00 0.00 0.0758 240 B
PR_334 Core Core 50 120.36 ns 2.4488 ns 3.8841 ns 0.34 0.01 0.0253 80 B
New Core Core 50 96.80 ns 2.1195 ns 3.1067 ns 0.27 0.01 0.0254 80 B
Default Clr Clr 100 733.31 ns 14.2941 ns 15.8878 ns 1.00 0.00 0.1345 424 B
PR_334 Clr Clr 100 373.12 ns 7.4124 ns 13.5540 ns 0.51 0.02 0.0911 288 B
New Clr Clr 100 153.03 ns 3.0541 ns 3.6357 ns 0.21 0.01 0.0405 128 B
Default Core Core 100 645.58 ns 13.2485 ns 22.1353 ns 1.00 0.00 0.1345 424 B
PR_334 Core Core 100 237.82 ns 1.9677 ns 1.8406 ns 0.37 0.01 0.0405 128 B
New Core Core 100 158.39 ns 2.0021 ns 1.7748 ns 0.25 0.01 0.0405 128 B

Encode Guid

BenchmarkDotNet=v0.10.13, OS=Windows 10 Redstone 3 [1709, Fall Creators Update] (10.0.16299.371)
Intel Core i7-7700HQ CPU 2.80GHz (Kaby Lake), 1 CPU, 8 logical cores and 4 physical cores
Frequency=2742187 Hz, Resolution=364.6724 ns, Timer=TSC
.NET Core SDK=2.1.300-preview3-008618
  [Host] : .NET Core 2.1.0-preview3-26411-06 (CoreCLR 4.6.26411.07, CoreFX 4.6.26411.06), 64bit RyuJIT
  Clr	 : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.2633.0
  Core	 : .NET Core 2.1.0-preview3-26411-06 (CoreCLR 4.6.26411.07, CoreFX 4.6.26411.06), 64bit RyuJIT

Method Job Runtime Mean Error StdDev Scaled ScaledSD Gen 0 Allocated
Default Clr Clr 123.48 ns 2.4681 ns 5.2596 ns 1.00 0.00 0.0455 144 B
PR_334 Clr Clr 156.93 ns 2.3024 ns 2.0410 ns 1.27 0.06 0.0226 72 B
New Clr Clr 92.41 ns 1.8525 ns 1.7329 ns 0.75 0.03 0.0228 72 B
Default Core Core 110.69 ns 2.2966 ns 3.0659 ns 1.00 0.00 0.0457 144 B
PR_334 Core Core 81.40 ns 0.5706 ns 0.4455 ns 0.74 0.02 0.0228 72 B
New Core Core 63.56 ns 0.9141 ns 0.8550 ns 0.57 0.02 0.0228 72 B

Encode Data

BenchmarkDotNet=v0.10.13, OS=Windows 10 Redstone 3 [1709, Fall Creators Update] (10.0.16299.371)
Intel Core i7-7700HQ CPU 2.80GHz (Kaby Lake), 1 CPU, 8 logical cores and 4 physical cores
Frequency=2742187 Hz, Resolution=364.6724 ns, Timer=TSC
.NET Core SDK=2.1.300-preview3-008618
  [Host] : .NET Core 2.1.0-preview3-26411-06 (CoreCLR 4.6.26411.07, CoreFX 4.6.26411.06), 64bit RyuJIT
  Clr	 : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.2633.0
  Core	 : .NET Core 2.1.0-preview3-26411-06 (CoreCLR 4.6.26411.07, CoreFX 4.6.26411.06), 64bit RyuJIT

Method Job Runtime DataSize Mean Error StdDev Scaled Gen 0 Allocated
Default Clr Clr 10 88.40 ns 0.7236 ns 0.6769 ns 1.00 0.0355 112 B
PR_334 Clr Clr 10 134.56 ns 0.6604 ns 0.5514 ns 1.52 0.0176 56 B
New Clr Clr 10 83.58 ns 0.7490 ns 0.6639 ns 0.95 0.0178 56 B
Default Core Core 10 81.69 ns 0.4227 ns 0.3954 ns 1.00 0.0355 112 B
PR_334 Core Core 10 77.21 ns 0.6466 ns 0.5732 ns 0.95 0.0178 56 B
New Core Core 10 63.37 ns 0.3465 ns 0.3241 ns 0.78 0.0178 56 B
Default Clr Clr 50 264.01 ns 1.7501 ns 1.6370 ns 1.00 0.1016 320 B
PR_334 Clr Clr 50 253.22 ns 1.9782 ns 1.8504 ns 0.96 0.0505 160 B
New Clr Clr 50 136.01 ns 1.0058 ns 0.8916 ns 0.52 0.0508 160 B
Default Core Core 50 218.02 ns 1.1414 ns 1.0676 ns 1.00 0.1016 320 B
PR_334 Core Core 50 131.78 ns 0.8857 ns 0.7396 ns 0.60 0.0508 160 B
New Core Core 50 98.77 ns 0.4972 ns 0.4651 ns 0.45 0.0508 160 B
Default Clr Clr 100 471.31 ns 1.9779 ns 1.7534 ns 1.00 0.1879 592 B
PR_334 Clr Clr 100 443.90 ns 2.8687 ns 2.6834 ns 0.94 0.1879 592 B
New Clr Clr 100 215.07 ns 1.2431 ns 1.1019 ns 0.46 0.1881 592 B
Default Core Core 100 415.51 ns 3.1875 ns 2.9816 ns 1.00 0.1879 592 B
PR_334 Core Core 100 289.83 ns 1.7229 ns 1.4387 ns 0.70 0.0939 296 B
New Core Core 100 151.40 ns 1.8358 ns 1.7172 ns 0.36 0.0939 296 B

Copy link
Member Author

@gfoidl gfoidl left a comment

Choose a reason for hiding this comment

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

Notes for review

@@ -96,144 +172,185 @@ public static byte[] Base64UrlDecode(string input, int offset, int count)
/// </remarks>
public static byte[] Base64UrlDecode(string input, int offset, char[] buffer, int bufferOffset, int count)
Copy link
Member Author

Choose a reason for hiding this comment

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

buffer isn't needed, because there is no intermediate step input -> base64 (which would be in buffer).
This is OK according to the xml comment ("Content is not preserved.").

So the checks with / for buffer could be eliminated?!

@gfoidl
Copy link
Member Author

gfoidl commented Apr 23, 2018

Rebased due to conflict in Common.sln (Microsoft.AspNetCore.Analyzer.Testing.csproj added to dev, this PR adds Microsoft.Extensions.Internal.Benchmarks.csproj).

@ycrumeyrolle
Copy link

Seems to be related to dotnet/corefxlab#1808

@davidfowl
Copy link
Member

@gfoidl we didn't forget this. We should look at it early for 2.2 (right now).

@gfoidl
Copy link
Member Author

gfoidl commented Jun 18, 2018

Rebased due to

Conflicting files
Common.sln

The <StandardTestTfms> is netcoreapp2.2 + net461 (on win), but as the file will be added as source to "consumers" other target frameworks are masked in the source.
net461 as target for desktop.
netcoreapp2.0 so ArrayPool can be used.
netcoreapp2.1 for string.Create
netcoreapp2.2 for the current tfm (no other enhanced features used over netcoreapp2.1).
@@ -251,7 +251,8 @@ public static unsafe string Base64UrlEncode(ReadOnlySpan<byte> data)

var base64Len = GetBufferSizeRequiredToBase64Encode(data.Length, out int numPaddingChars);
var base64UrlLen = base64Len - numPaddingChars;
#if NETCOREAPP2_1

#if NETCOREAPP2_2 || NETCOREAPP2_1
Copy link
Member Author

Choose a reason for hiding this comment

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

With dotnet/sdk#1813 this could be written cleaner.

@davidfowl
Copy link
Member

@gfoidl can you clean up the inline if defs? Maybe splitting the files would be better and clearer to read,

@gfoidl
Copy link
Member Author

gfoidl commented Jun 20, 2018

splitting the files

You mean something like WebEncoders.netcoreapp2_2.cs and so on?
Does this play well with the source-packaging of this code-file?

I would just duplicate the methods, and attach the if def around them, so it's easiert to read. OK?

@natemcmaster natemcmaster changed the base branch from dev to master July 2, 2018 17:44
@mkArtakMSFT
Copy link
Member

@pakrym, @davidfowl this seems to be still waiting for your reviews.

@davidfowl
Copy link
Member

@gfoidl Sorry I dropped the ball on this one, after much consideration we won't be taking it, but we'll be taking the other improvements to StringSegment. Thanks again and very sorry for the lack of attention here.

@davidfowl davidfowl closed this Nov 3, 2018
@gfoidl
Copy link
Member Author

gfoidl commented Nov 3, 2018

@davidfowl no problem, that's part of the game 😉

I'd like to say thank you too, as I learned quite a lot with these PRs -- escepially for the then new type Span.

@gfoidl gfoidl deleted the webencoders-direct-encode branch November 3, 2018 11:12
@gfoidl
Copy link
Member Author

gfoidl commented Nov 27, 2018

As info if anyone seeks a base64Url encoder / decoder and lands here: in https://github.com/gfoidl/Base64 I've made a library for this and put it on steroids (aka simd).

Right now it's in "preview" state, as hardware intrinsics in .NET Core 3.0 are also in preview state.

@davidfowl
Copy link
Member

@gfoidl nice! cc @GrabYourPitchforks

natemcmaster referenced this pull request in natemcmaster/Extensions Dec 4, 2018
Reference `Entropy` localization samples
@ghost ghost locked as resolved and limited conversation to collaborators May 30, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants