-
Notifications
You must be signed in to change notification settings - Fork 4.9k
Change SqlClient to use strongly typed packet and session handles #33155
Conversation
rename SNIPacket to SNIPacketHandle add PacketHandle type field and asserttions on native consumer methods
add SessionHandle strong type
src/System.Data.SqlClient/src/Interop/SNINativeMethodWrapper.Windows.cs
Outdated
Show resolved
Hide resolved
@@ -98,14 +98,14 @@ public void Allocate(int capacity) | |||
{ | |||
if (_isBufferFromArrayPool) | |||
{ | |||
_arrayPool.Return(_data); | |||
ArrayPool<byte>.Shared.Return(_data); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the default shared pool is being used it seems wasteful to carry around the extra field referring to it. The default pool can also be devirtualized by the jit possibly making the calls slightly faster.
I did wonder if it might be worth having an sql specific pool for packet buffers but considered the advice warning of creating too many pools and decided to err on the side of caution.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The default pool can also be devirtualized by the jit possibly making the calls slightly faster.
Yep, when referred to directly via ArrayPool<byte>.Shared
dotnet/coreclr#20637
src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIPacket.cs
Outdated
Show resolved
Hide resolved
src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParserStateObject.cs
Outdated
Show resolved
Hide resolved
oh no not this guy again !!! 😄 |
Do you have any measurements for the impact of these changes? |
I haven't done any direct measurements because these changes are on a different branch to my other perf changes in #32811. While I was working on the other PR I got to the point where the allocations were all putting values into objects in the parameters (unavoidable) and the IntPtr boxing for the various methods changed here. So logically it should roughly half the GC frequency seen in the graphs posted on the other PR. Now there are deeper concerns. I'm changing an object which is a single reference in size to a struct 4 times the size which is going to have some impact. When I looked at the uses of the new types all of them were used with a small number of other parameters so while there is more data present now there should be enough registers to allow them to be passed quickly or by reference. Doing some microbenching I could try to identify if it is faster to force references with `in' modifiers but realistically the cpu time is spent waiting on sql server and going to that low level is over optimising at this time. In performance terms it will be a memory net win. It may have a small throughput degredation but that is likely to be balanced by the lack of boxing instructions and memory operations related to it, it might even be a net win on that side. |
Ok, got some profile results (still can't get BDN to co-operate) they show that there is a minor improvement in both memory and speed. This is a slightly improved version of the benchmark written for Less GC peaks and probably because of that ~13% faster. |
@dotnet-bot Test Linux x64 Release Build |
EFCore tests passed on this change. |
Nudge. |
@dotnet-bot test Windows x64 Debug Build |
These changes remove constant boxing of session and packet handles which are IntPtr when using the native implementation of
TdsParserStateObject
(native is used in windows non-uap builds) which improves memory performance. Making these changes also allows assertion of the handle types in debug builds which adds safety and testability.To do this I have had to add in a project DefineConstant called
snidll
to allow some fields to be omitted where the native implementation is not included, while I like the current configuration with extremely minimal #define usage I considered this and think the additional type safety offered is worth the new constant. I have also renamed a couple of types to clarify which types are used in which implementations.The changes also include some changes to the ManualTests to add conditional facts on Udt and ServiceBroker reliant test cases so they won't run if the resources required aren't present or enabled. This assumes that a full test run with these available should not skip any tests. These changes were needed to allow me to run the manual tests locally without getting large numbers of errors to try and pick real problems out of.
please review, test, comment, say "oh no not this guy again" as usual 😁
/cc @keeratsingh @afsanehr @saurabh500 @David-Engel