C-Sharp | Java | Python | Swift | GO | WPF | Ruby | Scala | F# | JavaScript | SQL | PHP | Angular | HTML
It influences the enregistration of variables. We can sometimes enhance performance by reordering parameters in methods. We review the reasons why this is effective.
Performance of methods and parameter ordering X86 platform. Test first 2 parameters: 952 ms [faster] Test last 2 parameters: 2224 ms
Example. First, the .NET Framework compiles methods to native code, and it uses the same optimizations available in unmanaged languages with FASTCALL. By placing frequently-used variables in the first two parameters, you can improve performance.
Note: The benchmark tests two methods in tight loops. The methods are the same except for the parameter order.
C# program that benchmarks parameter usage using System; using System.Diagnostics; class Program { static bool Test1(int a, int b, int c, int d, int e, int f) { // // This method tests the first two parameters in the loop. // for (int i = 5; i < 10000000; i++) { if (a == i) { return true; } if (b == i) { return true; } } if (c == 1 || d == 1 || e == 1) { return true; } return false; } static bool Test2(int a, int b, int c, int d, int e, int f) { // // This method tests the last two parameters in the loop. // for (int i = 5; i < 10000000; i++) { if (e == i) { return true; } if (f == i) { return true; } } if (a == 1 || b == 1 || c == 1) { return true; } return false; } static void Main() { const int m = 100; Stopwatch s1 = Stopwatch.StartNew(); for (int i = 0; i < m; i++) { Test1(3, 3, 3, 3, 3, 3); } s1.Stop(); Stopwatch s2 = Stopwatch.StartNew(); for (int i = 0; i < m; i++) { Test2(3, 3, 3, 3, 3, 3); } s2.Stop(); Console.WriteLine("{0},{1}", s1.ElapsedMilliseconds, s2.ElapsedMilliseconds); Console.Read(); } }
The exact logic tests in Test1 and Test2 are unimportant here. Two parameters are tested in the tight loop in Test1 and Test2. In Test1, the variables tested are the first parameters. They are more likely to be enregistered.
Parameters. When you compile and execute a method in the C# language, the parameters are pushed onto the stack and the method is called. Internally, that method then uses the parameters on the stack.
However: Microsoft compilers have an optimization called FASTCALL, in which the first two parameters in x86 are passed as registers.
Understanding registers. An enregistered variable in machine code is one that is stored in the fastest processor cache so access to it is extremely fast. In loops, the iterator variable i is normally stored in a register.
Discussion. Rarely is parameter order likely to affect results. But you may find a method that uses many parameters. Often, such methods are focused on optimization—they defy object-oriented best practices. This technique could improve these methods.
For FASTCALL, compiler will try to pass arguments in registers, if not enough caller will pushed them into stack still in an order from right to left. Stack cleanup is done by callee. It is called FASTCALL because if arguments can be passed in registers (for 64bit CPU the maximum number is 6), no stack push/clean up is needed.
x86 Disassembly: Calling Convention Examples
Summary. We saw how parameter order in C# methods affects the performance of the variables and the likelihood they will be enregistered. Having your loop variables in registers is hugely faster, and C even has the (ignored) register keyword.
Finally: Adequate knowledge of compilers and registers can improve your C# code.