Damageable/Destructible Benchmarks (#41064)
* the fard * oomba * The woke swarm... * Review * review * Apply suggestions from code review --------- Co-authored-by: Princess Cheeseballs <66055347+Pronana@users.noreply.github.com> Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
7dbf084940
commit
3a9bcf1a83
159
Content.Benchmarks/DestructibleBenchmark.cs
Normal file
159
Content.Benchmarks/DestructibleBenchmark.cs
Normal file
@@ -0,0 +1,159 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Threading.Tasks;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using Content.IntegrationTests;
|
||||
using Content.IntegrationTests.Pair;
|
||||
using Content.Server.Destructible;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Damage.Prototypes;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Maps;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.Analyzers;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Benchmarks;
|
||||
|
||||
[Virtual]
|
||||
[GcServer(true)]
|
||||
[MemoryDiagnoser]
|
||||
public class DestructibleBenchmark
|
||||
{
|
||||
/// <summary>
|
||||
/// Number of destructible entities per prototype to spawn with a <see cref="DestructibleComponent"/>.
|
||||
/// </summary>
|
||||
[Params(1, 10, 100, 1000, 5000)]
|
||||
public int EntityCount;
|
||||
|
||||
/// <summary>
|
||||
/// Amount of blunt damage we do to each entity.
|
||||
/// </summary>
|
||||
[Params(10000)]
|
||||
public FixedPoint2 DamageAmount;
|
||||
|
||||
[Params("Blunt")]
|
||||
public ProtoId<DamageTypePrototype> DamageType;
|
||||
|
||||
private static readonly EntProtoId WindowProtoId = "Window";
|
||||
private static readonly EntProtoId WallProtoId = "WallReinforced";
|
||||
private static readonly EntProtoId HumanProtoId = "MobHuman";
|
||||
|
||||
private static readonly ProtoId<ContentTileDefinition> TileRef = "Plating";
|
||||
|
||||
private readonly EntProtoId[] _prototypes = [WindowProtoId, WallProtoId, HumanProtoId];
|
||||
|
||||
private readonly List<Entity<DamageableComponent>> _damageables = new();
|
||||
private readonly List<Entity<DamageableComponent, DestructibleComponent>> _destructbiles = new();
|
||||
|
||||
private DamageSpecifier _damage;
|
||||
|
||||
private TestPair _pair = default!;
|
||||
private IEntityManager _entMan = default!;
|
||||
private IPrototypeManager _protoMan = default!;
|
||||
private IRobustRandom _random = default!;
|
||||
private ITileDefinitionManager _tileDefMan = default!;
|
||||
private DamageableSystem _damageable = default!;
|
||||
private DestructibleSystem _destructible = default!;
|
||||
private SharedMapSystem _map = default!;
|
||||
|
||||
[GlobalSetup]
|
||||
public async Task SetupAsync()
|
||||
{
|
||||
ProgramShared.PathOffset = "../../../../";
|
||||
PoolManager.Startup();
|
||||
_pair = await PoolManager.GetServerClient();
|
||||
var server = _pair.Server;
|
||||
|
||||
var mapdata = await _pair.CreateTestMap();
|
||||
|
||||
_entMan = server.ResolveDependency<IEntityManager>();
|
||||
_protoMan = server.ResolveDependency<IPrototypeManager>();
|
||||
_random = server.ResolveDependency<IRobustRandom>();
|
||||
_tileDefMan = server.ResolveDependency<ITileDefinitionManager>();
|
||||
_damageable = _entMan.System<DamageableSystem>();
|
||||
_destructible = _entMan.System<DestructibleSystem>();
|
||||
_map = _entMan.System<SharedMapSystem>();
|
||||
|
||||
if (!_protoMan.Resolve(DamageType, out var type))
|
||||
return;
|
||||
|
||||
_damage = new DamageSpecifier(type, DamageAmount);
|
||||
|
||||
_random.SetSeed(69420); // Randomness needs to be deterministic for benchmarking.
|
||||
|
||||
var plating = _tileDefMan[TileRef].TileId;
|
||||
|
||||
// We make a rectangular grid of destructible entities, and then damage them all simultaneously to stress test the system.
|
||||
// Needed for managing the performance of destructive effects and damage application.
|
||||
await server.WaitPost(() =>
|
||||
{
|
||||
// Set up a thin line of tiles to place our objects on. They should be anchored for a "realistic" scenario...
|
||||
for (var x = 0; x < EntityCount; x++)
|
||||
{
|
||||
for (var y = 0; y < _prototypes.Length; y++)
|
||||
{
|
||||
_map.SetTile(mapdata.Grid, mapdata.Grid, new Vector2i(x, y), new Tile(plating));
|
||||
}
|
||||
}
|
||||
|
||||
for (var x = 0; x < EntityCount; x++)
|
||||
{
|
||||
var y = 0;
|
||||
foreach (var protoId in _prototypes)
|
||||
{
|
||||
var coords = new EntityCoordinates(mapdata.Grid, x + 0.5f, y + 0.5f);
|
||||
_entMan.SpawnEntity(protoId, coords);
|
||||
y++;
|
||||
}
|
||||
}
|
||||
|
||||
var query = _entMan.EntityQueryEnumerator<DamageableComponent, DestructibleComponent>();
|
||||
|
||||
while (query.MoveNext(out var uid, out var damageable, out var destructible))
|
||||
{
|
||||
_damageables.Add((uid, damageable));
|
||||
_destructbiles.Add((uid, damageable, destructible));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public async Task PerformDealDamage()
|
||||
{
|
||||
await _pair.Server.WaitPost(() =>
|
||||
{
|
||||
_damageable.ApplyDamageToAllEntities(_damageables, _damage);
|
||||
});
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public async Task PerformTestTriggers()
|
||||
{
|
||||
await _pair.Server.WaitPost(() =>
|
||||
{
|
||||
_destructible.TestAllTriggers(_destructbiles);
|
||||
});
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public async Task PerformTestBehaviors()
|
||||
{
|
||||
await _pair.Server.WaitPost(() =>
|
||||
{
|
||||
_destructible.TestAllBehaviors(_destructbiles);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
[GlobalCleanup]
|
||||
public async Task CleanupAsync()
|
||||
{
|
||||
await _pair.DisposeAsync();
|
||||
PoolManager.Shutdown();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using Content.Shared.Damage;
|
||||
|
||||
namespace Content.Server.Destructible;
|
||||
|
||||
public sealed partial class DestructibleSystem
|
||||
{
|
||||
/// <summary>
|
||||
/// Tests all triggers in a DestructibleComponent to see how expensive it is to query them.
|
||||
/// </summary>
|
||||
public void TestAllTriggers(List<Entity<DamageableComponent, DestructibleComponent>> destructibles)
|
||||
{
|
||||
foreach (var (uid, damageable, destructible) in destructibles)
|
||||
{
|
||||
foreach (var threshold in destructible.Thresholds)
|
||||
{
|
||||
// Chances are, none of these triggers will pass!
|
||||
Triggered(threshold, (uid, damageable));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests all behaviours in a DestructibleComponent to see how expensive it is to query them.
|
||||
/// </summary>
|
||||
public void TestAllBehaviors(List<Entity<DamageableComponent, DestructibleComponent>> destructibles)
|
||||
{
|
||||
foreach (var (uid, damageable, destructible) in destructibles)
|
||||
{
|
||||
foreach (var threshold in destructible.Thresholds)
|
||||
{
|
||||
Execute(threshold, uid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,7 @@ using Robust.Shared.Random;
|
||||
namespace Content.Server.Destructible
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public sealed class DestructibleSystem : SharedDestructibleSystem
|
||||
public sealed partial class DestructibleSystem : SharedDestructibleSystem
|
||||
{
|
||||
[Dependency] public readonly IRobustRandom Random = default!;
|
||||
public new IEntityManager EntityManager => base.EntityManager;
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
namespace Content.Shared.Damage;
|
||||
|
||||
public sealed partial class DamageableSystem
|
||||
{
|
||||
/// <summary>
|
||||
/// Applies damage to all entities to see how expensive it is to deal damage.
|
||||
/// </summary>
|
||||
public void ApplyDamageToAllEntities(List<Entity<DamageableComponent>> damageables, DamageSpecifier damage)
|
||||
{
|
||||
foreach (var (uid, damageable) in damageables)
|
||||
{
|
||||
TryChangeDamage(uid, damage, damageable: damageable);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Shared.Damage
|
||||
{
|
||||
public sealed class DamageableSystem : EntitySystem
|
||||
public sealed partial class DamageableSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||
|
||||
Reference in New Issue
Block a user