static void Subtest <TBodyBuilder, TConstraintBuilder, TConstraint>(TBodyBuilder bodyBuilder, TConstraintBuilder constraintBuilder, int width, int height, int length, int frameCount, IThreadDispatcher initializationThreadPool, StreamWriter writer) where TBodyBuilder : IBodyBuilder where TConstraintBuilder : IConstraintBuilder where TConstraint : IConstraintDescription <TConstraint> { const int testsPerVariant = 8; WriteLine(writer, $"{width}x{height}x{length} lattice, {frameCount} frames:"); var timings = new SimulationTimeSamples[Environment.ProcessorCount]; //for (int threadCount = 1; threadCount <= 1; ++threadCount) for (int threadCount = 1; threadCount <= Environment.ProcessorCount; ++threadCount) { var threadPool = new SimpleThreadDispatcher(threadCount); SimulationTimeSamples bestTimings = null; double bestTime = double.MaxValue; for (int i = 0; i < testsPerVariant; ++i) { var candidateTimings = Solve <TBodyBuilder, TConstraintBuilder, TConstraint>(bodyBuilder, constraintBuilder, width, height, length, frameCount, threadCount, initializationThreadPool, threadPool); var totalStats = candidateTimings.Simulation.ComputeStats(); WriteLine(writer, $"{i} AVE: {Math.Round(1e3 * totalStats.Average, 2)}, " + $"MIN: {Math.Round(1e3 * totalStats.Min, 2)}, " + $"MAX: {Math.Round(1e3 * totalStats.Max, 2)}, " + $"STD DEV: {Math.Round(1e3 * totalStats.StdDev, 3)}, "); if (totalStats.Total < bestTime) { bestTime = totalStats.Total; bestTimings = candidateTimings; } } WriteLine(writer, $"{threadCount}T: " + $"{Math.Round(bestTime * 1e3, 2)}, " + $"BOPT: {Math.Round(bestTimings.BodyOptimizer.ComputeStats().Total * 1e3, 2)}, " + $"COPT: {Math.Round(bestTimings.ConstraintOptimizer.ComputeStats().Total * 1e3, 2)}, " + $"BCMP: {Math.Round(bestTimings.BatchCompressor.ComputeStats().Total * 1e3, 2)}, " + $"POIN: {Math.Round(bestTimings.PoseIntegrator.ComputeStats().Total * 1e3, 2)}, " + $"SOLV: {Math.Round(bestTimings.Solver.ComputeStats().Total * 1e3, 2)}"); timings[threadCount - 1] = bestTimings; threadPool.Dispose(); } int fastestIndex = 0; for (int i = 1; i < timings.Length; ++i) { if (timings[i].Simulation.ComputeStats().Total < timings[fastestIndex].Simulation.ComputeStats().Total) { fastestIndex = i; } } WriteLine(writer, $"Scaling: {timings[0].Simulation.ComputeStats().Total / timings[fastestIndex].Simulation.ComputeStats().Total}"); }
public TimingDisplayMode GraphDisplayMode; //Current display mode used by the performance graph //Default Constructor which automatically sets up the graph in Regular timing mode public PerformanceGraph(Font UIFont, SimulationTimeSamples TimeSamples) { DisplayGraph = new Graph(new GraphDescription { BodyLineColor = new Vector3(1, 1, 1), AxisLabelHeight = 16, AxisLineRadius = 0.5f, HorizontalAxisLabel = "Frames", VerticalAxisLabel = "Time (ms)", VerticalIntervalValueScale = 1e3f, VerticalIntervalLabelRounding = 2, BackgroundLineRadius = 0.125f, IntervalTextHeight = 12, IntervalTickRadius = 0.25f, IntervalTickLength = 6f, TargetHorizontalTickCount = 5, HorizontalTickTextPadding = 0, VerticalTickTextPadding = 3, LegendMinimum = new Vector2(20, 200), LegendNameHeight = 12, LegendLineLength = 7, TextColor = new Vector3(1, 1, 1), Font = UIFont, LineSpacingMultiplier = 1f, ForceVerticalAxisMinimumToZero = true }); DisplayGraph.AddSeries("Total", new Vector3(1, 1, 1), 0.75f, TimeSamples.Simulation); DisplayGraph.AddSeries("Pose Integrator", new Vector3(0, 0, 1), 0.25f, TimeSamples.PoseIntegrator); DisplayGraph.AddSeries("Sleeper", new Vector3(0.5f, 0, 1), 0.25f, TimeSamples.Sleeper); DisplayGraph.AddSeries("Broad Update", new Vector3(1, 1, 0), 0.25f, TimeSamples.BroadPhaseUpdate); DisplayGraph.AddSeries("Collision Test", new Vector3(0, 1, 0), 0.25f, TimeSamples.CollisionTesting); DisplayGraph.AddSeries("Narrow Flush", new Vector3(1, 0, 1), 0.25f, TimeSamples.NarrowPhaseFlush); DisplayGraph.AddSeries("Solver", new Vector3(1, 0, 0), 0.5f, TimeSamples.Solver); DisplayGraph.AddSeries("Body Opt", new Vector3(1, 0.5f, 0), 0.125f, TimeSamples.BodyOptimizer); DisplayGraph.AddSeries("Constraint Opt", new Vector3(0, 0.5f, 1), 0.125f, TimeSamples.ConstraintOptimizer); DisplayGraph.AddSeries("Batch Compress", new Vector3(0, 0.5f, 0), 0.125f, TimeSamples.BatchCompressor); }
public static void Test() { const int width = 32; const int height = 32; const int length = 32; SimulationSetup.BuildLattice( new RegularGridWithKinematicBaseBuilder(new Vector3(1), new Vector3()), new BallSocketConstraintBuilder(), width, height, length, out var simulation, out var bodyHandles, out var constraintHandles); var threadDispatcher = new SimpleThreadDispatcher(8); const float inverseDt = 60f; const float dt = 1 / inverseDt; const int iterationCount = 8; const int frameCount = 128; simulation.Solver.IterationCount = iterationCount; simulation.PoseIntegrator.Gravity = new Vector3(0, -10, 0); var samples = new SimulationTimeSamples(frameCount); for (int frameIndex = 0; frameIndex < frameCount; ++frameIndex) { var energyBefore = TestHelpers.GetBodyEnergyHeuristic(simulation.Bodies); //simulation.Timestep(dt); simulation.Timestep(dt, threadDispatcher); samples.RecordFrame(simulation); var energyAfter = TestHelpers.GetBodyEnergyHeuristic(simulation.Bodies); int sampledBodyIndex = width; var samplePose = simulation.Bodies.ActiveSet.Poses[sampledBodyIndex]; var sampleVelocity = simulation.Bodies.ActiveSet.Velocities[sampledBodyIndex]; //for (int i =0; i < simulation.Bodies.BodyCount; ++i) //{ // simulation.Bodies.GetPose(simulation.Bodies.IndexToHandle[i], out var pose); // simulation.Bodies.GetVelocity(simulation.Bodies.IndexToHandle[i], out var velocity); // Console.WriteLine($"Sample {i} position: {pose.Position}, velocity: {velocity.Linear}"); //} Console.WriteLine($"Sample {sampledBodyIndex} position: {samplePose.Position}, velocity: {sampleVelocity.Linear}"); Console.WriteLine($"Body energy {frameIndex}: {energyAfter}, delta: {energyAfter - energyBefore}"); } var multiplier = 1e3 / frameCount; Console.WriteLine($"Simulation time (ms): {multiplier * samples.Simulation.ComputeStats().Total}"); Console.WriteLine($"Body opt time (ms): {multiplier * samples.BodyOptimizer.ComputeStats().Total}"); Console.WriteLine($"Constraint opt time (ms): {multiplier * samples.ConstraintOptimizer.ComputeStats().Total}"); Console.WriteLine($"Batch compress time (ms): {multiplier * samples.BatchCompressor.ComputeStats().Total}"); Console.WriteLine($"Pose integrate time (ms): {multiplier * samples.PoseIntegrator.ComputeStats().Total}"); Console.WriteLine($"Solve time (ms): {multiplier * samples.Solver.ComputeStats().Total}"); threadDispatcher.Dispose(); simulation.BufferPool.Clear(); }
//Constructor which sets up the whole game world scene public GameWorld(GameLoop Loop, ContentArchive Content) { //Store references from the GameLoop class ApplicationWindow = Loop.Window; UserInput = Loop.Input; //Assign the camera reference ObservationCamera.SetCamera(Loop); this.Content = Content; TimeSamples = new SimulationTimeSamples(512, Loop.Pool); UserControls = Controls.Default; //Load font from the content archive var FontContent = Content.Load <FontContent>(@"Carlito-Regular.ttf"); UIFont = new Font(Loop.Surface.Device, Loop.Surface.Context, FontContent); //Position the camera ObservationCamera.PositionCamera(new Vector3(2.7f, 6.48f, 9.76f)); ObservationCamera.FaceCamera(0.269f, 0.15899f); //Setup character controller and world simulation BufferPool = new BufferPool(); ThreadDispatcher = new SimpleThreadDispatcher(Environment.ProcessorCount); World = Simulation.Create(BufferPool, new CharacterNarrowphaseCallbacks(new CharacterControllers(BufferPool)), new ScenePoseIntegratorCallbacks(new Vector3(0, -10, 0))); //Initialize the mesh loader MeshManager.Initialize(Content, BufferPool); //Load in the numbers display the direction of the X/Z axes AxisMarkers.LoadModels(); AxisMarkers.AddModels(World); //Load in the PVP arena ArenaMeshHandle = MeshManager.LoadMesh(@"Arena.obj", new Vector3(1)); //Define its starting position and location Vector3 ArenaPosition = new Vector3(29.82f, 3.62f, 0.94f); Quaternion ArenaRotation = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), Trig.DegreesToRadians(180)); //Use those to add it into the world MeshManager.AddStatic(World, ArenaMeshHandle, ArenaPosition, ArenaRotation); //Place the jumping cubes World.Statics.Add(new StaticDescription(new Vector3(1.299f, 2.3f, -31.24f), new CollidableDescription(World.Shapes.Add(new Box(5, 5, 5)), 0.1f))); World.Statics.Add(new StaticDescription(new Vector3(-26.56f, 2.3f, -35.2f), new CollidableDescription(World.Shapes.Add(new Box(5, 5, 5)), 0.1f))); World.Statics.Add(new StaticDescription(new Vector3(-33.12f, 2.3f, -21.65f), new CollidableDescription(World.Shapes.Add(new Box(5, 5, 5)), 0.1f))); World.Statics.Add(new StaticDescription(new Vector3(-26.05f, 2.3f, -9.38f), new CollidableDescription(World.Shapes.Add(new Box(5, 5, 5)), 0.1f))); World.Statics.Add(new StaticDescription(new Vector3(-10.31f, 2.3f, -5.62f), new CollidableDescription(World.Shapes.Add(new Box(5, 5, 5)), 0.1f))); World.Statics.Add(new StaticDescription(new Vector3(1.94f, 2.3f, -15.88f), new CollidableDescription(World.Shapes.Add(new Box(5, 5, 5)), 0.1f))); World.Statics.Add(new StaticDescription(new Vector3(-11.3f, 2.3f, -37.44f), new CollidableDescription(World.Shapes.Add(new Box(5, 5, 5)), 0.1f))); //Place a ground plane to walk on World.Statics.Add(new StaticDescription(new Vector3(0, -0.5f, 0), new CollidableDescription(World.Shapes.Add(new Box(100, 1, 100)), 0.1f))); //Setup the command executor CommandInputField.Initialize(); //Make sure the window size is correct relative to the current resolution OnResize(ApplicationWindow.Resolution); }
public static SimulationTimeSamples Solve <TBodyBuilder, TConstraintBuilder, TConstraint>(TBodyBuilder bodyBuilder, TConstraintBuilder constraintBuilder, int width, int height, int length, int frameCount, int threadCount, IThreadDispatcher initializationThreadPool, IThreadDispatcher threadDispatcher) where TBodyBuilder : IBodyBuilder where TConstraintBuilder : IConstraintBuilder where TConstraint : IConstraintDescription <TConstraint> { //const int bodyCount = 8; //SimulationSetup.BuildStackOfBodiesOnGround(bodyCount, false, true, out var bodies, out var solver, out var graph, out var bodyHandles, out var constraintHandles); GC.Collect(3, GCCollectionMode.Forced, true); SimulationSetup.BuildLattice( bodyBuilder, constraintBuilder, width, height, length, out var simulation, out var bodyHandles, out var constraintHandles); SimulationScrambling.ScrambleBodies(simulation); SimulationScrambling.ScrambleConstraints(simulation.Solver); SimulationScrambling.ScrambleBodyConstraintLists(simulation); SimulationScrambling.AddRemoveChurn <TConstraint>(simulation, bodyHandles.Length * 2, bodyHandles, constraintHandles); const int batchCompressionIterations = 1000; simulation.SolverBatchCompressor.TargetCandidateFraction = .005f; simulation.SolverBatchCompressor.MaximumCompressionFraction = 0.0005f; for (int i = 0; i < batchCompressionIterations; ++i) { simulation.SolverBatchCompressor.Compress(simulation.BufferPool, initializationThreadPool); } //Attempt cache optimization. int bodyOptimizationIterations = bodyHandles.Length / 4; simulation.BodyLayoutOptimizer.OptimizationFraction = 0.005f; for (int i = 0; i < bodyOptimizationIterations; ++i) { simulation.BodyLayoutOptimizer.IncrementalOptimize(simulation.BufferPool, initializationThreadPool); } simulation.ConstraintLayoutOptimizer.OptimizationFraction = 0.044f; int constraintOptimizationIterations = 1024; for (int i = 0; i < constraintOptimizationIterations; ++i) { simulation.ConstraintLayoutOptimizer.Update(simulation.BufferPool, initializationThreadPool); } var simulationTimeSamples = new SimulationTimeSamples(frameCount); const float dt = 1 / 60f; const int iterationCount = 8; simulation.Solver.IterationCount = iterationCount; for (int frameIndex = 0; frameIndex < frameCount; ++frameIndex) { CacheBlaster.Blast(); simulation.Timestep(dt, threadDispatcher); simulationTimeSamples.RecordFrame(simulation); } simulation.Dispose(); simulation.BufferPool.Clear(); return(simulationTimeSamples); }
public DemoHarness(GameLoop loop, ContentArchive content, Controls?controls = null, DemoSet customDemoSet = null) { this.window = loop.Window; this.input = loop.Input; this.camera = loop.Camera; this.content = content; timeSamples = new SimulationTimeSamples(512, loop.Pool); if (controls == null) { this.controls = Controls.Default; } var fontContent = content.Load <FontContent>(@"Content\Carlito-Regular.ttf"); font = new Font(loop.Surface.Device, loop.Surface.Context, fontContent); timingGraph = new Graph(new GraphDescription { BodyLineColor = new Vector3(1, 1, 1), AxisLabelHeight = 16, AxisLineRadius = 0.5f, HorizontalAxisLabel = "Frames", VerticalAxisLabel = "Time (ms)", VerticalIntervalValueScale = 1e3f, VerticalIntervalLabelRounding = 2, BackgroundLineRadius = 0.125f, IntervalTextHeight = 12, IntervalTickRadius = 0.25f, IntervalTickLength = 6f, TargetHorizontalTickCount = 5, HorizontalTickTextPadding = 0, VerticalTickTextPadding = 3, LegendMinimum = new Vector2(20, 200), LegendNameHeight = 12, LegendLineLength = 7, TextColor = new Vector3(1, 1, 1), Font = font, LineSpacingMultiplier = 1f, ForceVerticalAxisMinimumToZero = true }); timingGraph.AddSeries("Total", new Vector3(1, 1, 1), 0.75f, timeSamples.Simulation); timingGraph.AddSeries("Pose Integrator", new Vector3(0, 0, 1), 0.25f, timeSamples.PoseIntegrator); timingGraph.AddSeries("Sleeper", new Vector3(0.5f, 0, 1), 0.25f, timeSamples.Sleeper); timingGraph.AddSeries("Broad Update", new Vector3(1, 1, 0), 0.25f, timeSamples.BroadPhaseUpdate); timingGraph.AddSeries("Collision Test", new Vector3(0, 1, 0), 0.25f, timeSamples.CollisionTesting); timingGraph.AddSeries("Narrow Flush", new Vector3(1, 0, 1), 0.25f, timeSamples.NarrowPhaseFlush); timingGraph.AddSeries("Solver", new Vector3(1, 0, 0), 0.5f, timeSamples.Solver); timingGraph.AddSeries("Body Opt", new Vector3(1, 0.5f, 0), 0.125f, timeSamples.BodyOptimizer); timingGraph.AddSeries("Constraint Opt", new Vector3(0, 0.5f, 1), 0.125f, timeSamples.ConstraintOptimizer); timingGraph.AddSeries("Batch Compress", new Vector3(0, 0.5f, 0), 0.125f, timeSamples.BatchCompressor); demoSet = customDemoSet ?? new DemoSet().AddDefaultOptions(); demo = demoSet.Build(0, content, camera); OnResize(window.Resolution); }