1

I'm optimizing every line of code in my application, as performance is key. I'm testing all assumptions, as what I expect is not what I see in reality.

A strange occurrence to me is the performance of function calls. Below are two scenarios. Iterating an integer within the loop, and with a function in the loop. I expected the function call to be slower, however it is faster??

Can anyone explain this? I'm using .NET 4.7.1

  • Without function: 2808ms
  • With function 2295ms

UPDATE:

Switching the loops switches the runtime as well - I don't understand why, but will accept it as it is. Running the two different loops in different applications give similar results. I'll assume in the future that a function call won't create any additional overhead

    public static int a = 0;

    public static void Increment()
    {
        a = a + 1;
    }

    static void Main(string[] args)
    {

        //There were suggestions that the first for loop always runs faster.  I have included a 'dummy' for loop here to warm up.  
        a = 0;
        for (int i = 0;i < 1000;i++)
        {
            a = a + 1;
        }



        //Normal increment
        Stopwatch sw = new Stopwatch();
        sw.Start();
        a = 0;
        for (int i = 0; i < 900000000;i++)
        {
            a = a + 1;
        }
        sw.Stop();
        Console.WriteLine(sw.ElapsedMilliseconds);


        //Increment with function
        Stopwatch sw2 = new Stopwatch();
        sw2.Start();
        a = 0;
        for (int i = 0; i < 900000000; i++)
        {
            Increment();
        }
        sw2.Stop();
        Console.WriteLine(sw2.ElapsedMilliseconds);

        Console.ReadLine();
    }
Isma
  • 14,604
  • 5
  • 37
  • 51
ceds
  • 2,097
  • 5
  • 32
  • 50
  • The two versions do the exact same thing. The reason why the second one is executed faster is discussed here: [Why does the second for loop always execute faster than the first one?](https://stackoverflow.com/q/1021737/4934172) – 41686d6564 stands w. Palestine Jul 27 '18 at 09:32
  • @AhmedAbdelhameed: That's kinda the point when testing which variant of something performs better: They *should* have the same result and behaviour. – Joey Jul 27 '18 at 09:34
  • @Ahmed Is there no function overhead (return pointers and the like) when calling a static function like that? – Adam Jul 27 '18 at 09:35
  • @AhmedAbdelhameed I have added a dummy for loop at the start of the code. Makes zero difference – ceds Jul 27 '18 at 09:40
  • @Joey If you swap them, the second one (originally first) will still be slightly faster. – 41686d6564 stands w. Palestine Jul 27 '18 at 09:41
  • What function? The function is so trivial it will be inlined by the JIT anyway. – TomTom Jul 27 '18 at 09:41
  • 1
    @Adam Perhaps while the code is _not_ optimized. But when the code is optimized (e.g., in release mode) there shouldn't be any difference, AFAIK. – 41686d6564 stands w. Palestine Jul 27 '18 at 09:43
  • @ceds As I said in a previous comment, try swapping them (while code optimization is enabled) and you'll notice that the one without a function becomes faster. – 41686d6564 stands w. Palestine Jul 27 '18 at 09:45
  • @AhmedAbdelhameed is correct, the performance should be the same in release mode. – Liu Jul 27 '18 at 09:46
  • @AhmedAbdelhameed swapping them indeed makes a difference. The code is run in Optimized (release) mode. I'll just assume in the future there is no difference – ceds Jul 27 '18 at 09:46
  • 1
    The key to optimizing an application is *not* "optimizing every line of code", by the way. That's finding the actual bottlenecks and optimizing *those*. When you find yourself comparing different ways to increment numbers, you're almost certainly looking into things that are not hotspots in any actual application, and performance reasoning by analogy is fraud. Having said all that, running a proper microbenchmark is hard -- don't reinvent the wheel but use things like [BenchmarkDotNet](https://benchmarkdotnet.org/), which allows you to go all the way down to the assembly level if need be. – Jeroen Mostert Jul 27 '18 at 09:47
  • 1
    Possible duplicate of [Why does the second for loop always execute faster than the first one?](https://stackoverflow.com/questions/1021737/why-does-the-second-for-loop-always-execute-faster-than-the-first-one) – Isma Jul 27 '18 at 09:49
  • @ceds I just run the test in release mode 4,5 times and both of them took ~1350 ms – Liu Jul 27 '18 at 09:52
  • 1
    @ceds your *benchmarking* code is flawed. You can't reach any conclusions from a *single* run with such small differences. Perhaps your AV was running the second time. Or the first call paid the JIT price. Or whatever. Use [BenchmarkDotNet](https://benchmarkdotnet.org/articles/overview.html/articles/overview.html) instead, which ensures a proper warmup and cooldown period between tests, and runs as long as needed for the results to *stabilise*. I suspect you won't find any differences – Panagiotis Kanavos Jul 27 '18 at 09:55
  • As said previously, switching the loops switches the runtime as well. I have no idea why, but I'll remember this. Thanks for all your help – ceds Jul 27 '18 at 09:55
  • You are probably wasting your time by trying to microoptimize by eliminating code constructions like functions etc. For my whole life, I did never meet a project where simple function call or other language construction overhead is a bottleneck. Moreover, compiler is smart enough to optimize it all out or inline this function call. Anyway, making your code less readable is not worth 1 saved nanosecond. Software engineering is about making code readable for people, not for machines. – Yeldar Kurmangaliyev Jul 27 '18 at 09:55
  • @PanagiotisKanavos thanks I'll check out BenchmarkDotNet – ceds Jul 27 '18 at 09:57
  • @YeldarKurmangaliyev, the reason why I checked a function call was because my code executes specific function billions of times (it takes up 15% of all runtime). I wanted to see if removing the code from a function will make a difference, when I stumbled upon the unexpected results – ceds Jul 27 '18 at 09:58
  • 1
    @ceds I appreciate it :) It is always right to stay interested, curious and questioning. Good luck with that. – Yeldar Kurmangaliyev Jul 27 '18 at 10:00
  • @JianpingLiu running the two different functions in separate programs gives similar results for me. However when running in one program the results are different – ceds Jul 27 '18 at 10:00
  • I'd be surprised if the loops aren't compiled-out entirely and replaced by simple assignments of immediate (constant) values. I suggest restructuring the test: write two separate programs, each of which runs only one of the variations, and then compare the overall execution times (and ideally then compare the CIL and machine code). This will help preclude 'warming-up' from distorting the numbers. Also, as others have said, it's very unlikely that function-call overhead is going to play any part here. The compiler should have no trouble inlining. – Max Barraclough Jul 27 '18 at 11:32

0 Answers0