Reputation: 767
I am trying to improve the speed of BitConvert, or rather, an alternative way.
So here is the code i thought was supposed to be faster :
bsize = ms.length
int index = 0;
byte[] target = new byte[intsize];
target[index++] = (byte)bsize;
target[index++] = (byte)(bsize >> 8);
target[index++] = (byte)(bsize >> 16);
target[index] = (byte)(bsize >> 24);
And well the BitConvert code:
BitConverter.GetBytes(bsize)
And well, it wasn´t faster, it was alot slower from my tests, more than twice as slow.
So why is it slower? And is there a way to improve the speed?
EDIT:
BitConvert = 5068 Ticks
OtherMethod above: 12847 Ticks
EDIT 2: My Benchmark code:
private unsafe void ExecuteBenchmark(int samplingSize = 100000)
{
// run the Garbage collector
GC.Collect();
GC.WaitForPendingFinalizers();
// log start
Console.WriteLine("Benchmark started");
// start timer
var t = Stopwatch.StartNew();
for (int i = 0; i < samplingSize; i++)
{
}
}
// stop timer
t.Stop();
// log ending
Console.WriteLine("Execute1 time = " + t.ElapsedTicks + " ticks");
}
Upvotes: 0
Views: 131
Reputation: 125650
Your implementation is slower, because BitConverter
uses unsafe
code which operates on pointers:
public unsafe static byte[] GetBytes(int value)
{
byte[] array = new byte[4];
fixed (byte* ptr = array)
{
*(int*)ptr = value;
}
return array;
}
And back to int
:
public unsafe static int ToInt32(byte[] value, int startIndex)
{
if (value == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
}
if ((ulong)startIndex >= (ulong)((long)value.Length))
{
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index);
}
if (startIndex > value.Length - 4)
{
ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
}
int result;
if (startIndex % 4 == 0)
{
result = *(int*)(&value[startIndex]);
}
else
{
if (BitConverter.IsLittleEndian)
{
result = ((int)(*(&value[startIndex])) | (int)(&value[startIndex])[(IntPtr)1 / 1] << 8 | (int)(&value[startIndex])[(IntPtr)2 / 1] << 16 | (int)(&value[startIndex])[(IntPtr)3 / 1] << 24);
}
else
{
result = ((int)(*(&value[startIndex])) << 24 | (int)(&value[startIndex])[(IntPtr)1 / 1] << 16 | (int)(&value[startIndex])[(IntPtr)2 / 1] << 8 | (int)(&value[startIndex])[(IntPtr)3 / 1]);
}
}
return result;
}
Upvotes: 3
Reputation: 30021
Well, first, measuring the speed of such a tiny amount of code is going to be error-prone. Posting your benchmark might give more answers.
But my guess is that on platforms supporting it (like x86), BitConverter probably does a single bounds check and an unaligned write into target
rather than 3 shifts, 4 bounds checks, and 4 writes. It may end up completely inlined, alleviating all call overhead.
Upvotes: 2