Runtime: Add EventCounter for ArrayPoolEventSource

Created on 14 Aug 2020  路  10Comments  路  Source: dotnet/runtime

I've been doing some performance investigation recently around how ASP.NET Core uses the ArrayPool and it would be great to have some counters for the existing events:

  • BuffersAllocated
  • BuffersRented
  • BuffersReturned

cc @noahfalk @adamsitnik

area-System.Buffers enhancement

Most helpful comment

Can we do a performance test to make sure?

Here you go:

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

class Program
{
    static int rents;
    static int returns;

    static void Work()
    {
        for (int i = 0; i < 100000000; i++)
        {
            Interlocked.Increment(ref rents);
            var a = ArrayPool<byte>.Shared.Rent(100);
            for (int j = 0; j < 100; j++) a[j] = (byte)j;
            Interlocked.Increment(ref returns);
            ArrayPool<byte>.Shared.Return(a);
        }
    }

    static void Main(string[] args)
    {
        for (int i = 0; i < Environment.ProcessorCount - 1; i++)
            new Thread(Work).Start();
        Stopwatch sw = new Stopwatch();
        sw.Start();
        Work();
        sw.Stop();
        Console.WriteLine(sw.ElapsedMilliseconds);
    }
}

On my Surfacebook:

Without Interlock.Increments: 13348ms
With Interlocked.Increments: 33192ms

The difference will be even more on higher end server machine.

All 10 comments

Tagging subscribers to this area: @tannergooding, @pgovind
See info in area-owners.md if you want to be subscribed.

@davidfowl have you tried using ArrayPool EventSource ?

It's not enabled in PerfView by default so when using PerfView you have to put its name like this before starting the collection:

obraz

@adamsitnik 馃槉 Yes I know how to add custom providers in perfview and using dotnet trace. I'm specifically asking for event counters though.

This would be pretty expensive non-pay-for-play counter. We do not have counter that tracks number of regular objects allocated either.

This would be pretty expensive non-pay-for-play counter. We do not have counter that tracks number of regular objects allocated either.

Wait why would it be expensive? Counting using interlocked in this code path is too expensive?

Counting using interlocked in this code path is too expensive?

Yes!

@jkotas Can we do a performance test to make sure? I believe you, but we should measure the overhead before we do something more complex.

I assumed @davidfowl was seeking a counter that would only track the count when someone enabled this provider. The only cost we'd pay by default would be the log.IsEnabled() check returning false and skipping the remainder of the logic, which is already a cost we incur now.

Can we do a performance test to make sure?

Here you go:

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

class Program
{
    static int rents;
    static int returns;

    static void Work()
    {
        for (int i = 0; i < 100000000; i++)
        {
            Interlocked.Increment(ref rents);
            var a = ArrayPool<byte>.Shared.Rent(100);
            for (int j = 0; j < 100; j++) a[j] = (byte)j;
            Interlocked.Increment(ref returns);
            ArrayPool<byte>.Shared.Return(a);
        }
    }

    static void Main(string[] args)
    {
        for (int i = 0; i < Environment.ProcessorCount - 1; i++)
            new Thread(Work).Start();
        Stopwatch sw = new Stopwatch();
        sw.Start();
        Work();
        sw.Stop();
        Console.WriteLine(sw.ElapsedMilliseconds);
    }
}

On my Surfacebook:

Without Interlock.Increments: 13348ms
With Interlocked.Increments: 33192ms

The difference will be even more on higher end server machine.

Setting this as 6.0.0 since I'm not seeing this meet the bar at the moment.

Was this page helpful?
0 / 5 - 0 ratings