Implement process CPU usage measurement

This commit is contained in:
Jordan Dominion
2025-02-16 17:35:41 -05:00
parent a9c0832de3
commit c25b9f1997
3 changed files with 63 additions and 1 deletions
@@ -519,6 +519,10 @@ namespace Tgstation.Server.Host.Components.Session
return process.CreateDump(outputFile, minidump, cancellationToken);
}
/// <inheritdoc />
public double MeasureProcessorTimeDelta()
=> process.MeasureProcessorTimeDelta();
/// <summary>
/// The <see cref="Task{TResult}"/> for <see cref="LaunchResult"/>.
/// </summary>
@@ -24,6 +24,12 @@ namespace Tgstation.Server.Host.System
/// </summary>
long? MemoryUsage { get; }
/// <summary>
/// Gets the estimated CPU usage fraction of the process based on the last time this was called.
/// </summary>
/// <returns>The CPU's estimated usage as a value between 0 and 1.</returns>
double MeasureProcessorTimeDelta();
/// <summary>
/// Set's the owned <see cref="global::System.Diagnostics.Process.PriorityClass"/> to a non-normal value.
/// </summary>
+53 -1
View File
@@ -1,4 +1,4 @@
using System;
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
@@ -87,6 +87,26 @@ namespace Tgstation.Server.Host.System
/// </summary>
readonly Task<string?>? readTask;
/// <summary>
/// <see langword="lock"/> object for measuring processor time usage.
/// </summary>
readonly object processTimeMeasureLock;
/// <summary>
/// The last time <see cref="MeasureProcessorTimeDelta"/> was called.
/// </summary>
DateTimeOffset lastProcessorMeasureTime;
/// <summary>
/// The last value of <see cref="global::System.Diagnostics.Process.TotalProcessorTime"/>.
/// </summary>
TimeSpan lastProcessorUsageTime;
/// <summary>
/// The last valid return value of <see cref="MeasureProcessorTimeDelta"/>.
/// </summary>
double lastProcessorUsageEstimation;
/// <summary>
/// If the <see cref="Process"/> was disposed.
/// </summary>
@@ -123,6 +143,8 @@ namespace Tgstation.Server.Host.System
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
processTimeMeasureLock = new object();
Lifetime = WrapLifetimeTask();
if (preExisting)
@@ -147,6 +169,8 @@ namespace Tgstation.Server.Host.System
DefaultIOManager.BlockingTaskCreationOptions,
TaskScheduler.Current);
MeasureProcessorTimeDelta();
logger.LogTrace("Created process ID: {pid}", Id);
}
@@ -267,6 +291,34 @@ namespace Tgstation.Server.Host.System
return processFeatures.CreateDump(handle, outputFile, minidump, cancellationToken);
}
/// <inheritdoc />
public double MeasureProcessorTimeDelta()
{
lock (processTimeMeasureLock)
{
try
{
var now = DateTimeOffset.UtcNow;
var newTime = handle.TotalProcessorTime;
var timeDelta = now - lastProcessorMeasureTime;
var newUsage = newTime - lastProcessorUsageTime;
lastProcessorMeasureTime = now;
lastProcessorUsageTime = newTime;
if (timeDelta != TimeSpan.Zero)
lastProcessorUsageEstimation = newUsage / (Environment.ProcessorCount * timeDelta);
}
catch (Exception ex)
{
logger.LogWarning(ex, "Error measuring processor time delta!");
}
return lastProcessorUsageEstimation;
}
}
/// <summary>
/// Attaches a log message to the process' exit event.
/// </summary>