Search code examples
c#.netperformance-testing.net-fiddle

Why is internal .NET method so much faster than simpler code copied from .NET open source?


I have following code based on this question. Fiddle here. https://dotnetfiddle.net/vchYHj

using System;
using System.Diagnostics;
public class Program
{
    public static void Main()
    {
        ReadOnlySpan<byte> r = stackalloc byte[] { 52, 48, 48, 55, 48 };
        var sw = new Stopwatch();
        int result = 0;


        sw.Restart();
        for (int i=0; i<10000000; i++) result =  Test1(r);
        sw.Stop();
        Console.WriteLine($"Test1 took {sw.ElapsedMilliseconds}ms {result}");


        sw.Restart();
        for (int i=0; i<10000000; i++) result = Test2(r);
        sw.Stop();
        Console.WriteLine($"Test2 took {sw.ElapsedMilliseconds}ms {result}");

    }

    public static int Test1(ReadOnlySpan<byte> source)
    {
        int answer = 0;
        int index = 0;
        int c = source[index];
        answer = c - '0';
        while (true)
        {
            index++;
            if ((uint)index >= (uint)source.Length)
                break;
            c = source[index];
            answer = answer * 10 + c - '0';
        }
         return answer;
    }
    
    public static int Test2(ReadOnlySpan<byte> data)
    {
        if (System.Buffers.Text.Utf8Parser.TryParse(data, out int value, out int bytes))
        {
            return(value);
        }   
        else
            return(0);
    }
}

Test1 took 244ms 40070
Test2 took 99ms 40070

Why is the second method Test1 so much slower on .NET fiddle, when it is copied exactly from .NET open source and is even much simpler?

https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Unsigned.N.cs#L53


Solution

  • Why is the second method Test1 so much slower on .NET fiddle,

    One reason would be that code compiled by .NET fiddle code is not optimized. As a simple example, consider that the following code

    #if DEBUG
        Console.WriteLine("DEBUG");
    #else
        Console.WriteLine("RELEASE");
    #endif
    

    will print DEBUG when executed with .NET fiddle.

    If you want to do benchmarks, I recommend reading Eric Lippert's blog series on that topic first. Benchmarking the Debug build instead of the Release build is just one of the common mistakes listed there.