Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unsafe.As from byte array to ulong array

Tags:

c#

c#-7.0

I'm currently looking at porting my metro hash implementon to use C#7 features, as several parts might profit from ref locals to improve performance. The hash does the calculations on a ulong[4] array, but the result is a 16 byte array. Currently I'm copying the ulong array to the result byte buffer, but this takes a bit of time. So i'm wondering if System.Runtime.CompilerServices.Unsafe is safe to use here:

var result = new byte[16];
ulong[] state = Unsafe.As<byte[], ulong[]>(ref result);
ref var firstState = ref state[0];
ref var secondState = ref state[1];
ulong thirdState = 0;
ulong fourthState = 0;

The above code snippet means that I'm using the result buffer also for parts of my state calculations and not only for the final output.

My unit tests are successful and according to benchmarkdotnet skipping the block copy would result in a 20% performance increase, which is high enough for me to find out if it is correct to use it.

like image 277
Tornhoof Avatar asked Mar 09 '17 12:03

Tornhoof


2 Answers

In current .NET terms, this would be a good fit for Span<T>:

Span<byte> result = new byte[16];
Span<ulong> state = MemoryMarshal.Cast<byte, ulong>(result);

This enforces lengths etc, while having good JIT behaviour and not requiring unsafe. You can even stackalloc the original buffer (from C# 7.2 onwards):

Span<byte> result = stackalloc byte[16];
Span<ulong> state = MemoryMarshal.Cast<byte, ulong>(result);

Note that Span<T> gets the length change correct; it is also trivial to cast into a Span<Vector<T>> if you want to use SIMD for hardware acceleration.

like image 96
Marc Gravell Avatar answered Nov 07 '22 10:11

Marc Gravell


What you're doing seems fine, just be careful because there's nothing to stop you from doing this:

byte[] x = new byte[16];
long[] y = Unsafe.As<byte[], long[]>(ref x);

Console.WriteLine(y.Length); // still 16

for (int i = 0; i < y.Length; i++)
    Console.WriteLine(y[i]); // reads random memory from your program, could cause crash
like image 1
Mike Marynowski Avatar answered Nov 07 '22 12:11

Mike Marynowski