-
Notifications
You must be signed in to change notification settings - Fork 4.7k
Atmos Delta-Pressure Window Shattering #39238
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Partmedia
merged 71 commits into
space-wizards:master
from
ArtisticRoomba:atmos-delta-pressure
Sep 3, 2025
Merged
Changes from 70 commits
Commits
Show all changes
71 commits
Select commit
Hold shift + click to select a range
2832218
Initial system groundwork
ArtisticRoomba a7203de
Basic AtmosphereSystem and DeltaPressureSystem API
ArtisticRoomba e72f6f2
Initial MVP
ArtisticRoomba 4f7afe9
First round of optimizations
ArtisticRoomba 62ae561
Second round of optimizations
ArtisticRoomba 83fc462
Third round of optimizations
ArtisticRoomba 05720dd
Microfix
ArtisticRoomba 4c27c53
Misc cleanup
ArtisticRoomba f51cf22
lol
ArtisticRoomba 743325f
Cache recently checked tiles
ArtisticRoomba 71f4e3e
Fix tile caching invalidation
ArtisticRoomba 1859583
Implement basic multithreading
ArtisticRoomba 810f36a
Revert "Implement basic multithreading"
ArtisticRoomba a995848
Cleanup, CVAR toggle
ArtisticRoomba 0587ef8
More cleanup and damage logic refac
ArtisticRoomba fc643eb
Move methods in AtmosphereSystem.DeltaPressure.cs over to DeltaPressu…
ArtisticRoomba e7f652f
Expand DeltaPressureSystem.cs API
ArtisticRoomba e89c90e
Add locale
ArtisticRoomba 6015999
Adjust default components
ArtisticRoomba bdeb5e2
Add damage values to windows
ArtisticRoomba 4b4a167
Add damage values to windoors
ArtisticRoomba 5d70985
Add damage values to uranium windows
ArtisticRoomba 4ed6c94
Add damage values to shuttle windows
ArtisticRoomba 1119fc3
Actually enable small damage numbers to be applied
ArtisticRoomba cb1e886
Make most API methods static
ArtisticRoomba 71c4fd5
Add WIP option for window damage randomness
ArtisticRoomba 826d7d4
Do randomness properly this time
ArtisticRoomba 5d8a33e
Address review
ArtisticRoomba a56ff49
base
ArtisticRoomba a76ff69
initial commit
ArtisticRoomba 574bfa5
misc
ArtisticRoomba 89b17ce
misc
ArtisticRoomba 56823f3
fix params
ArtisticRoomba cbd9069
Revert "base"
ArtisticRoomba 40570cf
Parallel solve initial commit
ArtisticRoomba 7c150fe
Merge branch 'atmos/delta-pressure-benchmark' into atmos/delta-pressu…
ArtisticRoomba 08d5b85
misc optimizations
ArtisticRoomba bda1722
tune default vars
ArtisticRoomba 130096e
misc cleanup
ArtisticRoomba f51323a
get rid of DeltaPressureBenchmark.cs
ArtisticRoomba b44953b
Cleanup using directives
ArtisticRoomba 1b374b7
Revert "get rid of DeltaPressureBenchmark.cs"
ArtisticRoomba b898ada
More parallel solve CVARs
ArtisticRoomba c709356
Fix mistake
ArtisticRoomba 6d35510
Merge branch 'atmos/delta-pressure' into atmos/delta-pressure-benchmark
ArtisticRoomba 80bbe23
Modify params
ArtisticRoomba 5fa7af1
Modify API
ArtisticRoomba 4026a31
Fix entity leak
ArtisticRoomba c04bc7a
Fix API for grid ref
ArtisticRoomba 76524f0
Two tests
ArtisticRoomba 3229a24
Merge branch 'atmos/delta-pressure' into atmos/delta-pressure-tests
ArtisticRoomba 3cc527b
directional pressure tests
ArtisticRoomba bd4f067
shitcoded static pressure tests
ArtisticRoomba 3a7548e
cleanup
ArtisticRoomba e03820c
SIMD accel bulk pressure retrieval plus cleanup
ArtisticRoomba 32d23af
Assert on dict/list check for sync
ArtisticRoomba f5e04cb
Fix API and add TODO
ArtisticRoomba 2cf5034
Docs
ArtisticRoomba 339ad47
fix out of bounds issues
ArtisticRoomba cc9da16
improve comments
ArtisticRoomba 25da8d3
fix NaN in bulk processing
ArtisticRoomba d79a793
csgrad
ArtisticRoomba 59a79c0
Merge branch 'atmos/delta-pressure-tests' into atmos/delta-pressure
ArtisticRoomba b6ec066
Merge branch 'atmos/delta-pressure-benchmark' into atmos/delta-pressure
ArtisticRoomba 386a2de
Major benchmarking changes to reduce measurement overhead, microoptim…
ArtisticRoomba 8d43656
Cache current ent pos to prevent relatively expensive indices lookup
ArtisticRoomba 2261975
Address review
ArtisticRoomba 160ba07
Misc fixes
ArtisticRoomba 8dc4c94
Comment fixe
ArtisticRoomba 74b066c
cleanup using directives
ArtisticRoomba 0e14ad1
Adjust default config values
ArtisticRoomba File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,174 @@ | ||
| using System.Threading.Tasks; | ||
| using BenchmarkDotNet.Attributes; | ||
| using BenchmarkDotNet.Diagnosers; | ||
| using Content.IntegrationTests; | ||
| using Content.IntegrationTests.Pair; | ||
| using Content.Server.Atmos.Components; | ||
| using Content.Server.Atmos.EntitySystems; | ||
| using Content.Shared.Atmos.Components; | ||
| using Content.Shared.CCVar; | ||
| using Robust.Shared; | ||
| using Robust.Shared.Analyzers; | ||
| using Robust.Shared.Configuration; | ||
| using Robust.Shared.GameObjects; | ||
| using Robust.Shared.Map; | ||
| using Robust.Shared.Map.Components; | ||
| using Robust.Shared.Maths; | ||
| using Robust.Shared.Prototypes; | ||
| using Robust.Shared.Random; | ||
|
|
||
| namespace Content.Benchmarks; | ||
|
|
||
| /// <summary> | ||
| /// Spawns N number of entities with a <see cref="DeltaPressureComponent"/> and | ||
| /// simulates them for a number of ticks M. | ||
| /// </summary> | ||
| [Virtual] | ||
| [GcServer(true)] | ||
| [MemoryDiagnoser] | ||
| [ThreadingDiagnoser] | ||
| public class DeltaPressureBenchmark | ||
| { | ||
| /// <summary> | ||
| /// Number of entities (windows, really) to spawn with a <see cref="DeltaPressureComponent"/>. | ||
| /// </summary> | ||
| [Params(1, 10, 100, 1000, 5000, 10000, 50000, 100000)] | ||
| public int EntityCount; | ||
|
|
||
| /// <summary> | ||
| /// Number of entities that each parallel processing job will handle. | ||
| /// </summary> | ||
| // [Params(1, 10, 100, 1000, 5000, 10000)] For testing how multithreading parameters affect performance (THESE TESTS TAKE 16+ HOURS TO RUN) | ||
| [Params(10)] | ||
| public int BatchSize; | ||
|
|
||
| /// <summary> | ||
| /// Number of entities to process per iteration in the DeltaPressure | ||
| /// processing loop. | ||
| /// </summary> | ||
| // [Params(100, 1000, 5000, 10000, 50000)] | ||
| [Params(100)] | ||
| public int EntitiesPerIteration; | ||
|
|
||
| private readonly EntProtoId _windowProtoId = "Window"; | ||
| private readonly EntProtoId _wallProtoId = "WallPlastitaniumIndestructible"; | ||
|
|
||
| private TestPair _pair = default!; | ||
| private IEntityManager _entMan = default!; | ||
| private SharedMapSystem _map = default!; | ||
| private IRobustRandom _random = default!; | ||
| private IConfigurationManager _cvar = default!; | ||
| private ITileDefinitionManager _tileDefMan = default!; | ||
| private AtmosphereSystem _atmospereSystem = default!; | ||
|
|
||
| private Entity<GridAtmosphereComponent, GasTileOverlayComponent, MapGridComponent, TransformComponent> | ||
| _testEnt; | ||
|
|
||
| [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>(); | ||
| _map = _entMan.System<SharedMapSystem>(); | ||
| _random = server.ResolveDependency<IRobustRandom>(); | ||
| _cvar = server.ResolveDependency<IConfigurationManager>(); | ||
| _tileDefMan = server.ResolveDependency<ITileDefinitionManager>(); | ||
| _atmospereSystem = _entMan.System<AtmosphereSystem>(); | ||
|
|
||
| _random.SetSeed(69420); // Randomness needs to be deterministic for benchmarking. | ||
|
|
||
| _cvar.SetCVar(CCVars.DeltaPressureParallelToProcessPerIteration, EntitiesPerIteration); | ||
| _cvar.SetCVar(CCVars.DeltaPressureParallelBatchSize, BatchSize); | ||
|
|
||
| var plating = _tileDefMan["Plating"].TileId; | ||
|
|
||
| /* | ||
| Basically, we want to have a 5-wide grid of tiles. | ||
| Edges are walled, and the length of the grid is determined by N + 2. | ||
| Windows should only touch the top and bottom walls, and each other. | ||
| */ | ||
|
|
||
| var length = EntityCount + 2; // ensures we can spawn exactly N windows between side walls | ||
| const int height = 5; | ||
|
|
||
| await server.WaitPost(() => | ||
| { | ||
| // Fill required tiles (extend grid) with plating | ||
| for (var x = 0; x < length; x++) | ||
| { | ||
| for (var y = 0; y < height; y++) | ||
| { | ||
| _map.SetTile(mapdata.Grid, mapdata.Grid, new Vector2i(x, y), new Tile(plating)); | ||
| } | ||
| } | ||
|
|
||
| // Spawn perimeter walls and windows row in the middle (y = 2) | ||
| const int midY = height / 2; | ||
| for (var x = 0; x < length; x++) | ||
| { | ||
| for (var y = 0; y < height; y++) | ||
| { | ||
| var coords = new EntityCoordinates(mapdata.Grid, x + 0.5f, y + 0.5f); | ||
|
|
||
| var isPerimeter = x == 0 || x == length - 1 || y == 0 || y == height - 1; | ||
| if (isPerimeter) | ||
| { | ||
| _entMan.SpawnEntity(_wallProtoId, coords); | ||
| continue; | ||
| } | ||
|
|
||
| // Spawn windows only on the middle row, spanning interior (excluding side walls) | ||
| if (y == midY) | ||
| { | ||
| _entMan.SpawnEntity(_windowProtoId, coords); | ||
| } | ||
| } | ||
| } | ||
| }); | ||
|
|
||
| // Next we run the fixgridatmos command to ensure that we have some air on our grid. | ||
| // Wait a little bit as well. | ||
| // TODO: Unhardcode command magic string when fixgridatmos is an actual command we can ref and not just | ||
| // a stamp-on in AtmosphereSystem. | ||
| await _pair.WaitCommand("fixgridatmos " + mapdata.Grid.Owner, 1); | ||
|
|
||
| var uid = mapdata.Grid.Owner; | ||
| _testEnt = new Entity<GridAtmosphereComponent, GasTileOverlayComponent, MapGridComponent, TransformComponent>( | ||
| uid, | ||
| _entMan.GetComponent<GridAtmosphereComponent>(uid), | ||
| _entMan.GetComponent<GasTileOverlayComponent>(uid), | ||
| _entMan.GetComponent<MapGridComponent>(uid), | ||
| _entMan.GetComponent<TransformComponent>(uid)); | ||
| } | ||
|
|
||
| [Benchmark] | ||
| public async Task PerformFullProcess() | ||
| { | ||
| await _pair.Server.WaitPost(() => | ||
| { | ||
| while (!_atmospereSystem.RunProcessingStage(_testEnt, AtmosphereProcessingState.DeltaPressure)) { } | ||
| }); | ||
| } | ||
|
|
||
| [Benchmark] | ||
| public async Task PerformSingleRunProcess() | ||
| { | ||
| await _pair.Server.WaitPost(() => | ||
| { | ||
| _atmospereSystem.RunProcessingStage(_testEnt, AtmosphereProcessingState.DeltaPressure); | ||
| }); | ||
| } | ||
|
|
||
| [GlobalCleanup] | ||
| public async Task CleanupAsync() | ||
| { | ||
| await _pair.DisposeAsync(); | ||
| PoolManager.Shutdown(); | ||
| } | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should not be a magic number, or at least this should match the default in the component, which is also a magic number currently set at 50. I have also said this multiple times, but 10 or 50 sound way too small. Can you profile this and determine what a "good" batch size is?
I have also said multiple times that this needs to be plotted against the number of parallel jobs on the x axis, not the number of entities. We already know it scales linearly with the number of entities.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Also not a blocking issue -- it's good enough that we have a benchmark in the first place.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let me go ahead and do some more profiling now that I have a better understanding of what we're looking for
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to be clear -- we are trying to use profiling to determine the best batch size and iteration size for a representative but high-ish end of entities, e.g. the number of entities that you can reasonably expect on a large map x2.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, I'm doing more profiling but I'll at least show what I've got so far: a really, really, shit chart. Sorry you have to look at it. But it does give us insights, and I'll get some more soon. All graphs are for
PerformFullProcess.Bear with me:
This is a similar case for processing 100,000 entities:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for doing this.
So, if I'm interpreting this correctly, it seems like a (small to me) batch size of 10 is actually the optimal batch size? If so, we should set the default to that.
I would still be curious in seeing how performance changes with respect to the number of parallel jobs. But that can be done at a later time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Default set. Still scratching my head on the parallelism speedup in general, but I'll probably spend some time reading up on it later.