-
Notifications
You must be signed in to change notification settings - Fork 4.9k
Optimize SqlClient primitive type writes #34048
Conversation
…ble path with fallback to array on continuation add WriteByteSpan and WriteByteArray public methods
… which avoid byte array allocation in favour of span
| { | ||
| byte[] tempArray = new byte[len]; | ||
| Span<byte> copyTempTo = tempArray.AsSpan(); | ||
| ReadOnlySpan<byte> copyTempFrom = b.Slice(remainder, len); |
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.
I am confused. Why do you need b.Slice again here? b.Slice(remainder) was already called on line 3062
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.
Good question. The len needs to be there so that we only copy data not empty buffer in the case where a small part of an array is used (pool rental for example). The remainder should be changed to 0 though. I've changed it and I'm re-running the test suites.
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.
manual and efcore tests all pass with the push from earlier today.
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.
Is this testing status for Windows only or both Windows and Linux?
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.
windows/native, this bit is shared though. I can force it into managed mode and test that way as well.
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.
OK. I will run the Unix validations.
|
@dotnet-bot Test Windows x86 Release Build Please 01:00 != 00:00:00, dn:(UTC+01:00) Casablanca, sn:(UTC+01:00) Casablanca |
| { | ||
| byte[] tempArray = new byte[len]; | ||
| Span<byte> copyTempTo = tempArray.AsSpan(); | ||
| ReadOnlySpan<byte> copyTempFrom = b.Slice(0, len); |
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.
Can't you just get rid of the call at 3048. It doesn't seem to be doing anything useful. And call b.Slice(remainder, len) like you were doing earlier, at this location? if ( array == null) is the only location where you are going to get the rest of the content of b
Does this make sense ?
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.
No, there is no guarantee that the WritePacket call will return a task so it's possible to go around the loop without allocating the array. This was a problem that occurred with one of the SplitPacket tests that was pointed out on the original PR.
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.
OK, now I understand. In that case, what is the effect of just doing a b = b.Slice(remainder, len) at 3048 and eliminate this slicing at 3066. Would that work? Then this line would read ReadOnlySpan<byte> copyTempFrom = b;
saurabh500
left a comment
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.
Merge pending product team validations.
|
@dotnet-bot Test Packaging All Configurations x64 Debug Build please |
|
I am facing some issues with EF tests failure with this change. I don't think this PR caused it but I wanna be sure. |
|
Managed or native? and what are you seeing fail? |
|
LGTM. Tested Manual Tests on Ubuntu, |
* change public WriteArrayBytes to private WriteBytes and add span capable path with fallback to array on continuation add WriteByteSpan and WriteByteArray public methods * add netcoreapp specific implementations of WriteFloat and WriteDouble which avoid byte array allocation in favour of span * fixup array compy slice to not use remainder as start since it has already advanced * remove additional span Commit migrated from dotnet/corefx@245d532
When writing some primitive types to the tds packet stream small arrays are allocated and passed to the WriteByteArray function. I have changed WriteByteArray to WriteBytes and added a span parameter so that either a span or an array can be passed in (but not both, the priority is explained in the comments). The function will attempt to write using only a span unless it encounters an end of packet and needs to use an async continuation, in that case it will allocate an array and copy the remainder of the span into it. For primitive types this will rarely be needed.
These changes can be used to allow the new BitConverter.TryWriteBytes overload with stackalloced buffers to remove memory allocations for writing of 16 and 32 bit reals. This can be extended to guids at a later time.
This PR was split from #32811 and into smaller commits for easier review. It has passed the manual and efcore tests in native mode, the tests cannot be successfully run in managed mode due to #33930 . Performance improvements for this and related PR's are in the original discussion.
/cc @keeratsingh @afsanehr @saurabh500 @David-Engel