C# Loop Unwinding

Performance optimization

Loop unwinding sometimes improves performance. It allows you to simplify code and make it more efficient. It reduces the number of iterations in for-loops. You can refactor your C# code with loop unrolling.

This C# benchmark article demonstrates the loop unwinding optimization. Unrolling the loop improved performance slightly.

Loop unwinding benchmark

Regular loop: 6255 ms
Unrolled ifs: 6179 ms [faster]

Examples

Note

First, we look at how you can change a regular for loop to an unwound for loop. Loop unrolling or unwinding is an optimization you can make to some loops. To make this optimization, you can separate every statement group rather than iterate over each one.

Example loop [C#]

class Program
{
    static void Main()
    {
	int[] a = {1, 4, 5, 7};

	for (int i = 0; i < a.Length; i++)
	{
	    if (a[i] == 3)
	    {
		// ...
	    }
	}
    }
}

Example unrolled loop [C#]

class Program
{
    static void Main()
    {
	int[] a = {1, 4, 5, 7};

	for (int i = 0; i < a.Length; i += 2)
	{
	    if (a[i] == 3)
	    {
		// ...
	    }
	    if (a[i + 1] == 3)
	    {
		// ...
	    }
	}
    }
}
Warning

Note. It is important that you only unwind loops so that the steps in the loops do not exceed the array bounds. The unwound loop above could have two, four, or six elements to loop over, but not three, five, or seven.

More loop examples

Loop unwinding can improve the logic of your code. It can improve performance, but more importantly, it can help you clear up confusing parts of your code. When I unrolled the example I had faster and shorter code. In the example, I had to test strings. If the string started with one of three acceptable strings, I had to accept it.

Code that tests strings in foreach loop [C#]

string[] a1 = new string[]
{
    "cat/",
    "dog/",
    "man/"
};
string l = "dog/example";

bool ok = false;
foreach (string a in a1)
{
    if (l.StartsWith(a))
    {
	ok = true;
	break;
    }
}

Code that tests strings in unrolled loop [C#]

const string aa = "cat/";
const string ab = "dog/";
const string ac = "man/";
string l = "dog/example";

bool ok = false;
if (l.StartsWith(aa) ||
    l.StartsWith(ab) ||
    l.StartsWith(ac))
{
    ok = true;
}

Tips

Programming tip

You can eliminate loops when the number of iterations is known beforehand. This is usually best with very few iterations—less than five. If you have a very long loop, then you can unroll four or eight parts at a time. This can improve performance. Make sure to test.

Timing unrolled loops. Unrolling loops does not always result in a speedup. However, in the above examples, I received a small speedup. It eliminated the entire loop and made the code shorter. The first code example in "More loop examples" was tested against the second example, and the unrolled loop was faster. My understanding is that the processor is better able to predict branches and use pipelining when the statements are unrolled.

Benchmark Programs

Summary

The C# programming language

We saw some examples and benchmarks of loops. Sometimes it can be beneficial to unroll or unwind your loops. However, the understanding of computer hardware and processors we gain here is more valuable.

Loop Constructs
.NET