C# Method Size Test

Performance optimization

Method size influences performance. It affects the JIT compiler in the .NET Framework. Why do shorter methods that follow the same paths at runtime run faster than longer methods? We gain an understanding of how the optimizer works.

Question: Are shorter methods faster even if the same statements are executed?
The result was that shorter methods are faster.

Test method size

First we see the benchmark I took. There are two methods being tested: the first one, which is short and doesn't contain code that isn't executed, and the second one, which follows the same steps but contains unnecessary code at the end, which is never used.

Program that tests method sizes [C#]

using System;
using System.Diagnostics;

class Program
{
    static void Main()
    {
	// [Note]
	// Shows how method size can impact performance.
	const int m = 10000000;
	Stopwatch s1 = Stopwatch.StartNew();
	for (int i = 0; i < m; i++)
	{
	    int a = Method1();
	    int b = Method1();
	    if (a != b) // [ignore]
	    {
		i++;
	    }
	}
	s1.Stop();
	Stopwatch s2 = Stopwatch.StartNew();
	for (int i = 0; i < m; i++)
	{
	    int a = Method2();
	    int b = Method2();
	    if (a != b) // [ignore]
	    {
		i++;
	    }
	}
	s2.Stop();
	Console.WriteLine("{0},{1}",
	    s1.ElapsedMilliseconds,
	    s2.ElapsedMilliseconds);
	Console.Read();
    }

    /// <summary>
    /// Short method.
    /// </summary>
    static int Method1()
    {
	int i = int.Parse("1");
	if (i == 1)
	{
	    return 1;
	}
	return 0;
    }

    /// <summary>
    /// Long method with unneeded logic that is never used.
    /// </summary>
    static int Method2()
    {
	int i = int.Parse("1");
	if (i == 1)
	{
	    return 1;
	}
	// [begin useless code]
	string a = 1.ToString();
	string b = 1.ToString();
	string c = 1.ToString();
	string d = 1.ToString();
	string e = 1.ToString();
	string f = 1.ToString();
	string g = 1.ToString();
	string h = 1.ToString();
	return (a != b ||
	    a != c ||
	    a != d ||
	    a != e ||
	    a != f ||
	    a != g ||
	    a != h) ? 1 : 0;
	// [end]
    }
}

Results

Method 1 (no extra code):         2269 ms [7.43% faster]
Method 2 (has extra unused code): 2451 ms
Main method

Main method. This method runs two loops and times them with Stopwatches. The first loop tests the first method, Method1, and then the second loop tests Method2. The elapsed milliseconds are printed afterwards.

Description of Method1. This method always returns the value 1 and doesn't have any unreachable code at the end. It performs better.

Description of Method2. This method always returns the value 1, and does have unreachable code at the end. The code after the "return" statement is never reached, but the compiler cannot remove it because it doesn't know the result of int.Parse at compile-time.

Benchmark

My test found the first method to always be faster than the second. This means that unreachable code that is not compiled away causes a performance hit. I measured the two methods in many configurations.

Percentage symbol

The method without the extra statements performed about 7% faster. As part of my test, I checked IL Disassembler and saw that Method1 has 1 local, while Method2 has 17 locals.

IL Disassembler Tutorial

Summary

The C# programming language

We saw that code that is not executed affects the performance of your methods. The compiler is unable to remove certain blocks of code. You can mitigate the performance loss when you need to have long groups of statements that are not executed often by refactoring, extracting them into a method. This reduces the stack size and number of locals.

Method Tips
.NET