protected Demo(DemosGame game) { Game = game; parallelLooper = new ParallelLooper(); //This section lets the engine know that it can make use of multithreaded systems //by adding threads to its thread pool. #if XBOX360 parallelLooper.AddThread(delegate { Thread.CurrentThread.SetProcessorAffinity(new[] { 1 }); }); parallelLooper.AddThread(delegate { Thread.CurrentThread.SetProcessorAffinity(new[] { 3 }); }); parallelLooper.AddThread(delegate { Thread.CurrentThread.SetProcessorAffinity(new[] { 4 }); }); parallelLooper.AddThread(delegate { Thread.CurrentThread.SetProcessorAffinity(new[] { 5 }); }); #else if (Environment.ProcessorCount > 1) { for (int i = 0; i < Environment.ProcessorCount; i++) { parallelLooper.AddThread(); } } #endif Space = new Space(parallelLooper); game.Camera.LockedUp = Vector3.Up; game.Camera.ViewDirection = new Vector3(0, 0, -1); }
public void BuildWorld() { MainThread = Thread.CurrentThread; MainThreadID = MainThread.ManagedThreadId; ParallelLooper pl = new ParallelLooper(); for (int i = 0; i < Environment.ProcessorCount; i++) { pl.AddThread(); } CollisionDetectionSettings.AllowedPenetration = 0.01f; PhysicsWorld = new Space(pl); PhysicsWorld.TimeStepSettings.MaximumTimeStepsPerFrame = 10; PhysicsWorld.ForceUpdater.Gravity = new Vector3(0, 0, -9.8f * 3f / 2f); PhysicsWorld.DuringForcesUpdateables.Add(new LiquidVolume(this)); PhysicsWorld.TimeStepSettings.TimeStepDuration = 1f / TheServer.CVars.g_fps.ValueF; Collision = new CollisionUtil(PhysicsWorld); EntityConstructors.Add(EntityType.ITEM, new ItemEntityConstructor()); EntityConstructors.Add(EntityType.BLOCK_ITEM, new BlockItemEntityConstructor()); EntityConstructors.Add(EntityType.GLOWSTICK, new GlowstickEntityConstructor()); EntityConstructors.Add(EntityType.MODEL, new ModelEntityConstructor()); EntityConstructors.Add(EntityType.SMOKE_GRENADE, new SmokeGrenadeEntityConstructor()); EntityConstructors.Add(EntityType.MUSIC_BLOCK, new MusicBlockEntityConstructor()); ChunkManager = new ChunkDataManager(); ChunkManager.Init(this); //LoadRegion(new Location(-MaxViewRadiusInChunks * 30), new Location(MaxViewRadiusInChunks * 30), true); //TheServer.Schedule.RunAllSyncTasks(0.016); // TODO: Separate per-region scheduler // Also don't freeze the entire server/region just because we're waiting on chunks >.> //SysConsole.Output(OutputType.INIT, "Finished building chunks! Now have " + LoadedChunks.Count + " chunks!"); }
/// <summary> /// Constructs a new demo. /// </summary> /// <param name="game">Game owning this demo.</param> public MultithreadedScalingTestDemo(DemosGame game) : base(game) { simulationBuilders = new Func<Space, int>[] { BuildPileSimulation, BuildWallSimulation, BuildPlanetSimulation }; #if WINDOWS int coreCountMax = Environment.ProcessorCount; testResults = new double[coreCountMax, simulationBuilders.Length]; int reruns = 1; for (int i = 0; i < reruns; i++) { GC.Collect(); var looper = new ParallelLooper(); //Try different thread counts. for (int j = 0; j < coreCountMax; j++) { looper.AddThread(); for (int k = 0; k < simulationBuilders.Length; k++) testResults[j, k] = RunTest(looper, simulationBuilders[k]); GC.Collect(); } } #else testResults = new double[4, simulationBuilders.Length]; int reruns = 10; for (int i = 0; i < reruns; i++) { GC.Collect(); var threadManager = new SpecializedThreadManager(); threadManager.AddThread(delegate { Thread.CurrentThread.SetProcessorAffinity(new[] { 1 }); }, null); for (int k = 0; k < simulationBuilders.Length; k++) testResults[0, k] += RunTest(threadManager, simulationBuilders[k]); GC.Collect(); threadManager.AddThread(delegate { Thread.CurrentThread.SetProcessorAffinity(new[] { 3 }); }, null); for (int k = 0; k < simulationBuilders.Length; k++) testResults[1, k] += RunTest(threadManager, simulationBuilders[k]); GC.Collect(); threadManager.AddThread(delegate { Thread.CurrentThread.SetProcessorAffinity(new[] { 5 }); }, null); for (int k = 0; k < simulationBuilders.Length; k++) testResults[2, k] += RunTest(threadManager, simulationBuilders[k]); GC.Collect(); threadManager.AddThread(delegate { Thread.CurrentThread.SetProcessorAffinity(new[] { 4 }); }, null); for (int k = 0; k < simulationBuilders.Length; k++) testResults[3, k] += RunTest(threadManager, simulationBuilders[k]); GC.Collect(); } #endif }
internal ParallelLoopWorker(ParallelLooper manager, Action threadStart) { this.manager = manager; this.threadStart = threadStart; getToWork = new AutoResetEvent(false); thread = new Thread(Work) { IsBackground = true }; thread.Start(); }
/// <summary> /// Constructs a new demo. /// </summary> /// <param name="game">Game owning this demo.</param> public BroadPhaseMultithreadingTestDemo(DemosGame game) : base(game) { Space.Solver.IterationLimit = 0; #if WINDOWS int coreCountMax = Environment.ProcessorCount; int splitOffsetMax = 6; testResults = new double[coreCountMax, splitOffsetMax + 1]; int reruns = 10; for (int i = 0; i < reruns; i++) { GC.Collect(); var looper = new ParallelLooper(); //Try different thread counts. for (int j = 0; j < coreCountMax; j++) { looper.AddThread(); //Try different split levels.); for (int k = 0; k <= splitOffsetMax; k++) { testResults[j, k] += RunTest(k, looper); GC.Collect(); } } } for (int i = 0; i < testResults.GetLength(0); i++) { for (int j = 0; j < testResults.GetLength(1); j++) { testResults[i, j] /= reruns; } } #else int splitOffsetMax = 6; testResults = new double[4, splitOffsetMax + 1]; int reruns = 10; for (int i = 0; i < reruns; i++) { var threadManager = new SpecializedThreadManager(); GC.Collect(); threadManager.AddThread(delegate { Thread.CurrentThread.SetProcessorAffinity(new[] { 1 }); }, null); for (int j = 0; j <= splitOffsetMax; j++) { testResults[0, j] += RunTest(j, threadManager); GC.Collect(); } threadManager.AddThread(delegate { Thread.CurrentThread.SetProcessorAffinity(new[] { 3 }); }, null); for (int j = 0; j <= splitOffsetMax; j++) { testResults[1, j] += RunTest(j, threadManager); GC.Collect(); } threadManager.AddThread(delegate { Thread.CurrentThread.SetProcessorAffinity(new[] { 5 }); }, null); for (int j = 0; j <= splitOffsetMax; j++) { testResults[2, j] += RunTest(j, threadManager); GC.Collect(); } threadManager.AddThread(delegate { Thread.CurrentThread.SetProcessorAffinity(new[] { 4 }); }, null); for (int j = 0; j <= splitOffsetMax; j++) { testResults[3, j] += RunTest(j, threadManager); GC.Collect(); } } for (int i = 0; i < testResults.GetLength(0); i++) { for (int j = 0; j < testResults.GetLength(1); j++) { testResults[i,j] /= reruns; } } #endif }
/// <summary> /// Builds the physics world. /// </summary> public void BuildWorld() { ParallelLooper pl = new ParallelLooper(); for (int i = 0; i < Environment.ProcessorCount; i++) { pl.AddThread(); } CollisionDetectionSettings.AllowedPenetration = 0.01f; PhysicsWorld = new Space(pl); PhysicsWorld.TimeStepSettings.MaximumTimeStepsPerFrame = 10; // Set the world's general default gravity PhysicsWorld.ForceUpdater.Gravity = new BEPUutilities.Vector3(0, 0, -9.8f * 3f / 2f); PhysicsWorld.DuringForcesUpdateables.Add(new LiquidVolume(this)); // Load a CollisionUtil instance Collision = new CollisionUtil(PhysicsWorld); }
public static void Test() { float leafMinSize = 1; float leafMaxSize = 100; float leafSizePower = 10; int queryCount = 1000000; int selfTestCount = 1; int refitCount = 1; int frameCount = 2048; float dt = 1 / 60f; VelocityDescription velocityDescription = new VelocityDescription { MinVelocity = 0, MaxVelocity = 10, VelocityDistributionPower = 10, PortionOfMovingLeaves = 1 }; Vector3 querySize = new Vector3(20); int queryLocationCount = 16384; //<-- POWER OF TWO!!! REMEMBER! ParallelLooper looper = new ParallelLooper(); for (int i = 0; i < Environment.ProcessorCount; ++i) { looper.AddThread(); } #if RANDOMLEAVES BoundingBox randomLeafBounds = new BoundingBox { Min = new Vector3(0, 0, 0), Max = new Vector3(629.96f) }; BoundingBox queryBounds = randomLeafBounds; int randomLeafCount = 65536; #else int leafCountX = 64; int leafCountY = 64; int leafCountZ = 64; float leafGap = 10; BoundingBox queryBounds = new BoundingBox { Min = new Vector3(0), Max = new Vector3(leafCountX, leafCountY, leafCountZ) * (new Vector3(leafSize) + new Vector3(leafGap)) }; #endif { var queries = GetQueryLocations(queryLocationCount, queryBounds, querySize); #if RANDOMLEAVES var leaves = GetRandomLeaves(randomLeafCount, randomLeafBounds, new Vector3(leafMinSize), new Vector3(leafMaxSize), leafSizePower, velocityDescription); #else var leaves = GetLeaves(leafCountX, leafCountY, leafCountZ, leafSize, leafGap); #endif GC.Collect(); //TestVectorized(leaves, queries, queryCount, selfTestCount, refitCount); #if RANDOMLEAVES leaves = GetRandomLeaves(randomLeafCount, randomLeafBounds, new Vector3(leafMinSize), new Vector3(leafMaxSize), leafSizePower, velocityDescription); #else leaves = GetLeaves(leafCountX, leafCountY, leafCountZ, leafSize, leafGap); #endif GC.Collect(); //TestBaseline(leaves, queries, queryCount, selfTestCount, refitCount); #if RANDOMLEAVES leaves = GetRandomLeaves(randomLeafCount, randomLeafBounds, new Vector3(leafMinSize), new Vector3(leafMaxSize), leafSizePower, velocityDescription); #else leaves = GetLeaves(leafCountX, leafCountY, leafCountZ, leafSize, leafGap); #endif GC.Collect(); var results = TestSingleArray(leaves, queries, randomLeafBounds, queryCount, selfTestCount, refitCount, frameCount, dt, looper); using (var stream = File.Open("newTreeResults.txt", FileMode.Create)) { using (var textWriter = new StreamWriter(stream)) { results.Save(textWriter); } } } { #if RANDOMLEAVES var leaves = GetRandomLeavesBEPU(randomLeafCount, randomLeafBounds, new Vector3(leafMinSize), new Vector3(leafMaxSize), leafSizePower, velocityDescription); #else var leaves = GetLeavesBEPU(leafCountX, leafCountY, leafCountZ, leafSize, leafGap); #endif var queries = GetBEPUQueryLocations(queryLocationCount, queryBounds, querySize); GC.Collect(); //TestBEPU(leaves, queries, queryCount, selfTestCount, refitCount); var results = TestDH(leaves, queries, ref randomLeafBounds, queryCount, selfTestCount, refitCount, frameCount, dt, looper); using (var stream = File.Open("oldDHResults.txt", FileMode.Create)) { using (var textWriter = new StreamWriter(stream)) { results.Save(textWriter); } } } }
public static unsafe TestResults TestSingleArray(TestCollidable[] leaves, BoundingBox[] queries, BoundingBox positionBounds, int queryCount, int selfTestCount, int refitCount, int frameCount, float dt, ParallelLooper looper) { { var warmLeaves = GetLeaves(10, 10, 10, 10, 10); Tree tree = new Tree(); //for (int i = 0; i < leaves.Length; ++i) //{ // BoundingBox box; // leaves[i].GetBoundingBox(out box); // //tree.Insert(i, ref box); // tree.AddGlobal(i, ref box); //} int[] leafIds = new int[warmLeaves.Length]; BoundingBox[] leafBounds = new BoundingBox[warmLeaves.Length]; for (int i = 0; i < warmLeaves.Length; ++i) { leafIds[i] = i; warmLeaves[i].GetBoundingBox(out leafBounds[i]); } //tree.BuildMedianSplit(leafIds, leafBounds); //tree.BuildVolumeHeuristic(leafIds, leafBounds); tree.SweepBuild(leafIds, leafBounds); Console.WriteLine($"SingleArray Cachewarm Build: {tree.LeafCount}"); tree.Refit(); //tree.BottomUpAgglomerativeRefine(); //tree.TopDownAgglomerativeRefine(); //tree.BottomUpSweepRefine(); //tree.TopDownSweepRefine(); tree.RefitAndRefine(0); var context = new Tree.RefitAndRefineMultithreadedContext(tree); tree.RefitAndRefine(0, looper, context); var selfTestContext = new Tree.SelfTestMultithreadedContext(looper.ThreadCount, BufferPools<Overlap>.Locking); tree.GetSelfOverlaps(looper, selfTestContext); var list = new QuickList<int>(new BufferPool<int>()); BoundingBox aabb = new BoundingBox { Min = new Vector3(0, 0, 0), Max = new Vector3(1, 1, 1) }; tree.QueryRecursive(ref aabb, ref list); list.Dispose(); var overlaps = new QuickList<Overlap>(new BufferPool<Overlap>()); tree.GetSelfOverlaps(ref overlaps); overlaps = new QuickList<Overlap>(new BufferPool<Overlap>()); tree.GetSelfOverlapsArityDedicated(ref overlaps); tree.IncrementalCacheOptimize(0); overlaps = new QuickList<Overlap>(new BufferPool<Overlap>()); tree.GetSelfOverlapsViaQueries(ref overlaps); Console.WriteLine($"Cachewarm overlaps: {overlaps.Count}"); tree.Dispose(); } { Console.WriteLine($"SingleArray arity: {Tree.ChildrenCapacity}"); Tree tree = new Tree(Math.Max(1, leaves.Length)); var startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; for (int i = 0; i < leaves.Length; ++i) { var leafIndex = (int)((982451653L * i) % leaves.Length); BoundingBox box; leaves[leafIndex].GetBoundingBox(out box); tree.Add(leafIndex, ref box); //tree.AddGlobal(leafIndex, ref box); } //int[] leafIds = new int[leaves.Length]; //BoundingBox[] leafBounds = new BoundingBox[leaves.Length]; //for (int i = 0; i < leaves.Length; ++i) //{ // leafIds[i] = i; // leaves[i].GetBoundingBox(out leafBounds[i]); //} ////tree.BuildMedianSplit(leafIds, leafBounds); ////tree.BuildVolumeHeuristic(leafIds, leafBounds); //tree.SweepBuild(leafIds, leafBounds); var endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; Console.WriteLine($"SingleArray Build Time: {endTime - startTime}, depth: {tree.ComputeMaximumDepth()}"); int nodeCount, childCount; tree.MeasureNodeOccupancy(out nodeCount, out childCount); Console.WriteLine($"SingleArray Occupancy: {childCount / (double)nodeCount}"); Console.WriteLine($"Cost metric: {tree.MeasureCostMetric()}"); Console.WriteLine($"Cache Quality: {tree.MeasureCacheQuality()}"); tree.Validate(); startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; for (int i = 0; i < refitCount; ++i) { //for (int i = 0; i < tree.LeafCount; ++i) //{ // BoundingBox box; // leaves[tree.Leaves[i].Id].GetBoundingBox(out box); // tree.UpdateLeafBoundingBox(i, ref box); //} tree.Refit(); } endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; Console.WriteLine($"SingleArray Refit Time1: {endTime - startTime}"); var overlaps = new QuickList<Overlap>(new BufferPool<Overlap>()); startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; for (int i = 0; i < selfTestCount; ++i) { overlaps.Count = 0; tree.GetSelfOverlaps(ref overlaps); } endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; Console.WriteLine($"SingleArray SelfTree Time1: {endTime - startTime}, overlaps: {overlaps.Count}"); int[] buffer; MemoryRegion region; BinnedResources resources; const int maximumSubtrees = 262144; var spareNodes = new QuickList<int>(new BufferPool<int>(), 8); var subtreeReferences = new QuickList<int>(BufferPools<int>.Thread, BufferPool<int>.GetPoolIndex(maximumSubtrees)); var treeletInternalNodes = new QuickList<int>(BufferPools<int>.Thread, BufferPool<int>.GetPoolIndex(maximumSubtrees)); Tree.CreateBinnedResources(BufferPools<int>.Thread, maximumSubtrees, out buffer, out region, out resources); bool nodesInvalidated; overlaps = new QuickList<Overlap>(new BufferPool<Overlap>()); var refineContext = new Tree.RefitAndRefineMultithreadedContext(tree); var selfTestContext = new Tree.SelfTestMultithreadedContext(looper.ThreadCount, BufferPools<Overlap>.Locking); var visitedNodes = new QuickSet<int>(BufferPools<int>.Thread, BufferPools<int>.Thread); //**************** Dynamic Testing Random random = new Random(5); TestResults results = new TestResults("New", frameCount); startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; for (int t = 0; t < frameCount; ++t) { //Update the positions of objects. for (int i = 0; i < tree.LeafCount; ++i) { var leafId = tree.Leaves[i].Id; var leaf = leaves[leafId]; //Bounce off the walls. if (leaf.Position.X < positionBounds.Min.X && leaf.Velocity.X < 0) leaf.Velocity.X = -leaf.Velocity.X; if (leaf.Position.Y < positionBounds.Min.Y && leaf.Velocity.Y < 0) leaf.Velocity.Y = -leaf.Velocity.Y; if (leaf.Position.Z < positionBounds.Min.Z && leaf.Velocity.Z < 0) leaf.Velocity.Z = -leaf.Velocity.Z; if (leaf.Position.X > positionBounds.Max.X && leaf.Velocity.X > 0) leaf.Velocity.X = -leaf.Velocity.X; if (leaf.Position.Y > positionBounds.Max.Y && leaf.Velocity.Y > 0) leaf.Velocity.Y = -leaf.Velocity.Y; if (leaf.Position.Z > positionBounds.Max.Z && leaf.Velocity.Z > 0) leaf.Velocity.Z = -leaf.Velocity.Z; leaf.Position += leaf.Velocity * dt; BoundingBox boundingBox; leaf.GetBoundingBox(out boundingBox); tree.SetLeafBoundingBox(i, ref boundingBox); } var refineStartTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; int refinementCount; if(looper.ThreadCount > 1) refinementCount = tree.RefitAndRefine(t, looper, refineContext); else refinementCount = tree.RefitAndRefine(t); var refineEndTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; int overlapsCount; if (looper.ThreadCount > 1) { tree.GetSelfOverlaps(looper, selfTestContext); overlapsCount = 0; for (int i = 0; i < selfTestContext.WorkerOverlaps.Length; ++i) { overlapsCount += selfTestContext.WorkerOverlaps[i].Count; } } else { overlaps.Count = 0; tree.GetSelfOverlapsArityDedicated(ref overlaps); overlapsCount = overlaps.Count; } var testEndTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; results.Refine[t] = 1000 * (refineEndTime - refineStartTime); results.SelfTest[t] = 1000 * (testEndTime - refineEndTime); results.Total[t] = 1000 * (testEndTime - refineStartTime); results.OverlapCounts[t] = overlapsCount; results.TreeCosts[t] = tree.MeasureCostMetric(); if (t % 16 == 0) { Console.WriteLine($"_________________{t}_________________"); Console.WriteLine($"Refinement count: {refinementCount}"); Console.WriteLine($"Refine time: {results.Refine[t]}"); Console.WriteLine($"Test time: {results.SelfTest[t]}"); Console.WriteLine($"TIME: {results.Total[t]}"); Console.WriteLine($"Cost metric: {results.TreeCosts[t]}"); Console.WriteLine($"Overlaps: {results.OverlapCounts[t]}"); Console.WriteLine($"Cache Quality: {tree.MeasureCacheQuality()}"); GC.Collect(); } tree.Validate(); } endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; tree.Validate(); Console.WriteLine($"SingleArray Cache Quality: {tree.MeasureCacheQuality()}"); Console.WriteLine($"Cost metric: {tree.MeasureCostMetric()}"); region.Dispose(); tree.RemoveUnusedInternalNodes(ref spareNodes); BufferPools<int>.Thread.GiveBack(buffer); //******************** tree.MeasureNodeOccupancy(out nodeCount, out childCount); Console.WriteLine($"SingleArray Occupancy: {childCount / (double)nodeCount}"); startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; for (int i = 0; i < refitCount; ++i) { //for (int i = 0; i < tree.LeafCount; ++i) //{ // BoundingBox box; // leaves[tree.Leaves[i].Id].GetBoundingBox(out box); // tree.UpdateLeafBoundingBox(i, ref box); //} tree.Refit(); } endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; Console.WriteLine($"SingleArray Refit Time2: {endTime - startTime}"); var list = new QuickList<int>(new BufferPool<int>()); var queryMask = queries.Length - 1; startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; for (int i = 0; i < queryCount; ++i) { list.Count = 0; //tree.Query2(ref queries[i & queryMask], ref list); tree.QueryRecursive(ref queries[i & queryMask], ref list); } endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; Console.WriteLine($"SingleArray Query Time: {endTime - startTime}, overlaps: {list.Count}"); Array.Clear(list.Elements, 0, list.Elements.Length); list.Dispose(); startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; for (int i = 0; i < selfTestCount; ++i) { overlaps.Count = 0; tree.GetSelfOverlaps(ref overlaps); } endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; Console.WriteLine($"SingleArray SelfTree Time: {endTime - startTime}, overlaps: {overlaps.Count}"); startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; for (int i = 0; i < selfTestCount; ++i) { overlaps.Count = 0; tree.GetSelfOverlapsArityDedicated(ref overlaps); } endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; Console.WriteLine($"SingleArray Arity-Dedicated SelfTree Time: {endTime - startTime}, overlaps: {overlaps.Count}"); startTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; for (int i = 0; i < selfTestCount; ++i) { overlaps.Count = 0; tree.GetSelfOverlapsViaQueries(ref overlaps); } endTime = Stopwatch.GetTimestamp() / (double)Stopwatch.Frequency; Console.WriteLine($"SingleArray SelfQuery Time: {endTime - startTime}, overlaps: {overlaps.Count}"); tree.Dispose(); return results; } }