Tuesday, December 15, 2009

Filling an array with a default value

After following the discussion on Stackoverflow about how to initialize a byte array with a value I decided to do some benchmarking for fun.

Here are the results, and the code follows below (run on Windows 7 64bit dual core).

Array length: 1048576
Iterations: 1000
Enumerable: 00:00:12.3817249
Parallel Enumerable: 00:00:17.6506353
For loop: 00:00:01.7095341
Parallel for loop: 00:00:06.9824434
Unsafe: 00:00:00.7028914


static void Fill1(byte value)
{
byte[] a = Enumerable.Repeat<byte>(value, _arrLength).ToArray();
}

static void Fill2(byte value)
{
byte[] a = ParallelEnumerable.Repeat<byte>(value, _arrLength).ToArray();
}

static void Fill3(byte value)
{
byte[] a = new byte[_arrLength];
for (int i = 0; i < _arrLength; i++)
{
a[i] = value;
}
}

static void Fill4(byte value)
{
byte[] a = new byte[_arrLength];
Parallel.For(0, _arrLength, i =>
{
a[i] = value;
});
}

static unsafe void Fill5(byte value)
{
Int64 fillValue = BitConverter.ToInt64(new byte[] { value, value, value, value, value, value, value, value }, 0);

byte[] a = new byte[_arrLength];
Int64* src = (Int64*)&fillValue;
fixed (byte* ptr = &a[0])
{
Int64* dest = (Int64*)ptr;
int length = _arrLength;
while (length >= 8)
{
*dest = fillValue;
dest++;
length -= 8;
}
byte* bDest = (byte*)dest;
for (byte i = 0; i < length; i++)
{
*bDest = value;
bDest++;
}
}
}



2 comments:

  1. can C# do duff's device? I wonder how it would preform? (:

    thanks for profiling this stuff, it makes the choice pretty clear... I'm going with the for loop because i don't think i can use so called "unsafe" code in my situation.

    Thanks man!

    ReplyDelete
  2. Glad you found it helpful :)

    Found an implementation of Duff's Device at http://www.giannistsakiris.com/index.php/2007/07/17/duffs-device/ which I modified to set just one value. When running many tests it 9/10 times performs marginally faster than the for loop and then 1/10 slower or the same.

    I would go with the for loop as well for most cases.

    public static void Fill6(byte value)
    {
    byte[] toBuffer = new byte[_arrLength];
    int count = _arrLength;
    int i = 0;

    if (count%8 == 7) goto case_7;
    if (count%8 == 6) goto case_6;
    if (count%8 == 5) goto case_5;
    if (count%8 == 4) goto case_4;
    if (count%8 == 3) goto case_3;
    if (count%8 == 2) goto case_2;
    if (count%8 == 1) goto case_1;

    case_0:
    toBuffer[i++] = value;
    case_7:
    toBuffer[i++] = value;
    case_6:
    toBuffer[i++] = value;
    case_5:
    toBuffer[i++] = value;
    case_4:
    toBuffer[i++] = value;
    case_3:
    toBuffer[i++] = value;
    case_2:
    toBuffer[i++] = value;
    case_1:
    toBuffer[i++] = value;
    if ((count -= 8) > 0) goto case_0;
    }

    ReplyDelete