Aracılığıyla paylaş


.NET'te EventCounters

Bu makale şunlar için geçerlidir: ✔️ .NET Core 3.0 SDK ve sonraki sürümler

EventCounters basit, platformlar arası ve neredeyse gerçek zamanlı performans ölçümü toplama için kullanılan .NET API'leridir. EventCounters, Windows üzerinde .NET Framework'ün "performans sayaçlarına" alternatif olarak platformlar arası bir alternatif olarak eklendi. Bu makalede EventCounters'ın ne olduğunu, bunları nasıl uygulayacağınızı ve nasıl tüketeceğinizi öğreneceksiniz.

.NET çalışma zamanı ve birkaç .NET kitaplığı, .NET Core 3.0'dan başlayarak EventCounters kullanarak temel tanılama bilgilerini yayımlar. .NET çalışma zamanı tarafından sağlanan EventCounters dışında kendi EventCounters'larınızı uygulamayı seçebilirsiniz. EventCounters çeşitli ölçümleri izlemek için kullanılabilir. .NET'te iyi bilinen EventCounters'da bunlar hakkında daha fazla bilgi edinin

EventCounters bir EventSourceöğesinin parçası olarak yaşar ve otomatik olarak düzenli olarak dinleyici araçlarına gönderiliyor. üzerindeki EventSourcediğer tüm olaylar gibi bunlar da hem proc içinde hem de eventPipe aracılığıyla EventListenerkullanıma açık olarak kullanılabilir. Bu makale EventCounters'ın platformlar arası özelliklerine odaklanır ve her ikisi de EventCounters ile birlikte kullanılabilse de PerfView ve ETW'yi (Windows için Olay İzleme) kasıtlı olarak dışlar.

EventCounters in-proc ve out-of-proc diagram image

EventCounter API'lerine genel bakış

EventCounters'ın iki birincil kategorisi vardır. Bazı sayaçlar toplam özel durum sayısı, toplam GC sayısı ve toplam istek sayısı gibi "oran" değerlerine yöneliktir. Diğer sayaçlar yığın kullanımı, CPU kullanımı ve çalışma kümesi boyutu gibi "anlık görüntü" değerleridir. Bu sayaç kategorilerinin her birinde, değerlerini nasıl aldıklarına göre değişen iki tür sayaç vardır. Yoklama sayaçları bir geri çağırma yoluyla değerlerini alır ve yoklama olmayan sayaçların değerleri doğrudan sayaç örneğinde ayarlanır.

Sayaçlar aşağıdaki uygulamalarla temsil edilir:

Olay dinleyicisi, ölçüm aralıklarının ne kadar uzun olduğunu belirtir. Her aralığın sonunda, her sayacın dinleyicisine bir değer iletilir. Sayaç uygulamaları, her aralıkta değeri üretmek için hangi API'lerin ve hesaplamaların kullanıldığını belirler.

  • bir EventCounter değer kümesi kaydeder. EventCounter.WriteMetric yöntemi kümeye yeni bir değer ekler. Her aralıkta, küme için min, max ve mean gibi istatistiksel bir özet hesaplanır. dotnet-counters aracı her zaman ortalama değeri görüntüler. EventCounter, ayrık bir işlem kümesini açıklamak için kullanışlıdır. Yaygın kullanım, son GÇ işlemlerinin bayt cinsinden ortalama boyutunu veya bir finansal işlem kümesinin ortalama parasal değerini izlemeyi içerebilir.

  • , IncrementingEventCounter her zaman aralığı için çalışan toplamı kaydeder. IncrementingEventCounter.Increment yöntemi toplama ekler. Örneğin, , 2ve değerleriyle 1bir aralıkta üç kez çağrılırsaIncrement(), çalışan toplamı 8 bu aralığın sayaç değeri 5olarak bildirilir. dotnet-counters aracı, hızı kaydedilen toplam /saat olarak görüntüler. IncrementingEventCounter, saniye başına işlenen istek sayısı gibi bir eylemin ne sıklıkta gerçekleştiğini ölçmek için yararlıdır.

  • , PollingCounter bildirilen değeri belirlemek için bir geri çağırma kullanır. Her zaman aralığında, kullanıcı tarafından sağlanan geri çağırma işlevi çağrılır ve dönüş değeri sayaç değeri olarak kullanılır. , PollingCounter bir dış kaynaktan bir ölçümü sorgulamak için kullanılabilir; örneğin diskte geçerli boş baytları alma. Ayrıca, bir uygulama tarafından isteğe bağlı olarak hesaplanabilen özel istatistikleri raporlamak için de kullanılabilir. Son istek gecikme sürelerinin 95. yüzdebirlik değerini veya önbelleğin geçerli isabet veya yanıtsız oranını raporlama örnekleri verilebilir.

  • , IncrementingPollingCounter bildirilen artım değerini belirlemek için bir geri çağırma kullanır. Her zaman aralığıyla, geri çağırma çağrılır ve ardından geçerli çağrı ile son çağrı arasındaki fark bildirilen değerdir. dotnet-counters aracı, farkı her zaman bir hız( bildirilen değer / saat) olarak görüntüler. Bu sayaç, her oluşumda bir API çağırmak mümkün olmadığında yararlıdır, ancak toplam yineleme sayısını sorgulamak mümkündür. Örneğin, bir bayt her yazışında bildirimde bulunmadan bile bir dosyaya saniyede yazılan bayt sayısını bildirebilirsiniz.

