Home icon indicating copy to clipboard operation
Home copied to clipboard

Improve performances for TestFramework and Json

Open Ellerbach opened this issue 3 years ago • 4 comments

Improve performances for type comparisons especially in Test Framework and Json classes but for sure used in few other plances.

Details about Problem

nanoFramework area: ( Other tools )

VS version:

VS extension version:

Target:

Firmware image version:

Description

So far all type comparisons in Test Framework (eg here: ) and in Json (eg here: ) are using strings. They should use typeof instead.

Using typeof on the following simple sample shows a performance improvement by 2 times. The first loop, using string took 1000 ms to execute on an ESP32. The second loop using typeof only uses 510 ms.

Memory wise, typeof will return a singleton on the system types, so there is no additional footprint neither other performance penalty.

We should consider moving from string comparisons to typeof.

using System;
using System.Diagnostics;
using System.Threading;

Debug.WriteLine("Hello from nanoFramework!");

object[] array = new object[5];

array[0] = (int)42;
array[1] = (byte)42;
array[2] = "This is a super string";
array[3] = (ulong)42;
array[4] = new Version(4, 2);

Stopwatch sw = Stopwatch.StartNew();
for (int loop = 0; loop < 100; loop++)
{
    for (int i = 0; i < array.Length; i++)
    {
        object obja = array.GetValue(i);
        var typea = obja.GetType();

        CompareUsingString(typea);
    }
}

sw.Stop();
Console.WriteLine("------------------");
Console.WriteLine($"Total time: {sw.ElapsedMilliseconds}");

sw = Stopwatch.StartNew();
for (int loop = 0; loop < 100; loop++)
{
    for (int i = 0; i < array.Length; i++)
    {
        object obja = array.GetValue(i);
        var typea = obja.GetType();

        CompareUsingTypeof(typea);
    }
}

sw.Stop();
Console.WriteLine("------------------");
Console.WriteLine($"Total time: {sw.ElapsedMilliseconds}");

void CompareUsingString(Type typea)
{
    switch (typea.FullName)
    {
        case "System.Int32":
            Console.WriteLine("System.Int32");
            break;
        case "System.UInt32":
            Console.WriteLine("System.UInt32");
            break;
        case "System.Byte":
            Console.WriteLine("System.Byte");
            break;
        case "System.SByte":
            Console.WriteLine("System.SByte");
            break;
        case "System.Int16":
            Console.WriteLine("System.Int16");
            break;
        case "System.UInt16":
            Console.WriteLine("System.UInt16");
            break;
        case "System.Int64":
            Console.WriteLine("System.Int64");
            break;
        case "System.UInt64":
            Console.WriteLine("System.UInt64");
            break;
        case "System.Char":
            Console.WriteLine("System.Char");
            break;
        case "System.Double":
            Console.WriteLine("System.Double");
            break;
        case "System.Boolean":
            Console.WriteLine("System.Boolean");
            break;
        case "System.Single":
            Console.WriteLine("System.Single");
            break;
        default:
            Console.WriteLine("Non system type");
            break;
    }
}

void CompareUsingTypeof(Type typea)
{
    if (typea == typeof(int))
    {
        Console.WriteLine("System.Int32");
    }
    else if (typea == typeof(uint))
    {
        Console.WriteLine("System.UInt32");
    }
    else if (typea == typeof(byte))
    {
        Console.WriteLine("System.Byte");
    }
    else if (typea == typeof(sbyte))
    {
        Console.WriteLine("System.SByte");
    }
    else if (typea == typeof(short))
    {
        Console.WriteLine("System.Int16");
    }
    else if (typea == typeof(ushort))
    {
        Console.WriteLine("System.UInt16");
    }
    else if (typea == typeof(long))
    {
        Console.WriteLine("System.Int64");
    }
    else if (typea == typeof(ulong))
    {
        Console.WriteLine("System.UInt64");
    }
    else if (typea == typeof(char))
    {
        Console.WriteLine("System.Char");
    }
    else if (typea == typeof(double))
    {
        Console.WriteLine("System.Double");
    }
    else if (typea == typeof(bool))
    {
        Console.WriteLine("System.Boolean");
    }
    else if (typea == typeof(float))
    {
        Console.WriteLine("System.Single");
    }
    else
    {
        Console.WriteLine("Non system type");
    }
}

Thread.Sleep(Timeout.Infinite);

Ellerbach avatar Aug 22 '22 13:08 Ellerbach

@Ellerbach Hope you haven't start working on it. I've played a little bit with benchmark tool, just to see how it's working in real example. So I've checked every unit test in Json lib and created benchmarks based on them. I've tried to avoide duplications in benchmarks, so not every unit test was moved. Here are results: image

Few more left to do:

  • Benchmark lib as nuget 😅
  • Extend ReferenceTypesSerializationBenchmark class
  • Increase sample count in one iteration (there is a lot of results in range of 0 to 20 ms)

After that we should get a solid baseline for further improvements.

Also, I've found few minor bugs in deserialization 😅

torbacz avatar Sep 02 '22 17:09 torbacz

So great! Just can't wait :-D

Ellerbach avatar Sep 05 '22 09:09 Ellerbach

@Ellerbach Let me do it :) I'm already working on refactoring JSON lib, I've extracted all type compare to single method, so should be easy to change. Also I'll take care of test framework.

torbacz avatar Sep 08 '22 16:09 torbacz

@josesimoes Reopening, still need JSON part.

torbacz avatar Sep 21 '22 08:09 torbacz