Files
UnrealEngine/Engine/Source/Programs/Horde/HordeServer/Server/MetricService.cs
2025-05-18 13:04:45 +08:00

74 lines
3.0 KiB
C#

// Copyright Epic Games, Inc. All Rights Reserved.
using System;
using System.Diagnostics.Metrics;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
namespace HordeServer.Server
{
/// <summary>
/// Periodically send metrics for the CLR and other services that cannot be collected on a per-request basis
/// </summary>
public sealed class MetricService : IHostedService, IDisposable
{
/// <summary>
/// Constructor
/// </summary>
public MetricService(Meter meter)
{
// Force a collection to ensure metrics are populated as some of them require a GC to have been run
GC.Collect();
meter.CreateObservableGauge("horde.clr.threadpool.io.min", () => new ThreadMetrics().IoMin);
meter.CreateObservableGauge("horde.clr.threadpool.io.max", () => new ThreadMetrics().IoMax);
meter.CreateObservableGauge("horde.clr.threadpool.io.free", () => new ThreadMetrics().IoFree);
meter.CreateObservableGauge("horde.clr.threadpool.io.busy", () => new ThreadMetrics().IoBusy);
meter.CreateObservableGauge("horde.clr.threadpool.worker.min", () => new ThreadMetrics().WorkerMin);
meter.CreateObservableGauge("horde.clr.threadpool.worker.max", () => new ThreadMetrics().WorkerMax);
meter.CreateObservableGauge("horde.clr.threadpool.worker.free", () => new ThreadMetrics().WorkerFree);
meter.CreateObservableGauge("horde.clr.threadpool.worker.busy", () => new ThreadMetrics().WorkerBusy);
meter.CreateObservableGauge("horde.clr.gc.totalMemory", () => GC.GetTotalMemory(false));
meter.CreateObservableGauge("horde.clr.gc.totalAllocated", () => GC.GetTotalAllocatedBytes());
meter.CreateObservableGauge("horde.clr.gc.heapSize", () => GC.GetGCMemoryInfo().HeapSizeBytes);
meter.CreateObservableGauge("horde.clr.gc.fragmented", () => GC.GetGCMemoryInfo().FragmentedBytes);
meter.CreateObservableGauge("horde.clr.gc.memoryLoad", () => GC.GetGCMemoryInfo().MemoryLoadBytes);
meter.CreateObservableGauge("horde.clr.gc.totalAvailableMemory", () => GC.GetGCMemoryInfo().TotalAvailableMemoryBytes);
meter.CreateObservableGauge("horde.clr.gc.highMemoryLoadThreshold", () => GC.GetGCMemoryInfo().HighMemoryLoadThresholdBytes);
}
/// <inheritdoc/>
public Task StartAsync(CancellationToken cancellationToken) { return Task.CompletedTask; }
/// <inheritdoc/>
public Task StopAsync(CancellationToken cancellationToken) { return Task.CompletedTask; }
/// <inheritdoc/>
public void Dispose() { }
private struct ThreadMetrics
{
public readonly int WorkerMin;
public readonly int WorkerMax;
public readonly int WorkerFree;
public readonly int WorkerBusy;
public readonly int IoMin;
public readonly int IoMax;
public readonly int IoFree;
public readonly int IoBusy;
public ThreadMetrics()
{
ThreadPool.GetMinThreads(out WorkerMin, out IoMin);
ThreadPool.GetMaxThreads(out WorkerMax, out IoMax);
ThreadPool.GetAvailableThreads(out WorkerFree, out IoFree);
WorkerBusy = WorkerMax - WorkerFree;
IoBusy = WorkerMax - WorkerFree;
}
}
}
}