EventSource uygulama

Aşağıdaki kod, adlandırılmış "Sample.EventCounter.Minimal" sağlayıcı olarak kullanıma sunulan bir örneği EventSource uygular. Bu kaynak, istek işleme süresini temsil eden bir EventCounter kaynak içerir. Böyle bir sayacın adı (kaynaktaki benzersiz kimliği) ve her ikisi de dotnet-counters gibi dinleyici araçları tarafından kullanılan bir görünen adı vardır.

using System.Diagnostics.Tracing;

[EventSource(Name = "Sample.EventCounter.Minimal")]
public sealed class MinimalEventCounterSource : EventSource
{
    public static readonly MinimalEventCounterSource Log = new MinimalEventCounterSource();

    private EventCounter _requestCounter;

    private MinimalEventCounterSource() =>
        _requestCounter = new EventCounter("request-time", this)
        {
            DisplayName = "Request Processing Time",
            DisplayUnits = "ms"
        };

    public void Request(string url, long elapsedMilliseconds)
    {
        WriteEvent(1, url, elapsedMilliseconds);
        _requestCounter?.WriteMetric(elapsedMilliseconds);
    }

    protected override void Dispose(bool disposing)
    {
        _requestCounter?.Dispose();
        _requestCounter = null;

        base.Dispose(disposing);
    }
}

İzlenebilen .NET işlemlerinin listesini görüntülemek için kullanırsınız dotnet-counters ps :

dotnet-counters ps
   1398652 dotnet     C:\Program Files\dotnet\dotnet.exe
   1399072 dotnet     C:\Program Files\dotnet\dotnet.exe
   1399112 dotnet     C:\Program Files\dotnet\dotnet.exe
   1401880 dotnet     C:\Program Files\dotnet\dotnet.exe
   1400180 sample-counters C:\sample-counters\bin\Debug\netcoreapp3.1\sample-counters.exe

EventSource Sayacınızı izlemeye başlama seçeneğine adı --counters geçirin:

dotnet-counters monitor --process-id 1400180 --counters Sample.EventCounter.Minimal

Aşağıdaki örnekte izleyici çıkışı gösterilmektedir:

Press p to pause, r to resume, q to quit.
    Status: Running

[Samples-EventCounterDemos-Minimal]
    Request Processing Time (ms)                            0.445

İzleme komutunu durdurmak için q tuşuna basın.

Koşullu sayaçlar

bir EventSourceuygularken, yöntemi değeriyle CommandEventCommand.Enableçağrıldığında EventSource.OnEventCommand içeren sayaçlar koşullu olarak örneklenebilir. Bir sayaç örneğini yalnızca ise nullgüvenli bir şekilde örneklemek için null birleşim atama işlecini kullanın. Ayrıca, özel yöntemler geçerli olay kaynağının IsEnabled etkin olup olmadığını belirlemek için yöntemini değerlendirebilir.

using System.Diagnostics.Tracing;

[EventSource(Name = "Sample.EventCounter.Conditional")]
public sealed class ConditionalEventCounterSource : EventSource
{
    public static readonly ConditionalEventCounterSource Log = new ConditionalEventCounterSource();

    private EventCounter _requestCounter;

    private ConditionalEventCounterSource() { }

    protected override void OnEventCommand(EventCommandEventArgs args)
    {
        if (args.Command == EventCommand.Enable)
        {
            _requestCounter ??= new EventCounter("request-time", this)
            {
                DisplayName = "Request Processing Time",
                DisplayUnits = "ms"
            };
        }
    }

    public void Request(string url, float elapsedMilliseconds)
    {
        if (IsEnabled())
        {
            _requestCounter?.WriteMetric(elapsedMilliseconds);
        }
    }

    protected override void Dispose(bool disposing)
    {
        _requestCounter?.Dispose();
        _requestCounter = null;

        base.Dispose(disposing);
    }
}

İpucu

Koşullu sayaçlar, mikro iyileştirme olarak koşullu olarak örneklenebilen sayaçlardır. Çalışma zamanı, sayaçların normalde kullanılmadığı senaryolarda milisaniyenin bir bölümünü kaydetmek için bu düzeni benimser.

.NET Core çalışma zamanı örnek sayaçları

.NET Core çalışma zamanında birçok harika örnek uygulama vardır. Uygulamanın çalışma kümesi boyutunu izleyen sayacın çalışma zamanı uygulaması aşağıdadır.

var workingSetCounter = new PollingCounter(
    "working-set",
    this,
    () => (double)(Environment.WorkingSet / 1_000_000))
{
    DisplayName = "Working Set",
    DisplayUnits = "MB"
};

Uygulamanın PollingCounter işlemine (çalışma kümesi) eşlenen geçerli fiziksel bellek miktarını raporlar, çünkü bir anda bir ölçüm yakalar. Bir değeri yoklama için geri çağırma, sağlanan lambda ifadesidir ve bu yalnızca API çağrısıdır System.Environment.WorkingSet . DisplayName ve DisplayUnits sayacın tüketici tarafının değeri daha net görüntülemesine yardımcı olacak şekilde ayarlanabilen isteğe bağlı özelliklerdir. Örneğin, dotnet-counters , sayaç adlarının daha kolay görünen sürümünü görüntülemek için bu özellikleri kullanır.

Önemli

DisplayName Özellikler yerelleştirilmemiş.

ve IncrementingPollingCounteriçin PollingCounterbaşka hiçbir şey yapılmasına gerek yoktur. Her ikisi de tüketici tarafından istenen bir aralıkta değerleri kendileri yoklar.

Aşağıda kullanılarak IncrementingPollingCounteruygulanan bir çalışma zamanı sayacı örneği verilmiştir.

var monitorContentionCounter = new IncrementingPollingCounter(
    "monitor-lock-contention-count",
    this,
    () => Monitor.LockContentionCount
)
{
    DisplayName = "Monitor Lock Contention Count",
    DisplayRateTimeScale = TimeSpan.FromSeconds(1)
};

, IncrementingPollingCounter toplam kilit çekişmesi sayısının artışını raporlamak için API'yi kullanır Monitor.LockContentionCount . DisplayRateTimeScale özelliği isteğe bağlıdır, ancak kullanıldığında sayacın en iyi görüntülendiği zaman aralığına ilişkin bir ipucu sağlayabilir. Örneğin, kilit çekişme sayısı en iyi saniye başına sayı olarak görüntülenir, bu nedenle DisplayRateTimeScale bir saniyeye ayarlanır. Görüntüleme hızı, farklı türlerdeki hız sayaçları için ayarlanabilir.

Not

DisplayRateTimeScaledotnet-counters tarafından kullanılmaz ve olay dinleyicilerinin bunu kullanması gerekmez.

.NET çalışma zamanı deposunda başvuru olarak kullanılacak daha fazla sayaç uygulaması vardır.

Eşzamanlılık

