Skip to content

Instantly share code, notes, and snippets.

@sven-n
Created Sep 3, 2018
Embed
What would you like to do?
A quickly hacked together test which compares marshalling with manually reading bytes from byte arrays
namespace MarshalTest
{
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
class Program
{
static void Main(string[] args)
{
// warm up:
RunMarshal(1000);
RunManual(1000);
// measuring:
var elapsedUnsafe = RunMarshal(10000000);
var elapsedSafe = RunManual(10000000);
Console.WriteLine($"Marshal: {elapsedUnsafe}");
Console.WriteLine($"Manual: {elapsedSafe}");
Console.WriteLine($"Manual is {elapsedUnsafe / elapsedSafe} times faster than Marshal");
Console.ReadKey();
/* my result running the Release build under .net core 2.0:
Marshal: 00:00:03.7376050
Manual: 00:00:00.0365468
Manual is 102,269008504165 times faster than Marshal
*/
}
private static TimeSpan RunMarshal(int times)
{
var array = new byte[] { 0xC1, 0x07, 0x11, 0x13, 0x37, 0x78, 0x01 };
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
try
{
for (int i = 0; i < times; i++)
{
var structure = GetStructure<HitPacket>(array);
Validate(structure.TargetId.SwapBytes(), structure.Animation, structure.Direction);
}
}
finally
{
stopwatch.Stop();
}
return stopwatch.Elapsed;
}
private static TimeSpan RunManual(int times)
{
var array = new byte[] { 0xC1, 0x07, 0x11, 0x13, 0x37, 0x78, 0x01 };
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
try
{
for (int i = 0; i < times; i++)
{
var target = array.MakeWordSmallEndian(3);
var animation = array[5];
var direction = array[6];
Validate(target, animation, direction);
}
}
finally
{
stopwatch.Stop();
}
return stopwatch.Elapsed;
}
private static void Validate(ushort target, byte animation, byte direction)
{
if (target + animation + direction != 0x1337 + 0x78 + 0x01)
{
throw new Exception("something went wrong");
}
}
/// <summary>
/// Marshals a raw buffer to a given marshalable struct.
/// </summary>
public static unsafe T GetStructure<T>(byte[] buffer) where T : struct
{
fixed (byte* bufferPin = buffer)
{
return (T)Marshal.PtrToStructure(new IntPtr(bufferPin), typeof(T));
}
}
}
public static class Extensions
{
/// <summary>
/// Converts bytes of an array to an unsigned short, small endian.
/// </summary>
/// <param name="array">The array.</param>
/// <param name="startIndex">The start index.</param>
/// <returns>An unsigned short.</returns>
public static ushort MakeWordSmallEndian(this byte[] array, int startIndex)
{
return (ushort)((array[startIndex] << 8) | array[startIndex + 1]);
}
/// <summary>
/// Swaps the bytes of an unsigned short value.
/// </summary>
/// <param name="value">The value.</param>
/// <returns>The value with swapped bytes</returns>
public static ushort SwapBytes(this ushort value)
{
return (ushort)(((value & 0xFF) << 8) + ((value >> 8) & 0xFF));
}
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct Header
{
public byte HeaderType;
public byte Length;
public byte Type;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct HitPacket
{
public Header Header;
public ushort TargetId;
public byte Animation;
public byte Direction;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment