Arrays in .NET–part V

In the previous post, we’ve looked an non-zero based arrays and I’ve ended the post by talking a little bit about performance. As I’ve said, non-zero based arrays are not really something you want to use regularly. Besides that, we’ve also seen that regular arrays aren’t as performant as jagged arrays because the compiler won’t, for instance,  hoist the index checking outside an eventual loop. Since this index hoisting *does* make a difference, then how can we improve the performance of our code? Well, there is a way for improving the performance, at the coast of safety: I’m talking about using unsafe code for enumerating the items of an array!

When you use this strategy, you’re performing a direct memory access. Notice also that these accesses won’t throw exceptions when you access an “invalid position” (like it happens when you use the “traditional approach”). Instead, you might end with a memory corruption…

In practice, using unsafe code means that the assembly that contains this code must be granted full trust or have the security permission’s skip verification option turned on.  After this basic intro, it’s time to see some code. The next snippet introduces two methods which go through all the items of a rectangular array by using a safe and an unsafe approach:

const Int32 itemsCount = 10000;
static void Main(string[] args) {            
    var ints = new Int32[itemsCount, itemsCount];
    var stopwatch = Stopwatch.StartNew();
    SafeAccess(ints);
    Console.WriteLine("time ellapsed: " + stopwatch.ElapsedMilliseconds);
    stopwatch = Stopwatch.StartNew();
    UnsafeAccess(ints);
    Console.WriteLine("time ellapsed: " + stopwatch.ElapsedMilliseconds);
}
static void SafeAccess(Int32[,] ints) {
    var totalCount = 0;
    for (int i = 0; i < itemsCount; i++) {
        for (int j = 0; j < itemsCount; j++) {
            totalCount += ints[i, j];
        }
    }
}
unsafe static void UnsafeAccess(Int32[,] ints){
    var totalCount = 0;
    fixed (Int32* ptr = ints) {
        for (int i = 0; i < itemsCount; i++) {
            var basePos = i * itemsCount;
            for (Int32 j = 0; j < itemsCount; j++) {
                totalCount += ptr[basePos + j];
            }
        }
    }
}

There’s not much to say about the SafeAccess method. There are, however several interesting observations about the UnsafeAccess method:

  • the method is marked with the unsafe keyword because it uses pointers to access the items on the array (don’t forget that you need to compile this code with the /unsafe option).
  • ptr is a pointer which points to the memory address of the first item of the array.
  • We’re fixing (or pinning) the pointer (by using the fixed statement) to prevent the GC from reallocating a movable variable (since the ints references a managed array, it could get moved during a GC compaction operation).
  • We need to perform the calculations required to access the items of the array. Even though we’ve got a rectangular array, the truth is that it is allocated as single block of items, where one line is appended to the end of the previous one.
  • Finally, notice that we get the value of each value by using an “array index syntax” (similar to the one used in traditional C# code and to the one you can use with unmanaged C or C++)

In my machine, running the previous code resulted in the following output:

safevsunsafe

As you can see, there’s a small difference which can make all the difference in the world for those apps  where you do need that extra performance ounce…Before
ending, a couple of observations:

  • as I said, this code needs full trust and there might be some places where your code won’t have it.
  • This strategy can only be used for arrays which hold primitive types, enums or structs whose fields’ type is one of the previously mentioned types.

If you want, there’s still an extra step for improving the performance of code that interacts with arrays, but that will be the topic of the next post. Stay tuned for more.

Advertisements

~ by Luis Abreu on May 22, 2011.

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 )

Google+ photo

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

Connecting to %s

 
%d bloggers like this: