Skip to content

Improve performance of callback handling #399

Closed

Description

@ikkentim

Benchmark:

public class BenchmarkNatives
{
    [NativeMethod] 
    public virtual void CallRemoteFunction(string func, string format, params object[] args)
    {
        throw new NativeNotImplementedException();
    }
}

public class GameMode : BaseMode
{
    private (string, int, float)? _benchStore;

    protected override void OnInitialized(EventArgs e)
    {
        base.OnInitialized(e);

        // (...)

        Console.WriteLine("Bench start");
        RunCallbackBenchmark();
    }

    private void RunCallbackBenchmark()
    {
        var natives = NativeObjectProxyFactory.CreateInstance<BenchmarkNatives>();
        var args = new object[] { "stringValue", 4321, 23.665f };
        var sw = new Stopwatch();
        
        const int maxRuns = 10;
        const int runCallCount = 1_000_000;

        var totalElapsed = TimeSpan.Zero;
        for (var j = 0; j <= maxRuns; j++)
        {
            Console.WriteLine($"Bench run {j}/{maxRuns}");
            if (j == 0) Console.WriteLine("(warmup)");

            sw.Restart();

            for (var i = 0; i < runCallCount; i++)
            {
                natives.CallRemoteFunction("BenchmarkCallback", "sdf", args);

                // validate
                
                if (!_benchStore.HasValue || _benchStore.Value.Item1 != "stringValue" ||
                    _benchStore.Value.Item2 != 4321 || Math.Abs(_benchStore.Value.Item3 - 23.665f) > 0.001f)
                {
                    throw new InvalidOperationException("native call failed!");
                }

                _benchStore = null;
            }

            sw.Stop();

            if (j > 0)
                totalElapsed += sw.Elapsed;
            Console.WriteLine($"{runCallCount} calls took {sw.Elapsed}");
        }

        Console.WriteLine($"AVG of {totalElapsed / maxRuns}");
    }

    [Callback]
    public void BenchmarkCallback(string stringValue, int intValue, float floatValue)
    {
        _benchStore = (stringValue, intValue, floatValue);
    }
}

Activity

  1. added this to the 0.11.0 milestone on Mar 30, 2022
  2. self-assigned this
    on Mar 30, 2022
  3. ikkentim commented on Mar 30, 2022

    @ikkentim
    OwnerAuthor

    a538257 performance. compiled plugin and .net libraries in release mode:

    • run 1. AVG of 00:00:00.2062383
    • run 2. AVG of 00:00:00.2036138
    • run 3. AVG of 00:00:00.2028090
    • run 4. AVG of 00:00:00.2046089
    • run 5. AVG of 00:00:00.2049936
  4. ikkentim commented on Mar 31, 2022

    @ikkentim
    OwnerAuthor

    changed benchmark to perform 1_000_000 instead of 100_000 in 9649ad6

    benchmark times are:

    AVG of 00:00:02.0727976
    AVG of 00:00:02.0378712
    AVG of 00:00:02.0661319
    
  5. ikkentim commented on Mar 31, 2022

    @ikkentim
    OwnerAuthor
    • Updated to .NET 6.0
    • Added [UnmanagedOnlyAttribute] entrypoints for ticks and public calls
    • Changed from callbackmapping + callback argument streams on plugin side to fully marshaling on the managed side

    1179c63

    benchmark times are:

    AVG of 00:00:01.5029470
    AVG of 00:00:01.4856173
    AVG of 00:00:01.5092219
    

    So that looks like a (1 - 150 ÷ 205 =) ~27% performance improvement already

  6. ikkentim commented on Apr 2, 2022

    @ikkentim
    OwnerAuthor

    Also tested this on an Ubuntu VM @ 4a55771

    AVG of 00:00:01.7994443
    AVG of 00:00:01.7907788
    AVG of 00:00:01.7601093
    

    When tested on master branch @ 9649ad6

    AVG of 00:00:02.5606534
    AVG of 00:00:02.5192036
    AVG of 00:00:02.5845466
    

    So that also looks like a (1 - 1,78344 / 2,5548 =) ~30% performance improvement

  7. ikkentim commented on Apr 8, 2022

    @ikkentim
    OwnerAuthor

    Good enough for now, merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions