Skip to content

Commit

Permalink
Speed up data dehydration (#79209)
Browse files Browse the repository at this point in the history
Now that we switched everything we wanted to switch to dehydrated data, I redid startup measurements.

I used a 30 MB app that doesn't actually do anything useful with those megabytes and just exits (to get a lot of dehydrated data into the startup path).

On Windows:

(The measurements were frustratingly noisy within a range that spans 10 ms.)

Without dehydration, the app exits in ~27 ms.
With dehydration, the app exits in ~37 ms.
With the fixes in this PR and dehydration, it exits in ~34 ms.

On Linux, the difference between not dehydrated and dehydrated is ~8 ms -> ~12 ms. I didn't re-measure with this PR. Possibly shaved off a millisecond.
  • Loading branch information
MichalStrehovsky committed Dec 6, 2022
1 parent cd3a76c commit 72486c5
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -262,9 +262,44 @@ private static unsafe void RehydrateData(IntPtr dehydratedData, int length)
switch (command)
{
case DehydratedDataCommand.Copy:
// TODO: can we do any kind of memcpy here?
for (; payload > 0; payload--)
*pDest++ = *pCurrent++;
Debug.Assert(payload != 0);
if (payload < 4)
{
*pDest = *pCurrent;
if (payload > 1)
*(short*)(pDest + payload - 2) = *(short*)(pCurrent + payload - 2);
}
else if (payload < 8)
{
*(int*)pDest = *(int*)pCurrent;
*(int*)(pDest + payload - 4) = *(int*)(pCurrent + payload - 4);
}
else if (payload <= 16)
{
#if TARGET_64BIT
*(long*)pDest = *(long*)pCurrent;
*(long*)(pDest + payload - 8) = *(long*)(pCurrent + payload - 8);
#else
*(int*)pDest = *(int*)pCurrent;
*(int*)(pDest + 4) = *(int*)(pCurrent + 4);
*(int*)(pDest + payload - 8) = *(int*)(pCurrent + payload - 8);
*(int*)(pDest + payload - 4) = *(int*)(pCurrent + payload - 4);
#endif
}
else
{
// At the time of writing this, 90% of DehydratedDataCommand.Copy cases
// would fall into the above specialized cases. 10% fall back to memmove.
memmove(pDest, pCurrent, (nuint)payload);

// Not a DllImport - we don't need a GC transition since this is early startup
[MethodImplAttribute(MethodImplOptions.InternalCall)]
[RuntimeImport("*", "memmove")]
static extern unsafe void* memmove(byte* dmem, byte* smem, nuint size);
}

pDest += payload;
pCurrent += payload;
break;
case DehydratedDataCommand.ZeroFill:
pDest += payload;
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/tools/Common/Internal/Runtime/DehydratedData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Runtime.CompilerServices;

using Debug = System.Diagnostics.Debug;

Expand Down Expand Up @@ -59,6 +60,7 @@ public static int Encode(int command, int commandData, byte[] buffer)
return 1 + numExtraBytes;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe byte* Decode(byte* pB, out int command, out int payload)
{
byte b = *pB;
Expand Down

0 comments on commit 72486c5

Please sign in to comment.