Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fast array copy in C#

I have a C# class that contains an int[] array (and a couple of other fields, but the array is the main thing). The code often creates copies of this class and profiling shows that the Array.Copy() call to copy this array takes a lot of time. What can I do to make it faster?

The array size is very small and constant: 12 elements. So ideally I'd like something like a C-style array: a single block of memory that's inside the class itself (not a pointer). Is this possible in C#? (I can use unsafe code if needed.)

I've already tried:

1) Using a UIn64 and bit-shifting instead of the array. (The values of each element are also very small.) This does make the copy fast, but slows down the program overall.

2) Using separate fields for each array element: int element0, int element1, int element2, etc. Again, this is slower overall when I have to access the element at a given index.

like image 380
EM0 Avatar asked Apr 23 '14 15:04

EM0


People also ask

How to copy an array in C?

Copy an Array in C 1 Create a new array with a similar data type and size. 2 Use a loop to iterate through the original array. 3 Copy the ith element of the original array to the ith element of the new array. More ...

How to copy an array of the same length?

Copying an array involves index-by-index copying. For this to work we shall know the length of array in advance, which we shall use in iteration. Another array of same length shall be required, to which the array will be copied.

How to calculate the size of an array in C?

The sizeof () function can be used to calculate the size of an array in C. Now, let us demonstrate the copy of the array using loops. In the main method, we have taken an array with existing values. You can read input from the end-user. Later using the sizeof () function we calculated the size of the array.


2 Answers

You asked about managed arrays. If you are content to use fixed / unsafe, this can be very fast.

struct is assignable, like any primitive. Almost certainly faster than Buffer.BlockCopy() or any other method, due to the lack of method call overhead:

public unsafe struct MyStruct //the actual struct used, contains all
{
    public int a;
    public unsafe fixed byte buffer[16];
    public ulong b;
    //etc.
}

public unsafe struct FixedSizeBufferWrapper //contains _only_ the buffer
{
    public unsafe fixed byte buffer[16];
}

unsafe 
{
    fixed (byte* bufferA = myStructA.buffer, bufferB = myStructB.buffer)
    {
        *((FixedSizeBufferWrapper*)bufferA) =
        *((FixedSizeBufferWrapper*)bufferB);
    }
}

We cast fixed-size byte buffers from each of your original structs to the wrapper pointer type and dereference each pointer SO THAT we can assign one to the other by value; assigning fixed buffers directly is not possible, hence the wrapper, which is basically zero overhead (it just affects values used in pointer arithmetic that is done anyway). That wrapper is only ever used for casting.

We have to cast because (at least in my version of C#) we cannot assign anything other than a primitive type (usually byte[]) as the buffer, and we aren't allowed to cast inside fixed(...).

EDIT: This appears get translated into a call to Buffer.Memcpy() (specifically Buffer.memcpy4() in my case, in Unity / Mono) under the hood to do the copy.

like image 90
Engineer Avatar answered Oct 27 '22 00:10

Engineer


I would checkout the System.Buffer.BlockCopy if you are really concerned about speed.

http://msdn.microsoft.com/en-us/library/system.buffer.blockcopy.aspx

Simple Example:

  int[] a = new int[] {1,2,3,4,5,6,7,8};
  int[] b = new int[a.Length];
  int size = sizeof(int);
  int length = a.Length * size;               
  System.Buffer.BlockCopy(a, 0, b, 0, length);

Great discussion on it over here: Array.Copy vs Buffer.BlockCopy

like image 26
Moop Avatar answered Oct 27 '22 00:10

Moop