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

Use one SequenceReader+Rewind rather than 2 SequenceReaders #8076

Merged
merged 1 commit into from
Jun 7, 2019

Conversation

benaadams
Copy link
Member

@benaadams benaadams commented Mar 1, 2019

SequenceReader is a very chunky struct; so taking a copy of it to rewind 2 chars in an uncommon case is expensive as it forces stack reservation and zeroing for the copy:

Also move the exception handling to the outer method, and clean up the loop

                Method |     Mean |    Error |   StdDev |        Op/s | Scaled |
 --------------------- |---------:|---------:|---------:|------------:|-------:|
- PlaintextTechEmpower | 310.4 ns | 1.301 ns | 1.153 ns | 3,221,411.1 |   1.00 |
+ PlaintextTechEmpower | 271.8 ns | 2.267 ns | 2.121 ns | 3,679,437.9 |   1.00 |
-           LiveAspNet | 526.9 ns | 2.322 ns | 1.939 ns | 1,897,874.1 |   1.70 |
+           LiveAspNet | 454.3 ns | 2.496 ns | 2.212 ns | 2,201,384.0 |   1.55 |
-              Unicode | 687.7 ns | 3.629 ns | 3.217 ns | 1,454,153.2 |   2.22 |
+              Unicode | 614.2 ns | 3.414 ns | 3.193 ns | 1,628,024.1 |   2.09 |

(Some PR changes highlighted by diff)

; Assembly listing for method HttpParser`1:ParseHeaders(struct,byref):bool:this
-; Lcl frame size = 1032
+; Lcl frame size = 120

-mov      ecx, 226
+mov      ecx, 14
 xor      rax, rax
 rep stosd 

Zeroing in the common path to set it to default(SequenceReader<byte>)

-    call     SequenceReader`1:GetNextSpan():this
-
-G_M20071_IG23:
-    xor      rcx, rcx
-    lea      rax, bword ptr [rbp-108H]
-    vxorps   xmm0, xmm0
-    vmovdqu  qword ptr [rax], xmm0
-    vmovdqu  qword ptr [rax+16], xmm0
-    vmovdqu  qword ptr [rax+32], xmm0
-    vmovdqu  qword ptr [rax+48], xmm0
-    vmovdqu  qword ptr [rax+64], xmm0
-    vmovdqu  qword ptr [rax+80], xmm0
-    mov      qword ptr [rax+96], rcx
-    mov      dword ptr [rbp-10CH], ecx
-
-G_M20071_IG24:
-    cmp      byte  ptr [rbp-8CH], 0
-    je       G_M20071_IG190

+    call     SequenceReader`1:GetNextSpan():this
+
+G_M20042_IG23:
+    xor      ecx, ecx
+    mov      dword ptr [rbp-A4H], ecx
+
+G_M20042_IG24:
+    cmp      byte  ptr [rbp-8CH], 0
+    je       G_M20042_IG204

/cc @JeremyKuhne @davidfowl

@benaadams
Copy link
Member Author

Rewind is expensive; trying something else

@benaadams benaadams changed the title Use one SequenceReader+Rewind rather than 2 SequenceReaders [wip] Use one SequenceReader+Rewind rather than 2 SequenceReaders Mar 1, 2019
@analogrelay
Copy link
Contributor

analogrelay commented Mar 1, 2019

@benaadams Btw, rebase on master when you can. You've got some flaky tests failing in your PR and I think we've knocked them down in master now :).

Edit: I think re-running will get the changes, so I'm triggering helix again.

@analogrelay
Copy link
Contributor

/azp run AspNetCore-helix-test

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@JeremyKuhne
Copy link
Member

@benaadams This change: aspnet/KestrelHttpServer#3068 has a revamp of this code which in micro benchmarks was much much faster. Do you have any interest in getting that back up / further refining it? It would be good for measuring the impact of other possible reader changes.

@benaadams
Copy link
Member Author

@JeremyKuhne If I made the parser "safe"; what would @blowdart think of me 😱

Will take a look 😸

@benaadams
Copy link
Member Author

made the parser "safe" ...

Bit of a rabbit hole, probably should be done as its own PR

@JeremyKuhne
Copy link
Member

Bit of a rabbit hole, probably should be done as its own PR

Sorry, I wasn't suggesting that it be done in this PR. It does, however, cross over this same method and make this change moot (I think). I'll get that one going again if you don't want to, just thought I'd point it out and offer it to you as you're much more focused on this right now than I am. :) Just let me know.

@benaadams benaadams changed the title [wip] Use one SequenceReader+Rewind rather than 2 SequenceReaders Use one SequenceReader+Rewind rather than 2 SequenceReaders Mar 2, 2019
@benaadams
Copy link
Member Author

benaadams commented Mar 2, 2019

                Method |     Mean |    Error |   StdDev |        Op/s | Scaled |
 --------------------- |---------:|---------:|---------:|------------:|-------:|
- PlaintextTechEmpower | 310.4 ns | 1.301 ns | 1.153 ns | 3,221,411.1 |   1.00 |
+ PlaintextTechEmpower | 271.8 ns | 2.267 ns | 2.121 ns | 3,679,437.9 |   1.00 |
-           LiveAspNet | 526.9 ns | 2.322 ns | 1.939 ns | 1,897,874.1 |   1.70 |
+           LiveAspNet | 454.3 ns | 2.496 ns | 2.212 ns | 2,201,384.0 |   1.55 |
-              Unicode | 687.7 ns | 3.629 ns | 3.217 ns | 1,454,153.2 |   2.22 |
+              Unicode | 614.2 ns | 3.414 ns | 3.193 ns | 1,628,024.1 |   2.09 |

@benaadams
Copy link
Member Author

Helix Win10 error

System.IO.IOException : The process cannot access the file '...' because it is being used by another process.

Failed   Microsoft.AspNetCore.Authentication.DataHandler.SecureDataFormatTests.UnprotectWithDifferentPurposeFails
Error Message:
 System.Security.Cryptography.CryptographicException : An error occurred while trying to encrypt the provided data. Refer to the inner exception for more information.
---- System.IO.IOException : The process cannot access the file 'C:\Users\runner\AppData\Local\ASP.NET\DataProtection-Keys\key-7ec42fe5-23f5-4bc1-ad2c-85ba5ff21a6e.xml' because it is being used by another process.
Stack Trace:
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.Protect(Byte[] plaintext) in /_/src/DataProtection/DataProtection/src/KeyManagement/KeyRingBasedDataProtector.cs:line 141
   at Microsoft.AspNetCore.Authentication.SecureDataFormat`1.Protect(TData data, String purpose) in /_/src/Security/Authentication/Core/src/SecureDataFormat.cs:line 34
   at Microsoft.AspNetCore.Authentication.DataHandler.SecureDataFormatTests.UnprotectWithDifferentPurposeFails() in /_/src/Security/Authentication/test/SecureDataFormatTests.cs:line 59
