first of all, thanks for your great example.
I update my little program based of your answer to benchmark it.
The project should be .NETFramework 4.0 client, but for the benchmark i change it to be .NETFramework 4.0.
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public class SomeStructure
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public char[] szF1;
public char cF2;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public char[] szF3;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)]
public char[] szF4;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)]
public char[] szF5;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)]
public char[] szF6;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 9)]
public char[] szF7;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 9)]
public char[] szF8;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 9)]
public char[] szF9;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 9)]
public char[] szF10;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
public char[] cF11;
public char cF12;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public char[] cF13;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)]
public char[] szF14;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 9)]
public char[] szF15;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)]
public char[] szF16;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 9)]
public char[] szF17;
}
public class Race
{
//[Benchmark(Baseline = true)]
//public SomeStruct A() => MemoryMarshal.Read<SomeStruct>(_data);
[Benchmark(Baseline = true)]
public object A() => Program.ConvertBytesToStructure(new SomeStructure(), _data, Marshal.SizeOf(typeof(SomeStructure)), 0, _data.Length);
[Benchmark]
public SomeStructure B() => Program.ConvertBytesToStructureV2<SomeStructure>(_data, 0, _data.Length);
private readonly byte[] _data = new byte[] {
49, 50, 49, 49, 50, 51, 52, 53, 54, 55, 56,
49, 50, 51, 52, 53, 54, 55, 49, 50, 51, 52,
53, 54, 55, 49, 50, 51, 52, 53, 54, 55, 49,
50, 51, 52, 53, 54, 55, 56, 57, 49, 50, 51,
52, 53, 54, 55, 56, 57, 49, 50, 51, 52, 53,
54, 55, 56, 57, 49, 50, 51, 52, 53, 54, 55,
56, 57, 49, 97, 49, 50, 49, 50, 51, 52, 53,
54, 55, 49, 50, 51, 52, 53, 54, 55, 56, 57,
49, 50, 51, 52, 53, 54, 55, 49, 50, 51, 52,
53, 54, 55, 56, 57
};
}
public class Program
{
static void Main(string[] args)
{
var summary = BenchmarkRunner.Run<Race>();
Console.ReadKey();
}
public static object ConvertBytesToStructure(object target, byte[] source, Int32 targetSize, int startIndex, int length)
{
if (target == null)
return null;
IntPtr p_objTarget = Marshal.AllocHGlobal(targetSize);
try
{
Marshal.Copy(source, startIndex, p_objTarget, length);
Marshal.PtrToStructure(p_objTarget, target);
}
catch (Exception e)
{
Console.WriteLine(e);
}
finally
{
Marshal.FreeHGlobal(p_objTarget);
}
return target;
}
public static T ConvertBytesToStructureV2<T>(byte[] data, int startIndex, int length)
{
byte[] fixedData = new byte[length];
unsafe
{
fixed (byte* pSource = data, pTarget = fixedData)
{
int index = 0;
for (int i = startIndex; i < data.Length; i++)
{
pTarget[index] = pSource[i];
index++;
}
}
fixed (byte* p = &fixedData[0])
{
return (T)Marshal.PtrToStructure(new IntPtr(p), typeof(T));
}
}
}
}
The results:
If i understand good - it seems that according to the Benchmark results,the first method is faster than the second method.
But these are not the results I see in my system.
More details:
It's multi-threading system, i've a service that listen to another service and register to his event, when the event is raised with unmanaged data (byte[]) i convert that to the my cutom managed object.
So far so good, but when i stress the system by sending thousands of events (~20000) per second, The original method (ConvertBytesToStructure) getting poor performance, and the new method getting excellent performance..
MemoryMarshal
class which has a methodRead<T>
that I believe matches your needs. Alternatively, one can import the System.Memory NuGet package if using .NET Framework 4.5 or above; it is not as optimized but should work well. \$\endgroup\$struct
s you are using? \$\endgroup\$