İpucu

EventCounters API'si iş parçacığı güvenliğini garanti etmez. veya IncrementingPollingCounter örneklerine PollingCounter geçirilen temsilciler birden çok iş parçacığı tarafından çağrıldığında, temsilcilerin iş parçacığı güvenliğini garanti etmek sizin sorumluluğunuzdadır.

Örneğin, istekleri izlemek için aşağıdakileri EventSource göz önünde bulundurun.

using System;
using System.Diagnostics.Tracing;

public class RequestEventSource : EventSource
{
    public static readonly RequestEventSource Log = new RequestEventSource();

    private IncrementingPollingCounter _requestRateCounter;
    private long _requestCount = 0;

    private RequestEventSource() =>
        _requestRateCounter = new IncrementingPollingCounter("request-rate", this, () => _requestCount)
        {
            DisplayName = "Request Rate",
            DisplayRateTimeScale = TimeSpan.FromSeconds(1)
        };

    public void AddRequest() => ++ _requestCount;

    protected override void Dispose(bool disposing)
    {
        _requestRateCounter?.Dispose();
        _requestRateCounter = null;

        base.Dispose(disposing);
    }
}

AddRequest() yöntemi bir istek işleyicisinden çağrılabilir ve RequestRateCounter değeri sayacın tüketicisi tarafından belirtilen aralıkta yoklar. Ancak, AddRequest() yöntemi aynı anda birden çok iş parçacığı tarafından çağrılabilir ve üzerine _requestCountbir yarış durumu konulabilir. değerini artırmanın _requestCount iş parçacığı açısından güvenli alternatif bir yolu kullanmaktır Interlocked.Increment.

public void AddRequest() => Interlocked.Increment(ref _requestCount);

-field _requestCount komutunun yırtılmış okumalarını (32 bit mimarilerde) longönlemek için kullanınInterlocked.Read.

_requestRateCounter = new IncrementingPollingCounter("request-rate", this, () => Interlocked.Read(ref _requestCount))
{
    DisplayName = "Request Rate",
    DisplayRateTimeScale = TimeSpan.FromSeconds(1)
};

EventCounters kullanma

EventCounter kullanmanın iki birincil yolu vardır: in-proc ve out-of-proc. EventCounters tüketimi, çeşitli tüketen teknolojilerin üç katmanına ayırt edilebilir.

  • ETW veya EventPipe aracılığıyla ham akıştaki olayları taşıma:

    ETW API'leri Windows işletim sistemiyle birlikte gelir ve EventPipe'e .NET API veya tanılama IPC protokolü olarak erişilebilir.

  • İkili olay akışının kodunu olaylara ayırma:

    TraceEvent kitaplığı hem ETW hem de EventPipe akış biçimlerini işler.

  • Komut satırı ve GUI araçları:

    PerfView (ETW veya EventPipe), dotnet-counters (yalnızca EventPipe) ve dotnet-monitor (yalnızca EventPipe) gibi araçlar.

Proc dışında kullanma

EventCounters'ı kullanıma dışında kullanmak yaygın bir yaklaşımdır. Dotnet-counters kullanarak bunları bir EventPipe aracılığıyla platformlar arası bir şekilde kullanabilirsiniz. Araç dotnet-counters , sayaç değerlerini izlemek için kullanılabilecek platformlar arası bir dotnet CLI genel aracıdır. Sayaçlarınızı izlemek için nasıl kullanacağınızı dotnet-counters öğrenmek için dotnet-counters bölümüne bakın veya EventCounters kullanarak performansı ölçme öğreticisi üzerinden çalışın.

dotnet-trace

Araç, dotnet-trace bir EventPipe aracılığıyla sayaç verilerini kullanmak için kullanılabilir. Sayaç verilerini toplamaya yönelik bir örnek dotnet-trace aşağıda verilmiştir.

dotnet-trace collect --process-id <pid> Sample.EventCounter.Minimal:0:0:EventCounterIntervalSec=1

Zaman içinde sayaç değerlerini toplama hakkında daha fazla bilgi için dotnet-trace belgelerine bakın.

Azure Application Insights