----- Inner Stack Trace -----
   at System.IO.FileStream.ValidateFileHandle(SafeFileHandle fileHandle)
   at System.IO.FileStream.CreateFileOpenHandle(FileMode mode, FileShare share, FileOptions options)
   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options)
   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share)
   at System.IO.File.OpenRead(String path)
   at Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository.ReadElementFromFile(String fullPath) in /_/src/DataProtection/DataProtection/src/Repositories/FileSystemXmlRepository.cs:line 102
   at Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository.GetAllElementsCore()+MoveNext() in /_/src/DataProtection/DataProtection/src/Repositories/FileSystemXmlRepository.cs:line 83
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository.GetAllElements() in /_/src/DataProtection/DataProtection/src/Repositories/FileSystemXmlRepository.cs:line 68
   at Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager.GetAllKeys() in /_/src/DataProtection/DataProtection/src/KeyManagement/XmlKeyManager.cs:line 152
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider.CreateCacheableKeyRingCore(DateTimeOffset now, IKey keyJustAdded) in /_/src/DataProtection/DataProtection/src/KeyManagement/KeyRingProvider.cs:line 57
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider.CreateCacheableKeyRingCore(DateTimeOffset now, IKey keyJustAdded) in /_/src/DataProtection/DataProtection/src/KeyManagement/KeyRingProvider.cs:line 103
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider.Microsoft.AspNetCore.DataProtection.KeyManagement.Internal.ICacheableKeyRingProvider.GetCacheableKeyRing(DateTimeOffset now) in /_/src/DataProtection/DataProtection/src/KeyManagement/KeyRingProvider.cs:line 254
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider.GetCurrentKeyRingCore(DateTime utcNow) in /_/src/DataProtection/DataProtection/src/KeyManagement/KeyRingProvider.cs:line 186
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider.GetCurrentKeyRing() in /_/src/DataProtection/DataProtection/src/KeyManagement/KeyRingProvider.cs:line 142
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.Protect(Byte[] plaintext) in /_/src/DataProtection/DataProtection/src/KeyManagement/KeyRingBasedDataProtector.cs:line 102

@analogrelay
Copy link
Contributor

analogrelay commented Mar 3, 2019

Yep, that's https://github.com/aspnet/AspNetCore/issues/7366. Applying ye olde skip attribute ;P

@analogrelay
Copy link
Contributor

#8129 should unblock this

@benaadams
Copy link
Member Author

Rebased

@analogrelay analogrelay added this to the 3.0.0-preview5 milestone Apr 8, 2019
@benaadams
Copy link
Member Author

Rebased

@analogrelay
Copy link
Contributor

Moving this to preview 6. FYI, this should not be merged until we've got confirmation that the branch is open for preview 6 changes. We've got a tight timeline for preview 5 and are starting to lock down now :).

@benaadams
Copy link
Member Author

Rebased

@benaadams
Copy link
Member Author

Rebased

@analogrelay
Copy link
Contributor

@davidfowl @Tratcher @jkotalik @halter73 Where do we stand (on our side) as far as merging this? Preview 6 is locking soon and we already punted this from preview 5 :).

@benaadams
Copy link
Member Author

Rebased

@benaadams
Copy link
Member Author

Rebased

@benaadams
Copy link
Member Author

Rebased

@analogrelay
Copy link
Contributor

Ping @Tratcher @jkotalik @halter73 - we should get this reviewed instead of just making @benaadams rebase it down the road ;P

Copy link
Member

@halter73 halter73 left a comment

Choose a reason for hiding this comment

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

This looks solid to me. I think we're ready to merge. @davidfowl do you agree?

}

return result;
bool TrimAndTakeMessageHeaders(in ReadOnlySequence<byte> buffer, bool trailers, out SequencePosition consumed, out SequencePosition examined)
Copy link
Member

Choose a reason for hiding this comment

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

The redundancy of TakeMessageHeaders and TrimAndTakeMessageHeaders is one thing I don't love, but I understand doing this if necessary to optimize the fast path.

@jkotalik jkotalik merged commit f10680a into dotnet:master Jun 7, 2019
@jkotalik
Copy link
Contributor

jkotalik commented Jun 7, 2019

Thanks @benaadams

@benaadams benaadams deleted the Parser branch June 7, 2019 20:25
@amcasey amcasey added area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions and removed area-runtime labels Jun 6, 2023
@github-actions github-actions bot locked and limited conversation to collaborators Dec 8, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants