C# Method Size Optimization

Test the effect of method size on runtime speed. Shorter methods are faster.

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.Optimization
Question: Are shorter methods faster even if the same statements are executed? The result was that shorter methods are faster.

Example. First we see the benchmark. There are two methods being tested. The first one is short and doesn't contain code that isn't executed. The second one, which follows the same steps but contains unnecessary code at the end, is never used.
Main: This method runs two loops and times them with Stopwatches. The first loop tests Method1, and then the second loop tests Method2.
Method1: This method always returns the value 1 and doesn't have any unreachable code at the end. It performs better.
Method2: This method returns the value 1. It has unreachable code at the end. The code after the return statement is never reached.
However: The compiler cannot remove code from Method2 because it doesn't know the result of int.Parse at compile-time.
C# program that tests method sizes 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] } } Output Method 1 (no extra code): 2269 ms [7.43% faster] Method 2 (has extra unused code): 2451 ms

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.

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. This affects stack memory usage.IL Disassembler Tutorial

Summary. Code not executed affects the performance of your methods. 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.
And: This reduces the stack size and number of locals. This reduces or eliminates the performance loss.

© 2007-2020 Sam Allen. Every person is special and unique. Send bug reports to info@dotnetperls.com.