title: Surprising or wrong benchmarks of Where(predicate).FirstOrDefault() vs FirstOrDefault(predicate)?
body: <p>I know this question has been <a href="https://stackoverflow.com/questions/8059285/c-sharp-linq-whereexpression-firstordefault-vs-firstordefaultexpression">asked</a> <a href="https://stackoverflow.com/questions/9335015/find-vs-where-firstordefault">a lot</a> <a href="https://stackoverflow.com/questions/20394023/difference-between-linq-firstordefault-vs-where-firstordefault">by</a> <a href="https://stackoverflow.com/questions/19842794/wherecondition-firstordefault-vs-firstordefaultcondition">people</a> and some even say</p>
  
  <blockquote>
    <p>So, first(FirstOrDefault(predicate)) one is better in terms of performance<sup><a href="https://stackoverflow.com/a/20394280/3394884">1</a></sup></p>
  </blockquote>
  
  <p>and I get it, I also think that one more method call should be slightly slower, its just intuition that I have. Nevertheless, I decided to run some benchmarks in order to prove my right and boy little did I know.</p>
  
  <p>This is what I had as results of running my benchmarks:</p>
  
  <pre><code>BenchmarkDotNet=v0.12.0, OS=Windows 10.0.18363
  Intel Core i7-3630QM CPU 2.40GHz (Ivy Bridge), 1 CPU, 8 logical and 4 physical cores
  .NET Core SDK=3.1.101
    [Host]     : .NET Core 3.1.1 (CoreCLR 4.700.19.60701, CoreFX 4.700.19.60801), X64 RyuJIT
    Job-XMZTSC : .NET Framework 4.8 (4.8.4121.0), X64 RyuJIT
  Runtime=.NET 4.7.2  
  
  Method                            N      Mean         Error      StdDev    Ratio    RatioSD
  WherePlusFirstOrDefaultArray    10000   31.44 us    0.288 us    0.270 us    0.40    0.00
  FirstOrDefaultArray             10000   78.47 us    0.679 us    0.635 us    1.00    0.00
  WherePlusFirstOrDefaultList     10000   54.27 us    1.070 us    1.099 us    0.69    0.02
  FirstOrDefaultList              10000   100.84 us   1.722 us    1.611 us    1.29    0.02
  WherePlusFirstOrDefaultArray    100000  325.41 us   4.840 us    4.527 us    0.39    0.01
  FirstOrDefaultArray             100000  829.85 us   16.513 us   15.446 us   1.00    0.00
  WherePlusFirstOrDefaultList     100000  558.10 us   5.507 us    5.151 us    0.67    0.01
  FirstOrDefaultList              100000  1,026.93 us 17.648 us   16.508 us   1.24    0.02
  WherePlusFirstOrDefaultArray    1000000 3,255.46 us 9.615 us    7.507 us    0.40    0.01
  FirstOrDefaultArray             1000000 8,134.15 us 108.425 us  101.420 us  1.00    0.00
  WherePlusFirstOrDefaultList     1000000 5,477.63 us 70.584 us   66.024 us   0.67    0.01
  FirstOrDefaultList              1000000 9,987.54 us 64.239 us   60.089 us   1.23    0.02
  </code></pre>
  
  <p>Not only <code>Where(predicate).FirstOrDefault()</code> was faster, but at what margin.</p>
  
  <p>This is my benchmark code using <code>BenchmarkDotNet</code></p>
  
  <pre><code>[SimpleJob(RuntimeMoniker.Net472)]
  public class Benchmarks
  {
      private int[] _array;
      private List&lt;int&gt; _list;
  
      [Params(10000, 100000, 1000000)]
      public int N;
  
      [GlobalSetup]
      public void Setup()
      {
          _array = new int[N];
          _list = new List&lt;int&gt;(N);
  
          _array = Enumerable
              .Repeat(0, N - 1).ToArray();
          _list = Enumerable
              .Repeat(0, N - 1).ToList();
  
          _array[N - 2] = 7;
          _list[N - 2] = 7;
      }
  
      [Benchmark]
      public int WherePlusFirstOrDefaultArray()
      {
          var seven = _array.Where(n =&gt; n == 7).FirstOrDefault();
  
          return seven;
      }
  
      [Benchmark(Baseline = true)]
      public int FirstOrDefaultArray()
      {
          var seven = _array.FirstOrDefault(n =&gt; n == 7);
  
          return seven;
      }
  
      [Benchmark]
      public int WherePlusFirstOrDefaultList()
      {
          var seven = _list.Where(n =&gt; n == 7).FirstOrDefault();
  
          return seven;
      }
  
      [Benchmark]
      public int FirstOrDefaultList()
      {
          var seven = _list.FirstOrDefault(n =&gt; n == 7);
  
          return seven;
      }
  }
  </code></pre>
  
  <p>Since I was stunned from the results leaving me with no other choice but to ask you guys what am I doing wrong or am I missing something?</p>
  
  <hr>
  
  <p>EDIT: </p>
  
  <p>I added benchmarks for array vs list structure to the guys thinking it might be because of the <code>List</code>.</p>
  
  <p>EDIT2:
   The saga continues and I think I am closer to the answer. Adding hardware counter to my benchmark yielded following interesting results:</p>
  
  <pre><code>BenchmarkDotNet=v0.12.0, OS=Windows 10.0.18363
  Intel Core i7-3630QM CPU 2.40GHz (Ivy Bridge), 1 CPU, 8 logical and 4 physical cores
  .NET Core SDK=3.1.101
    [Host]     : .NET Core 3.1.1 (CoreCLR 4.700.19.60701, CoreFX 4.700.19.60801), X64 RyuJIT
    Job-ZTIMEH : .NET Framework 4.8 (4.8.4121.0), X64 RyuJIT
  Runtime=.NET 4.7.2
  
  Method                             N     Mean        Error      StdDev     Ratio    RatioSD CacheMisses/Op  BranchMispredictions/Op
  WherePlusFirstOrDefaultArray    1000000 3.222 ms    0.0224 ms   0.0210 ms    0.39     0.01      885                  327
  FirstOrDefaultArray             1000000 8.166 ms    0.1992 ms   0.1863 ms   1.00      0.00     1,795                 810
  WherePlusFirstOrDefaultList     1000000 5.564 ms    0.1066 ms   0.1228 ms   0.68      0.02     1,051                 503
  FirstOrDefaultList              1000000 10.161 ms   0.1816 ms   0.1699 ms   1.24      0.03     3,451                1,442
  </code></pre>
  
  <p>For some reason, I can't still explain to myself why <code>FirstOrDefault(predicate)</code> method is yielding <em>2 to 3 times</em> more branch mispredictions and ofc cache misses than <code>Where(predicate).FirstOrDefault()</code>, surely this has to play a bit part in the results I am observing previously.</p>
  
  <p>Also, one curious thing, if you look at <code>FirstOrDefaultArray</code> and <code>FirstOrDefaultList</code> results and compare them you will see that list is 24% slower, but assemblies generated by these methods are identical to me: <a href="https://www.diffchecker.com/WSjAQlet" rel="nofollow noreferrer">https://www.diffchecker.com/WSjAQlet</a> (I stripped memory addresses of the instructions.)</p>