<PackageReference Include="System.Diagnostics.DiagnosticSource" Version="9.0.0-preview.7.24405.7" />

RuntimeMetrics

static class RuntimeMetrics
using System.Collections.Generic; using System.Runtime; using System.Runtime.ExceptionServices; using System.Runtime.Versioning; using System.Threading; namespace System.Diagnostics.Metrics { internal static class RuntimeMetrics { [ThreadStatic] private static bool t_handlingFirstChanceException; private static readonly Meter s_meter; private static readonly string[] s_genNames; private static readonly int s_maxGenerations; private static readonly ObservableCounter<long> s_gcCollections; private static readonly ObservableUpDownCounter<long> s_processWorkingSet; private static readonly ObservableCounter<long> s_gcHeapTotalAllocated; private static readonly ObservableUpDownCounter<long> s_gcLastCollectionMemoryCommitted; private static readonly ObservableUpDownCounter<long> s_gcLastCollectionHeapSize; private static readonly ObservableUpDownCounter<long> s_gcLastCollectionFragmentationSize; private static readonly ObservableCounter<double> s_gcPauseTime; private static readonly ObservableCounter<long> s_jitCompiledSize; private static readonly ObservableCounter<long> s_jitCompiledMethodCount; private static readonly ObservableCounter<double> s_jitCompilationTime; private static readonly ObservableCounter<long> s_monitorLockContention; private static readonly ObservableCounter<long> s_threadPoolThreadCount; private static readonly ObservableCounter<long> s_threadPoolCompletedWorkItems; private static readonly ObservableCounter<long> s_threadPoolQueueLength; private static readonly ObservableUpDownCounter<long> s_timerCount; private static readonly ObservableUpDownCounter<long> s_assembliesCount; private static readonly Counter<long> s_exceptions; private static readonly ObservableUpDownCounter<long> s_processCpuCount; private static readonly ObservableCounter<double> s_processCpuTime; static RuntimeMetrics() { s_meter = new Meter("System.Runtime"); s_genNames = new string[5] { "gen0", "gen1", "gen2", "loh", "poh" }; s_maxGenerations = Math.Min(GC.GetGCMemoryInfo().GenerationInfo.Length, s_genNames.Length); s_gcCollections = s_meter.CreateObservableCounter("dotnet.gc.collections", GetGarbageCollectionCounts, "{collection}", "The number of garbage collections that have occurred since the process has started."); s_processWorkingSet = s_meter.CreateObservableUpDownCounter("dotnet.process.memory.working_set", () => Environment.WorkingSet, "By", "The number of bytes of physical memory mapped to the process context."); s_gcHeapTotalAllocated = s_meter.CreateObservableCounter("dotnet.gc.heap.total_allocated", () => GC.GetTotalAllocatedBytes(false), "By", "The approximate number of bytes allocated on the managed GC heap since the process has started. The returned value does not include any native allocations."); s_gcLastCollectionMemoryCommitted = s_meter.CreateObservableUpDownCounter("dotnet.gc.last_collection.memory.committed_size", delegate { GCMemoryInfo gCMemoryInfo = GC.GetGCMemoryInfo(); if (gCMemoryInfo.Index != 0) return new Measurement<long>[1] { new Measurement<long>(gCMemoryInfo.TotalCommittedBytes) }; return Array.Empty<Measurement<long>>(); }, "By", "The amount of committed virtual memory in use by the .NET GC, as observed during the latest garbage collection."); s_gcLastCollectionHeapSize = s_meter.CreateObservableUpDownCounter("dotnet.gc.last_collection.heap.size", GetHeapSizes, "By", "The managed GC heap size (including fragmentation), as observed during the latest garbage collection."); s_gcLastCollectionFragmentationSize = s_meter.CreateObservableUpDownCounter("dotnet.gc.last_collection.heap.fragmentation.size", GetHeapFragmentation, "By", "The heap fragmentation, as observed during the latest garbage collection."); s_gcPauseTime = s_meter.CreateObservableCounter("dotnet.gc.pause.time", () => GC.GetTotalPauseDuration().TotalSeconds, "s", "The total amount of time paused in GC since the process has started."); s_jitCompiledSize = s_meter.CreateObservableCounter("dotnet.jit.compiled_il.size", () => JitInfo.GetCompiledILBytes(false), "By", "Count of bytes of intermediate language that have been compiled since the process has started."); s_jitCompiledMethodCount = s_meter.CreateObservableCounter("dotnet.jit.compiled_methods", () => JitInfo.GetCompiledMethodCount(false), "{method}", "The number of times the JIT compiler (re)compiled methods since the process has started."); s_jitCompilationTime = s_meter.CreateObservableCounter("dotnet.jit.compilation.time", () => JitInfo.GetCompilationTime(false).TotalSeconds, "s", "The number of times the JIT compiler (re)compiled methods since the process has started."); s_monitorLockContention = s_meter.CreateObservableCounter("dotnet.monitor.lock_contentions", () => Monitor.LockContentionCount, "{contention}", "The number of times there was contention when trying to acquire a monitor lock since the process has started."); s_threadPoolThreadCount = s_meter.CreateObservableCounter("dotnet.thread_pool.thread.count", (Func<long>)(() => ThreadPool.ThreadCount), "{thread}", "The number of thread pool threads that currently exist."); s_threadPoolCompletedWorkItems = s_meter.CreateObservableCounter("dotnet.thread_pool.work_item.count", () => ThreadPool.CompletedWorkItemCount, "{work_item}", "The number of work items that the thread pool has completed since the process has started."); s_threadPoolQueueLength = s_meter.CreateObservableCounter("dotnet.thread_pool.queue.length", () => ThreadPool.PendingWorkItemCount, "{work_item}", "The number of work items that are currently queued to be processed by the thread pool."); s_timerCount = s_meter.CreateObservableUpDownCounter("dotnet.timer.count", () => Timer.ActiveCount, "{timer}", "The number of timer instances that are currently active. An active timer is registered to tick at some point in the future and has not yet been canceled."); s_assembliesCount = s_meter.CreateObservableUpDownCounter("dotnet.assembly.count", (Func<long>)(() => AppDomain.CurrentDomain.GetAssemblies().Length), "{assembly}", "The number of .NET assemblies that are currently loaded."); s_exceptions = s_meter.CreateCounter<long>("dotnet.exceptions", "{exception}", "The number of exceptions that have been thrown in managed code."); s_processCpuCount = s_meter.CreateObservableUpDownCounter("dotnet.process.cpu.count", (Func<long>)(() => Environment.ProcessorCount), "{cpu}", "The number of processors available to the process."); s_processCpuTime = ((OperatingSystem.IsBrowser() || OperatingSystem.IsTvOS() || (OperatingSystem.IsIOS() && !OperatingSystem.IsMacCatalyst())) ? null : s_meter.CreateObservableCounter("dotnet.process.cpu.time", GetCpuTime, "s", "CPU time used by the process.")); AppDomain.CurrentDomain.FirstChanceException += delegate(object source, FirstChanceExceptionEventArgs e) { if (!t_handlingFirstChanceException) { t_handlingFirstChanceException = true; s_exceptions.Add(1, new KeyValuePair<string, object>("error.type", e.Exception.GetType().Name)); t_handlingFirstChanceException = false; } }; } public static bool IsEnabled() { if (!s_gcCollections.Enabled && !s_processWorkingSet.Enabled && !s_gcHeapTotalAllocated.Enabled && !s_gcLastCollectionMemoryCommitted.Enabled && !s_gcLastCollectionHeapSize.Enabled && !s_gcLastCollectionFragmentationSize.Enabled && !s_gcPauseTime.Enabled && !s_jitCompiledSize.Enabled && !s_jitCompiledMethodCount.Enabled && !s_jitCompilationTime.Enabled && !s_monitorLockContention.Enabled && !s_timerCount.Enabled && !s_threadPoolThreadCount.Enabled && !s_threadPoolCompletedWorkItems.Enabled && !s_threadPoolQueueLength.Enabled && !s_assembliesCount.Enabled && !s_exceptions.Enabled && !s_processCpuCount.Enabled) return s_processCpuTime?.Enabled ?? false; return true; } private static IEnumerable<Measurement<long>> GetGarbageCollectionCounts() { long num = 0; int num2; for (int gen = GC.MaxGeneration; gen >= 0; gen = num2) { long collectionsFromThisGeneration = GC.CollectionCount(gen); long value = collectionsFromThisGeneration - num; KeyValuePair<string, object> reference = new KeyValuePair<string, object>("gc.heap.generation", s_genNames[gen]); yield return new Measurement<long>(value, new ReadOnlySpan<KeyValuePair<string, object>>(ref reference)); num = collectionsFromThisGeneration; num2 = gen - 1; } } [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("browser")] [SupportedOSPlatform("maccatalyst")] private static IEnumerable<Measurement<double>> GetCpuTime() { Environment.ProcessCpuUsage processCpuUsage = Environment.CpuUsage; TimeSpan timeSpan = processCpuUsage.UserTime; double totalSeconds = timeSpan.TotalSeconds; KeyValuePair<string, object> reference = new KeyValuePair<string, object>("cpu.mode", "user"); yield return new Measurement<double>(totalSeconds, new ReadOnlySpan<KeyValuePair<string, object>>(ref reference)); timeSpan = processCpuUsage.PrivilegedTime; double totalSeconds2 = timeSpan.TotalSeconds; KeyValuePair<string, object> reference2 = new KeyValuePair<string, object>("cpu.mode", "system"); yield return new Measurement<double>(totalSeconds2, new ReadOnlySpan<KeyValuePair<string, object>>(ref reference2)); } private static IEnumerable<Measurement<long>> GetHeapSizes() { GCMemoryInfo gcInfo = GC.GetGCMemoryInfo(); if (gcInfo.Index != 0) { int num; for (int i = 0; i < s_maxGenerations; i = num) { long sizeAfterBytes = gcInfo.GenerationInfo[i].SizeAfterBytes; KeyValuePair<string, object> reference = new KeyValuePair<string, object>("gc.heap.generation", s_genNames[i]); yield return new Measurement<long>(sizeAfterBytes, new ReadOnlySpan<KeyValuePair<string, object>>(ref reference)); num = i + 1; } } } private static IEnumerable<Measurement<long>> GetHeapFragmentation() { GCMemoryInfo gcInfo = GC.GetGCMemoryInfo(); if (gcInfo.Index != 0) { int num; for (int i = 0; i < s_maxGenerations; i = num) { long fragmentationAfterBytes = gcInfo.GenerationInfo[i].FragmentationAfterBytes; KeyValuePair<string, object> reference = new KeyValuePair<string, object>("gc.heap.generation", s_genNames[i]); yield return new Measurement<long>(fragmentationAfterBytes, new ReadOnlySpan<KeyValuePair<string, object>>(ref reference)); num = i + 1; } } } } }