mirror of
https://github.com/Facepunch/sbox-public.git
synced 2026-01-16 18:29:15 -05:00
This commit imports the C# engine code and game files, excluding C++ source code. [Source-Commit: ceb3d758046e50faa6258bc3b658a30c97743268]
139 lines
4.8 KiB
C#
139 lines
4.8 KiB
C#
using Sandbox.Engine;
|
|
using System.Threading;
|
|
|
|
namespace Sandbox.Services;
|
|
|
|
/// <summary>
|
|
/// Allows access to stats for the current game. Stats are defined by the game's author
|
|
/// and can be used to track anything from player actions to performance metrics. They are
|
|
/// how you submit data to leaderboards.
|
|
/// </summary>
|
|
public partial class BenchmarkSystem
|
|
{
|
|
private Dictionary<string, BenchmarkRecord> results { get; } = new();
|
|
private List<Sampler> samplers;
|
|
private Dictionary<string, double> metrics = new();
|
|
private Allocations.Scope allocations = new Allocations.Scope();
|
|
|
|
string testName;
|
|
FastTimer timer;
|
|
|
|
public BenchmarkSystem()
|
|
{
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called to start a benchmark
|
|
/// </summary>
|
|
public void Start( string name )
|
|
{
|
|
testName = name;
|
|
|
|
metrics.Clear();
|
|
allocations.Clear();
|
|
|
|
samplers = new()
|
|
{
|
|
new ("Fps", () => 1.0f / Time.Delta ),
|
|
|
|
// PerformanceStats
|
|
new ("ApproximateProcessMemoryUsage", () => PerformanceStats.ApproximateProcessMemoryUsage / (1024.0f * 1024.0f * 1024.0f) ),
|
|
new ("BytesAllocated", () => PerformanceStats.BytesAllocated),
|
|
new ("FrameTimeMs", () => PerformanceStats.FrameTime * 1000.0f ),
|
|
new ("GpuFrametime", () => PerformanceStats.GpuFrametime, () => PerformanceStats.GpuFrameNumber ),
|
|
new ("Gen0Collections", () => PerformanceStats.Gen0Collections ),
|
|
new ("Gen1Collections", () => PerformanceStats.Gen1Collections ),
|
|
new ("Gen2Collections", () => PerformanceStats.Gen2Collections ),
|
|
new ("GcPauseMs", () => TimeSpan.FromTicks( PerformanceStats.GcPause ).Milliseconds ), // Convert to ms so it matches the other timings
|
|
new ("Exceptions", () => PerformanceStats.Exceptions ),
|
|
|
|
// SceneStats
|
|
new( "ObjectsRendered", () => FrameStats._current.ObjectsRendered ),
|
|
new( "TrianglesRendered", () => FrameStats._current.TrianglesRendered ),
|
|
new( "DrawCalls", () => FrameStats._current.DrawCalls ),
|
|
new( "MaterialChanges", () => FrameStats._current.MaterialChanges ),
|
|
new( "DisplayLists", () => FrameStats._current.DisplayLists ),
|
|
new( "SceneViewsRendered", () => FrameStats._current.SceneViewsRendered ),
|
|
new( "RenderTargetResolves", () => FrameStats._current.RenderTargetResolves ),
|
|
new( "ObjectsCulledByVis", () => FrameStats._current.ObjectsCulledByVis ),
|
|
new( "ObjectsCulledByScreenSize", () => FrameStats._current.ObjectsCulledByScreenSize ),
|
|
new( "ObjectsCulledByFade", () => FrameStats._current.ObjectsCulledByFade ),
|
|
new( "ObjectsFading", () => FrameStats._current.ObjectsFading ),
|
|
new( "ShadowedLightsInView", () => FrameStats._current.ShadowedLightsInView ),
|
|
new( "UnshadowedLightsInView", () => FrameStats._current.UnshadowedLightsInView ),
|
|
new( "ShadowMaps", () => FrameStats._current.ShadowMaps ),
|
|
};
|
|
|
|
foreach ( var e in Sandbox.Diagnostics.PerformanceStats.Timings.GetMain() )
|
|
{
|
|
samplers.Add( new( e.Name, () => e.AverageMs( 1 ) ) );
|
|
}
|
|
|
|
timer.Start();
|
|
allocations.Start();
|
|
IGameInstanceDll.Current.ResetSceneListenerMetrics();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set a custom metric, like load time, shutdown time etc
|
|
/// </summary>
|
|
/// <param name="name"></param>
|
|
/// <param name="metric"></param>
|
|
public void SetMetric( string name, double metric )
|
|
{
|
|
metrics[name] = metric;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called to close a benchmark off
|
|
/// </summary>
|
|
public void Finish()
|
|
{
|
|
var elapsedSeconds = timer.ElapsedSeconds;
|
|
allocations.Stop();
|
|
|
|
var benchmarkResult = new BenchmarkRecord();
|
|
benchmarkResult.Name = testName;
|
|
benchmarkResult.Duration = elapsedSeconds;
|
|
benchmarkResult.Data = samplers.ToDictionary( x => x.Name, x => (object)x.GetResults() );
|
|
|
|
benchmarkResult.Data["Alloc"] = allocations.Entries.OrderByDescending( x => x.TotalBytes ).Take( 100 ).ToDictionary( x => x.Name, x => new { x.Count, Size = x.TotalBytes } );
|
|
benchmarkResult.Data["Listeners"] = IGameInstanceDll.Current.GetSceneListenerMetrics();
|
|
|
|
foreach ( var m in metrics )
|
|
{
|
|
benchmarkResult.Data[m.Key] = m.Value;
|
|
}
|
|
|
|
results[testName] = benchmarkResult;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Should be called in update every frame
|
|
/// </summary>
|
|
public void Sample()
|
|
{
|
|
if ( samplers is null )
|
|
return;
|
|
|
|
foreach ( var sampler in samplers )
|
|
{
|
|
sampler.Update();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Finish this benchmark session and send it off to the backend
|
|
/// </summary>
|
|
public Task<Guid> SendAsync( CancellationToken token = default )
|
|
{
|
|
var value = results.Values.ToArray();
|
|
results.Clear();
|
|
allocations?.Stop();
|
|
|
|
return Api.Benchmarks.Post( value, token );
|
|
}
|
|
}
|
|
|