Skip to content

Commit

Permalink
Add tests and improve binary XmlDictionaryReader performance (#73332)
Browse files Browse the repository at this point in the history
* Read primitive types more efficient

* Allow stream to read more than minimum number of required bytes

* Remove pinning and pointer code from array reads

* Remove bounds checks from remaing array reads

* remove extra unchecked

* cleanup code

* Start adding tests

* Add tests for binary XmlDictionaryReader

* cleanup

* revert back to old byte read

* add test for arrays using "ref" enumeration

* add guid test

* Try to read while arrays from stream before processing

* Write guid arrays as memory on LittleEndian platforms

* Update tests to be independent of byte order

* FIx bugs introduced in #71752
* Add missing Advance to prevent corruption of reader
* Correctly read decimal values
  • Loading branch information
Daniel-Svensson committed Aug 15, 2022
1 parent 00f34fb commit 5dbdde9
Show file tree
Hide file tree
Showing 6 changed files with 405 additions and 210 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;

namespace System.Xml
Expand Down Expand Up @@ -1250,10 +1251,7 @@ private unsafe int ReadArray(bool[] array, int offset, int count)
{
CheckArray(array, offset, count);
int actual = Math.Min(count, _arrayCount);
fixed (bool* items = &array[offset])
{
BufferReader.UnsafeReadArray((byte*)items, (byte*)&items[actual]);
}
BufferReader.ReadRawArrayBytes(array.AsSpan(offset, actual));
SkipArrayElements(actual);
return actual;
}
Expand All @@ -1276,10 +1274,7 @@ private unsafe int ReadArray(short[] array, int offset, int count)
{
CheckArray(array, offset, count);
int actual = Math.Min(count, _arrayCount);
fixed (short* items = &array[offset])
{
BufferReader.UnsafeReadArray((byte*)items, (byte*)&items[actual]);
}
BufferReader.ReadRawArrayBytes(array.AsSpan(offset, actual));
SkipArrayElements(actual);
return actual;
}
Expand All @@ -1302,10 +1297,7 @@ private unsafe int ReadArray(int[] array, int offset, int count)
{
CheckArray(array, offset, count);
int actual = Math.Min(count, _arrayCount);
fixed (int* items = &array[offset])
{
BufferReader.UnsafeReadArray((byte*)items, (byte*)&items[actual]);
}
BufferReader.ReadRawArrayBytes(array.AsSpan(offset, actual));
SkipArrayElements(actual);
return actual;
}
Expand All @@ -1328,10 +1320,7 @@ private unsafe int ReadArray(long[] array, int offset, int count)
{
CheckArray(array, offset, count);
int actual = Math.Min(count, _arrayCount);
fixed (long* items = &array[offset])
{
BufferReader.UnsafeReadArray((byte*)items, (byte*)&items[actual]);
}
BufferReader.ReadRawArrayBytes(array.AsSpan(offset, actual));
SkipArrayElements(actual);
return actual;
}
Expand All @@ -1354,10 +1343,7 @@ private unsafe int ReadArray(float[] array, int offset, int count)
{
CheckArray(array, offset, count);
int actual = Math.Min(count, _arrayCount);
fixed (float* items = &array[offset])
{
BufferReader.UnsafeReadArray((byte*)items, (byte*)&items[actual]);
}
BufferReader.ReadRawArrayBytes(array.AsSpan(offset, actual));
SkipArrayElements(actual);
return actual;
}
Expand All @@ -1380,10 +1366,7 @@ private unsafe int ReadArray(double[] array, int offset, int count)
{
CheckArray(array, offset, count);
int actual = Math.Min(count, _arrayCount);
fixed (double* items = &array[offset])
{
BufferReader.UnsafeReadArray((byte*)items, (byte*)&items[actual]);
}
BufferReader.ReadRawArrayBytes(array.AsSpan(offset, actual));
SkipArrayElements(actual);
return actual;
}
Expand All @@ -1406,10 +1389,7 @@ private unsafe int ReadArray(decimal[] array, int offset, int count)
{
CheckArray(array, offset, count);
int actual = Math.Min(count, _arrayCount);
fixed (decimal* items = &array[offset])
{
BufferReader.UnsafeReadArray((byte*)items, (byte*)&items[actual]);
}
BufferReader.ReadRawArrayBytes(array.AsSpan(offset, actual));
SkipArrayElements(actual);
return actual;
}
Expand All @@ -1433,9 +1413,11 @@ private int ReadArray(DateTime[] array, int offset, int count)
{
CheckArray(array, offset, count);
int actual = Math.Min(count, _arrayCount);
for (int i = 0; i < actual; i++)
// Try to read in whole array, but don't fail if not possible
BufferReader.GetBuffer(actual * ValueHandleLength.DateTime, out _, out _);
foreach (ref DateTime item in array.AsSpan(offset, actual))
{
array[offset + i] = BufferReader.ReadDateTime();
item = BufferReader.ReadDateTime();
}
SkipArrayElements(actual);
return actual;
Expand All @@ -1460,9 +1442,18 @@ private int ReadArray(Guid[] array, int offset, int count)
{
CheckArray(array, offset, count);
int actual = Math.Min(count, _arrayCount);
for (int i = 0; i < actual; i++)
if (BitConverter.IsLittleEndian)
{
array[offset + i] = BufferReader.ReadGuid();
BufferReader.ReadRawArrayBytes(array.AsSpan(offset, actual));
}
else
{
// Try to read in whole array, but don't fail if not possible
BufferReader.GetBuffer(actual * ValueHandleLength.Guid, out _, out _);
foreach (ref Guid item in array.AsSpan(offset, actual))
{
item = BufferReader.ReadGuid();
}
}
SkipArrayElements(actual);
return actual;
Expand All @@ -1487,9 +1478,11 @@ private int ReadArray(TimeSpan[] array, int offset, int count)
{
CheckArray(array, offset, count);
int actual = Math.Min(count, _arrayCount);
for (int i = 0; i < actual; i++)
// Try to read in whole array, but don't fail if not possible
BufferReader.GetBuffer(actual * ValueHandleLength.TimeSpan, out _, out _);
foreach (ref TimeSpan item in array.AsSpan(offset, actual))
{
array[offset + i] = BufferReader.ReadTimeSpan();
item = BufferReader.ReadTimeSpan();
}
SkipArrayElements(actual);
return actual;
Expand Down
Loading

0 comments on commit 5dbdde9

Please sign in to comment.