Skip to content

Commit

Permalink
Fix Stream.ReadAtLeast perf regression in DataContractSerializer
Browse files Browse the repository at this point in the history
dotnet#69272 changed DCS to no longer call Stream.Read inside a loop, but instead call the new ReadAtLeast method. ReadAtLeast only takes a Span<byte>, and not a byte[]. This caused a regression because the internal encoding stream wrapper classes don't override Read(Span<byte>), so the base implementation is used. The base implementation is slower because it needs to rent a byte[] from the pool, and do 2 copies.

Overriding Read(Span<byte>) on the internal encoding stream wrapper classes allows ReadAtLeast to be just as fast.

Fix dotnet#69730
  • Loading branch information
eerhardt committed May 26, 2022
1 parent 3436758 commit 69c3475
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -174,15 +174,18 @@ public override void Flush()
_stream.Flush();
}

public override int Read(byte[] buffer, int offset, int count)
public override int Read(byte[] buffer, int offset, int count) =>
Read(new Span<byte>(buffer, offset, count));

public override int Read(Span<byte> buffer)
{
try
{
if (_byteCount == 0)
{
if (_encodingCode == SupportedEncoding.UTF8)
{
return _stream.Read(buffer, offset, count);
return _stream.Read(buffer);
}

Debug.Assert(_bytes != null);
Expand All @@ -206,11 +209,13 @@ public override int Read(byte[] buffer, int offset, int count)
}

// Give them bytes
int count = buffer.Length;
if (_byteCount < count)
{
count = _byteCount;
}
Buffer.BlockCopy(_bytes!, _byteOffset, buffer, offset, count);

_bytes.AsSpan(_byteOffset, count).CopyTo(buffer);
_byteOffset += count;
_byteCount -= count;
return count;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -593,14 +593,17 @@ public override int ReadByte()
return _byteBuffer[0];
}

public override int Read(byte[] buffer, int offset, int count)
public override int Read(byte[] buffer, int offset, int count) =>
Read(new Span<byte>(buffer, offset, count));

public override int Read(Span<byte> buffer)
{
try
{
if (_byteCount == 0)
{
if (_encodingCode == SupportedEncoding.UTF8)
return _stream.Read(buffer, offset, count);
return _stream.Read(buffer);

Debug.Assert(_bytes != null);
Debug.Assert(_chars != null);
Expand All @@ -622,9 +625,11 @@ public override int Read(byte[] buffer, int offset, int count)
}

// Give them bytes
int count = buffer.Length;
if (_byteCount < count)
count = _byteCount;
Buffer.BlockCopy(_bytes!, _byteOffset, buffer, offset, count);

_bytes.AsSpan(_byteOffset, count).CopyTo(buffer);
_byteOffset += count;
_byteCount -= count;
return count;
Expand Down

0 comments on commit 69c3475

Please sign in to comment.