// Copyright Epic Games, Inc. All Rights Reserved. using HordeServer.Utilities; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using PoolId = HordeServer.Utilities.StringId; using StreamId = HordeServer.Utilities.StringId; namespace HordeServer.Models { /// /// Information about the utilization of a pool /// public interface IUtilizationTelemetry { /// /// Start time for the bucket /// public DateTime StartTime { get; } /// /// Finish time for this bucket /// public DateTime FinishTime { get; } /// /// Number of agents in total /// public int NumAgents { get; } /// /// Breakdown of utilization by pool /// public IReadOnlyList Pools { get; } /// /// Total time spent running administrative tasks (conform, etc...) /// public double AdminTime { get; } } /// /// Concrete implementation of /// public sealed class NewUtilizationTelemetry : IUtilizationTelemetry { /// public DateTime StartTime { get; set; } /// public DateTime FinishTime { get; set; } /// public int NumAgents { get; set; } /// List Pools { get; set; } = new List(); IReadOnlyList IUtilizationTelemetry.Pools => Pools; Dictionary PoolsLookup { get; set; } = new Dictionary(); /// public double AdminTime { get; set; } /// /// Constructor /// /// /// public NewUtilizationTelemetry(DateTime StartTime, DateTime FinishTime) { this.StartTime = StartTime; this.FinishTime = FinishTime; } /// /// Adds a new pool /// /// The pool id /// Telemetry for the given pool public NewPoolUtilizationTelemetry FindOrAddPool(PoolId PoolId) { NewPoolUtilizationTelemetry? Pool; if (!PoolsLookup.TryGetValue(PoolId, out Pool)) { Pool = new NewPoolUtilizationTelemetry(PoolId); Pools.Add(Pool); PoolsLookup.Add(PoolId, Pool); } return Pool; } } /// /// Information about the utilization of a pool /// public interface IPoolUtilizationTelemetry { /// /// Pool containing the work to execute /// public PoolId PoolId { get; } /// /// Number of agents in this pool /// public int NumAgents { get; } /// /// The stream executing work. If this is null, the time accounts for the machine executing work in another pool. /// public IReadOnlyList Streams { get; } /// /// Admount of time spent running /// public double AdminTime { get; } /// /// Amount of time spent by agents in this pool servicing other pools /// public double OtherTime { get; } } /// /// Concrete implementation of /// public sealed class NewPoolUtilizationTelemetry : IPoolUtilizationTelemetry { /// public PoolId PoolId { get; set; } /// public int NumAgents { get; set; } /// List Streams { get; set; } = new List(); IReadOnlyList IPoolUtilizationTelemetry.Streams => Streams; Dictionary StreamLookup { get; set; } = new Dictionary(); /// public double AdminTime { get; set; } /// public double OtherTime { get; set; } /// /// Constructor /// /// public NewPoolUtilizationTelemetry(PoolId PoolId) { this.PoolId = PoolId; } /// /// Adds a stream to the object /// /// public NewPoolUtilizationTelemetryStream FindOrAddStream(StreamId StreamId) { NewPoolUtilizationTelemetryStream? Stream; if (!StreamLookup.TryGetValue(StreamId, out Stream)) { Stream = new NewPoolUtilizationTelemetryStream(StreamId); Streams.Add(Stream); StreamLookup.Add(StreamId, Stream); } return Stream; } } /// /// Utilization of a pool for a particular stream /// public interface IStreamUtilizationTelemetry { /// /// The stream id /// public StreamId StreamId { get; } /// /// Number of machine hours spent executing work for this stream /// public double Time { get; } } /// /// Concrete implementation of /// public sealed class NewPoolUtilizationTelemetryStream : IStreamUtilizationTelemetry { /// public StreamId StreamId { get; set; } /// public double Time { get; set; } /// /// Constructor /// /// public NewPoolUtilizationTelemetryStream(StreamId StreamId) { this.StreamId = StreamId; } } }