in src/Microsoft.Diagnostics.Runtime/Windows/ArrayPoolBasedCacheEntry.cs [50:117]
protected override (byte[] Data, ulong DataExtent) GetPageDataAtOffset(ulong pageAlignedOffset)
{
// NOTE: The caller ensures this method is not called concurrently
if (HeapSegmentCacheEventSource.Instance.IsEnabled())
HeapSegmentCacheEventSource.Instance.PageInDataStart((long)(_segmentData.VirtualAddress + pageAlignedOffset), EntryPageSize);
uint readSize;
if (pageAlignedOffset + EntryPageSize <= _segmentData.Size)
{
readSize = EntryPageSize;
}
else
{
readSize = (uint)(_segmentData.Size - pageAlignedOffset);
}
bool pageInFailed = false;
using MemoryMappedViewAccessor view = _mappedFile.CreateViewAccessor((long)_segmentData.FileOffset + (long)pageAlignedOffset, size: readSize, MemoryMappedFileAccess.Read);
try
{
ulong viewOffset = (ulong)view.PointerOffset;
unsafe
{
byte* pViewLoc = null;
try
{
view.SafeMemoryMappedViewHandle.AcquirePointer(ref pViewLoc);
if (pViewLoc == null)
throw new InvalidOperationException("Failed to acquire the underlying memory mapped view pointer. This is unexpected");
pViewLoc += viewOffset;
// Grab a shared buffer to use if there is one, or create one for the pool
byte[] data = ArrayPool<byte>.Shared.Rent((int)readSize);
// NOTE: This looks sightly ridiculous but view.ReadArray<T> is TERRIBLE for primitive types like byte, it calls Marshal.PtrToStructure for EVERY item in the
// array, the overhead of that call SWAMPS all access costs to the memory, and it is called N times (where N here is 4k), whereas memcpy just blasts the bits
// from one location to the other, it is literally a couple of orders of magnitude faster.
fixed (byte* pData = data)
{
CacheNativeMethods.Memory.memcpy(new UIntPtr(pData), new UIntPtr(pViewLoc), new UIntPtr(readSize));
}
return (data, readSize);
}
finally
{
if (pViewLoc != null)
view.SafeMemoryMappedViewHandle.ReleasePointer();
}
}
}
catch (Exception ex)
{
if (HeapSegmentCacheEventSource.Instance.IsEnabled())
HeapSegmentCacheEventSource.Instance.PageInDataFailed(ex.Message);
pageInFailed = true;
throw;
}
finally
{
if (!pageInFailed && HeapSegmentCacheEventSource.Instance.IsEnabled())
HeapSegmentCacheEventSource.Instance.PageInDataEnd((int)readSize);
}
}