A quickly hacked together test which compares marshalling with manually reading bytes from byte arrays
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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