From d0ac7d0b39134a9a7d847d375f875a041d849bd1 Mon Sep 17 00:00:00 2001
From: Kryyto <69859497+Kryyto@users.noreply.github.com>
Date: Fri, 31 Oct 2025 01:05:31 +0100
Subject: [PATCH] Add a new gas React() benchmark (#41202)
* Add a new gas React() benchmark
* fix the iteration amount to 100, remove unused using
* fix the iteration amount to 1000
---
Content.Benchmarks/GasReactionBenchmark.cs | 253 +++++++++++++++++++++
1 file changed, 253 insertions(+)
create mode 100644 Content.Benchmarks/GasReactionBenchmark.cs
diff --git a/Content.Benchmarks/GasReactionBenchmark.cs b/Content.Benchmarks/GasReactionBenchmark.cs
new file mode 100644
index 0000000000..9ed30373d1
--- /dev/null
+++ b/Content.Benchmarks/GasReactionBenchmark.cs
@@ -0,0 +1,253 @@
+using System.Threading.Tasks;
+using BenchmarkDotNet.Attributes;
+using Content.IntegrationTests;
+using Content.IntegrationTests.Pair;
+using Content.Server.Atmos;
+using Content.Server.Atmos.EntitySystems;
+using Content.Server.Atmos.Reactions;
+using Content.Shared.Atmos;
+using Robust.Shared;
+using Robust.Shared.Analyzers;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Maths;
+
+namespace Content.Benchmarks;
+
+///
+/// Benchmarks the performance of different gas reactions.
+/// Tests each reaction type with realistic gas mixtures to measure computational cost.
+///
+[Virtual]
+[GcServer(true)]
+[MemoryDiagnoser]
+public class GasReactionBenchmark
+{
+ private const int Iterations = 1000;
+ private TestPair _pair = default!;
+ private AtmosphereSystem _atmosphereSystem = default!;
+
+ // Grid and tile for reactions that need a holder
+ private EntityUid _testGrid = default!;
+ private TileAtmosphere _testTile = default!;
+ // Reaction instances
+ private PlasmaFireReaction _plasmaFireReaction = default!;
+ private TritiumFireReaction _tritiumFireReaction = default!;
+ private FrezonProductionReaction _frezonProductionReaction = default!;
+ private FrezonCoolantReaction _frezonCoolantReaction = default!;
+ private AmmoniaOxygenReaction _ammoniaOxygenReaction = default!;
+ private N2ODecompositionReaction _n2oDecompositionReaction = default!;
+ private WaterVaporReaction _waterVaporReaction = default!;
+ // Gas mixtures for each reaction type
+ private GasMixture _plasmaFireMixture = default!;
+ private GasMixture _tritiumFireMixture = default!;
+ private GasMixture _frezonProductionMixture = default!;
+ private GasMixture _frezonCoolantMixture = default!;
+ private GasMixture _ammoniaOxygenMixture = default!;
+ private GasMixture _n2oDecompositionMixture = default!;
+ private GasMixture _waterVaporMixture = default!;
+
+ [GlobalSetup]
+ public async Task SetupAsync()
+ {
+ ProgramShared.PathOffset = "../../../../";
+ PoolManager.Startup();
+ _pair = await PoolManager.GetServerClient();
+ var server = _pair.Server;
+
+ // Create test map and grid
+ var mapData = await _pair.CreateTestMap();
+ _testGrid = mapData.Grid;
+
+ await server.WaitPost(() =>
+ {
+ var entMan = server.ResolveDependency();
+ _atmosphereSystem = entMan.System();
+
+ _plasmaFireReaction = new PlasmaFireReaction();
+ _tritiumFireReaction = new TritiumFireReaction();
+ _frezonProductionReaction = new FrezonProductionReaction();
+ _frezonCoolantReaction = new FrezonCoolantReaction();
+ _ammoniaOxygenReaction = new AmmoniaOxygenReaction();
+ _n2oDecompositionReaction = new N2ODecompositionReaction();
+ _waterVaporReaction = new WaterVaporReaction();
+
+ SetupGasMixtures();
+ SetupTile();
+ });
+ }
+
+ private void SetupGasMixtures()
+ {
+ // Plasma Fire: Plasma + Oxygen at high temperature
+ // Temperature must be > PlasmaMinimumBurnTemperature for reaction to occur
+ _plasmaFireMixture = new GasMixture(Atmospherics.CellVolume)
+ {
+ Temperature = Atmospherics.PlasmaMinimumBurnTemperature + 100f // ~673K
+ };
+ _plasmaFireMixture.AdjustMoles(Gas.Plasma, 20f);
+ _plasmaFireMixture.AdjustMoles(Gas.Oxygen, 100f);
+
+ // Tritium Fire: Tritium + Oxygen at high temperature
+ // Temperature must be > FireMinimumTemperatureToExist for reaction to occur
+ _tritiumFireMixture = new GasMixture(Atmospherics.CellVolume)
+ {
+ Temperature = Atmospherics.FireMinimumTemperatureToExist + 100f // ~473K
+ };
+ _tritiumFireMixture.AdjustMoles(Gas.Tritium, 20f);
+ _tritiumFireMixture.AdjustMoles(Gas.Oxygen, 100f);
+
+ // Frezon Production: Oxygen + Tritium + Nitrogen catalyst
+ // Optimal temperature for efficiency (80% of max efficiency temp)
+ _frezonProductionMixture = new GasMixture(Atmospherics.CellVolume)
+ {
+ Temperature = Atmospherics.FrezonProductionMaxEfficiencyTemperature * 0.8f // ~48K
+ };
+ _frezonProductionMixture.AdjustMoles(Gas.Oxygen, 50f);
+ _frezonProductionMixture.AdjustMoles(Gas.Tritium, 50f);
+ _frezonProductionMixture.AdjustMoles(Gas.Nitrogen, 10f);
+
+ // Frezon Coolant: Frezon + Nitrogen
+ // Temperature must be > FrezonCoolLowerTemperature (23.15K) for reaction to occur
+ _frezonCoolantMixture = new GasMixture(Atmospherics.CellVolume)
+ {
+ Temperature = Atmospherics.T20C + 50f // ~343K
+ };
+ _frezonCoolantMixture.AdjustMoles(Gas.Frezon, 30f);
+ _frezonCoolantMixture.AdjustMoles(Gas.Nitrogen, 100f);
+
+ // Ammonia + Oxygen reaction (concentration-dependent, no temp requirement)
+ _ammoniaOxygenMixture = new GasMixture(Atmospherics.CellVolume)
+ {
+ Temperature = Atmospherics.T20C + 100f // ~393K
+ };
+ _ammoniaOxygenMixture.AdjustMoles(Gas.Ammonia, 40f);
+ _ammoniaOxygenMixture.AdjustMoles(Gas.Oxygen, 40f);
+
+ // N2O Decomposition (no temperature requirement, just needs N2O moles)
+ _n2oDecompositionMixture = new GasMixture(Atmospherics.CellVolume)
+ {
+ Temperature = Atmospherics.T20C + 100f // ~393K
+ };
+ _n2oDecompositionMixture.AdjustMoles(Gas.NitrousOxide, 100f);
+
+ // Water Vapor - needs water vapor to condense
+ _waterVaporMixture = new GasMixture(Atmospherics.CellVolume)
+ {
+ Temperature = Atmospherics.T20C
+ };
+ _waterVaporMixture.AdjustMoles(Gas.WaterVapor, 50f);
+ }
+
+ private void SetupTile()
+ {
+ // Create a tile atmosphere to use as holder for all reactions
+ var testIndices = new Vector2i(0, 0);
+ _testTile = new TileAtmosphere(_testGrid, testIndices, new GasMixture(Atmospherics.CellVolume)
+ {
+ Temperature = Atmospherics.T20C
+ });
+ }
+
+ private static GasMixture CloneMixture(GasMixture original)
+ {
+ return new GasMixture(original);
+ }
+
+ [Benchmark]
+ public async Task PlasmaFireReaction()
+ {
+ await _pair.Server.WaitPost(() =>
+ {
+ for (var i = 0; i < Iterations; i++)
+ {
+ var mixture = CloneMixture(_plasmaFireMixture);
+ _plasmaFireReaction.React(mixture, _testTile, _atmosphereSystem, 1f);
+ }
+ });
+ }
+
+ [Benchmark]
+ public async Task TritiumFireReaction()
+ {
+ await _pair.Server.WaitPost(() =>
+ {
+ for (var i = 0; i < Iterations; i++)
+ {
+ var mixture = CloneMixture(_tritiumFireMixture);
+ _tritiumFireReaction.React(mixture, _testTile, _atmosphereSystem, 1f);
+ }
+ });
+ }
+
+ [Benchmark]
+ public async Task FrezonProductionReaction()
+ {
+ await _pair.Server.WaitPost(() =>
+ {
+ for (var i = 0; i < Iterations; i++)
+ {
+ var mixture = CloneMixture(_frezonProductionMixture);
+ _frezonProductionReaction.React(mixture, _testTile, _atmosphereSystem, 1f);
+ }
+ });
+ }
+
+ [Benchmark]
+ public async Task FrezonCoolantReaction()
+ {
+ await _pair.Server.WaitPost(() =>
+ {
+ for (var i = 0; i < Iterations; i++)
+ {
+ var mixture = CloneMixture(_frezonCoolantMixture);
+ _frezonCoolantReaction.React(mixture, _testTile, _atmosphereSystem, 1f);
+ }
+ });
+ }
+
+ [Benchmark]
+ public async Task AmmoniaOxygenReaction()
+ {
+ await _pair.Server.WaitPost(() =>
+ {
+ for (var i = 0; i < Iterations; i++)
+ {
+ var mixture = CloneMixture(_ammoniaOxygenMixture);
+ _ammoniaOxygenReaction.React(mixture, _testTile, _atmosphereSystem, 1f);
+ }
+ });
+ }
+
+ [Benchmark]
+ public async Task N2ODecompositionReaction()
+ {
+ await _pair.Server.WaitPost(() =>
+ {
+ for (var i = 0; i < Iterations; i++)
+ {
+ var mixture = CloneMixture(_n2oDecompositionMixture);
+ _n2oDecompositionReaction.React(mixture, _testTile, _atmosphereSystem, 1f);
+ }
+ });
+ }
+
+ [Benchmark]
+ public async Task WaterVaporReaction()
+ {
+ await _pair.Server.WaitPost(() =>
+ {
+ for (var i = 0; i < Iterations; i++)
+ {
+ var mixture = CloneMixture(_waterVaporMixture);
+ _waterVaporReaction.React(mixture, _testTile, _atmosphereSystem, 1f);
+ }
+ });
+ }
+
+ [GlobalCleanup]
+ public async Task CleanupAsync()
+ {
+ await _pair.DisposeAsync();
+ PoolManager.Shutdown();
+ }
+}