Array access performance (unsafe code). The direct memory access to arrays.

1. What we can do to make access to arrays 2 times faster. Which types of data are suitable for the direct memory access technique?

2. Three disadvantages of the direct memory access technique.

If we are concerned about performance we can perform the direct memory access to arrays. This unsafe array access technique is useful only for types:

1.     sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, or bool.

2.     Any enum type.

3.     Any pointer type.

4.     Any user-defined struct type that contains fields of unmanaged types only.

Because an object reference cannot be garbage collected even if a pointer is pointing to it. The GC does not keep track of whether an object is being pointed to by any pointer types.

                                  

        public static void Main()

        {

            int testCount = 10000;

 

            int[] lengths = new int[] { 100, 100 };

            int[] lowerBounds = new int[] { 0, 0 };

            int[,] array = (int[,])Array.CreateInstance(typeof(int), lengths, lowerBounds);

            //FillArray(array);

 

            int[][] jaggedArray = new int[100][];

 

            for (int i = 0; i < 100; i++)

                jaggedArray[i] = new int[100];

 

            Thread.Sleep(500);

 

            Stopwatch sw = Stopwatch.StartNew();

            for (int i = 0; i < testCount; i++)

                GetJaggedArrayAccess(jaggedArray);

            Console.WriteLine("Access to jagged array: {0}", sw.Elapsed);

 

            sw = Stopwatch.StartNew();

            for (int i = 0; i < testCount; i++)

                GetRectangleArrayAccess(array);

            Console.WriteLine("Access to rectangle array: {0}", sw.Elapsed);

 

            sw = Stopwatch.StartNew();

            for (int i = 0; i < testCount; i++)

                GetUnsafeArrayAccess(array);

 

            Console.WriteLine("Safe array access: {0}", sw.Elapsed);

 

            Console.ReadKey();

        }

 

        public static void GetJaggedArrayAccess(int[][] array)

        {

            //The method Length returns the number of arrays contained in the jagged array.

            for (int i = 0; i < array.Length; i++)

            {

                for (int j = 0; j < array[i].Length; j++)

                {

                    int result = array[i][j];

                }

            }

        }

 

 

        public static void GetRectangleArrayAccess(int[,] array)

        {

 

            int lowerBound0 = array.GetLowerBound(0);

            int upperBound0 = array.GetUpperBound(0);

 

            int lowerBound1 = array.GetLowerBound(1);

            int upperBound1 = array.GetUpperBound(1);

 

 

            for (int i = lowerBound0; i <= upperBound0; i++)

            {

                for (int j = lowerBound1; j <= upperBound1; j++)

                {

                    int result = array[i, j];

                }

            }

        }

 

        /// <summary>

        /// To allow unsafe code the "Allow unsafe code" checkbox must be checked

        /// </summary>

        /// <param name="array"></param>

        public static unsafe void GetUnsafeArrayAccess(int[,] array)

        {

            int lowerBound0 = array.GetLowerBound(0);

            int upperBound0 = array.GetUpperBound(0);

 

            int lowerBound1 = array.GetLowerBound(1);

            int upperBound1 = array.GetUpperBound(1);

 

            //Number of elements in row

            int numElements = upperBound1 – lowerBound1 + 1;

 

            int rowBounds = array.GetLength(0);

            int colBounds = array.GetLength(1);

 

            //The fixed statement sets a pointer to a managed variable

            //and "pins" that variable during the execution of statement.

            //Without fixed, pointers to movable managed variables

            //would be of little use since garbage collection could

            //relocate the variables unpredictably. The C# compiler only

            //lets you assign a pointer to a managed variable in a fixed statement.          

            fixed (int* p = &array[lowerBound0, lowerBound1])

            {

                for (int i = 0; i < rowBounds; i++)

                {

                    //calculate offset to get an access to the element, because 

                    //we should treat access via pointer like getting

                    //access to the single dimension array

                    int offset = i * numElements;

                    for (int j = 0; j < colBounds; j++)

                    {

                        int result = p[offset + j];

                    }

                }

            }

        }

 

Output:

 

Access to jagged array: 00:00:00.7642407

Access to rectangle array: 00:00:00.7765845

Safe array access: 00:00:00.4876177

 

The unsafe access is almost 2 times faster than a safe access but it has following disadvantages:

1.     It is hard to read and write code.

2.     It will be easy to read the memory outside array bounds. It leads to memory curruption and type safety violation.

3.     Code can be run only with granded permission. By default such permission is granted for assemblies installed locally. But there are no such permission for code downloaded from net.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s