EventCounters, Özellikle Azure Uygulaması Analizler Azure İzleyici tarafından kullanılabilir. Sayaçlar eklenebilir ve kaldırılabilir ve özel sayaçlar veya iyi bilinen sayaçlar belirtebilirsiniz. Daha fazla bilgi için bkz . Toplanacak sayaçları özelleştirme.

dotnet-monitor

Araç, dotnet-monitor bir .NET işleminden tanılamaya uzak ve otomatik bir şekilde erişmeyi kolaylaştırır. İzlemelere ek olarak ölçümleri izleyebilir, bellek dökümlerini toplayabilir ve GC dökümlerini toplayabilir. Hem CLI aracı hem de docker görüntüsü olarak dağıtılır. Rest API'yi kullanıma sunar ve tanılama yapıtları koleksiyonu REST çağrıları aracılığıyla gerçekleşir.

Daha fazla bilgi için bkz . dotnet-monitor.

Proc içinde kullanma

Sayaç değerlerini API aracılığıyla EventListener kullanabilirsiniz. , EventListener uygulamanızdaki bir örneğinin tüm örnekleri EventSource tarafından yazılan tüm olayları kullanmanızı sağlar. API'yi kullanma EventListener hakkında daha fazla bilgi için bkz EventListener. .

İlk olarak, EventSource sayaç değerini üreten öğesinin etkinleştirilmesi gerekir. EventListener.OnEventSourceCreated bir oluşturulduğunda bildirim EventSource almak için yöntemini geçersiz kılın ve EventCounters'ınız için doğruysaEventSource, bunu çağırabilirsinizEventListener.EnableEvents. Aşağıda örnek bir geçersiz kılma işlemi verilmiştir:

protected override void OnEventSourceCreated(EventSource source)
{
    if (!source.Name.Equals("System.Runtime"))
    {
        return;
    }

    EnableEvents(source, EventLevel.Verbose, EventKeywords.All, new Dictionary<string, string>()
    {
        ["EventCounterIntervalSec"] = "1"
    });
}

Örnek kod

Burada, iç sayaçlarını (System.Runtime) her saniye yayımlamak için .NET çalışma zamanının EventSourcetüm sayaç adlarını ve değerlerini yazdıran örnek EventListener bir sınıf verilmiştir.

using System;
using System.Collections.Generic;
using System.Diagnostics.Tracing;

public class SimpleEventListener : EventListener
{
    public SimpleEventListener()
    {
    }

    protected override void OnEventSourceCreated(EventSource source)
    {
        if (!source.Name.Equals("System.Runtime"))
        {
            return;
        }

        EnableEvents(source, EventLevel.Verbose, EventKeywords.All, new Dictionary<string, string>()
        {
            ["EventCounterIntervalSec"] = "1"
        });
    }

    protected override void OnEventWritten(EventWrittenEventArgs eventData)
    {
        if (!eventData.EventName.Equals("EventCounters"))
        {
            return;
        }

        for (int i = 0; i < eventData.Payload.Count; ++ i)
        {
            if (eventData.Payload[i] is IDictionary<string, object> eventPayload)
            {
                var (counterName, counterValue) = GetRelevantMetric(eventPayload);
                Console.WriteLine($"{counterName} : {counterValue}");
            }
        }
    }

    private static (string counterName, string counterValue) GetRelevantMetric(
        IDictionary<string, object> eventPayload)
    {
        var counterName = "";
        var counterValue = "";

        if (eventPayload.TryGetValue("DisplayName", out object displayValue))
        {
            counterName = displayValue.ToString();
        }
        if (eventPayload.TryGetValue("Mean", out object value) ||
            eventPayload.TryGetValue("Increment", out value))
        {
            counterValue = value.ToString();
        }

        return (counterName, counterValue);
    }
}

Yukarıda gösterildiği gibi, çağrılırken EnableEventsbağımsız değişkenin "EventCounterIntervalSec" bağımsız değişkende ayarlandığından filterPayload emin olmanız gerekir. Aksi takdirde sayaçlar, hangi aralıkta boşaltılacağını bilmediğinden değerleri boşaltamaz.

Ayrıca bkz.