package org.openpixi.pixi.distributed.utils; import org.openpixi.pixi.distributed.Master; import org.openpixi.pixi.distributed.Node; import org.openpixi.pixi.physics.Settings; import org.openpixi.pixi.physics.Simulation; import org.openpixi.pixi.physics.util.ResultsComparator; /** * Emulates distributed environment on local host. * Verifies whether the result of the distributed simulation * is the same as the result of non-distributed simulation. */ public class EmulatedDistributedEnvironment { private Settings settings; public EmulatedDistributedEnvironment(Settings settings) { this.settings = settings; } /** * Runs the distributed simulation at once and compares the results at the end. */ public void runAtOnce() { final Node[] nodes = new Node[settings.getNumOfNodes()]; for (int i = 0; i < settings.getNumOfNodes(); i++) { nodes[i] = new Node(settings); } runRunnables(nodes); // Set the master Master master = null; for (Node n: nodes) { if (n.isMaster()) { master = n.getMaster(); } } // Run non-distributed simulation Simulation simulation = new Simulation(settings); simulation.run(); settings.terminateThreads(); // Compare results ResultsComparator comparator = new ResultsComparator(); compareResults(master, simulation, comparator); } /** * Runs the distributed and non-distributed simulations in steps * and compares the result after each step. */ public void runInSteps() { final Node[] nodes = new Node[settings.getNumOfNodes()]; for (int i = 0; i < settings.getNumOfNodes(); i++) { nodes[i] = new Node(settings); } Runnable[] distributeRuns = new Runnable[nodes.length]; for (int i = 0; i < nodes.length; ++i) { final int nodeID = i; distributeRuns[nodeID] = new Runnable() { public void run() { nodes[nodeID].distribute(); } }; } Runnable[] collectRuns = new Runnable[nodes.length]; for (int i = 0; i < nodes.length; ++i) { final int nodeID = i; collectRuns[nodeID] = new Runnable() { public void run() { nodes[nodeID].collect(); } }; } Runnable[] stepRuns = new Runnable[nodes.length]; for (int i = 0; i < nodes.length; ++i) { final int nodeID = i; stepRuns[nodeID] = new Runnable() { public void run() { nodes[nodeID].step(); } }; } runRunnables(distributeRuns); // Determine the master Master master = null; for (Node n: nodes) { if (n.isMaster()) { master = n.getMaster(); } } // Create non-distributed simulation Simulation simulation = new Simulation(settings); for (int i = 0; i < settings.getIterations(); ++i) { simulation.step(); runRunnables(stepRuns); runRunnables(collectRuns); ResultsComparator comparator = new ResultsComparator(i); compareResults(master, simulation, comparator); } Runnable[] closeRuns = new Runnable[nodes.length]; for (int i = 0; i < nodes.length; ++i) { final int nodeID = i; closeRuns[nodeID] = new Runnable() { public void run() { nodes[nodeID].close(); } }; } runRunnables(closeRuns); settings.terminateThreads(); } private void compareResults(Master master, Simulation simulation, ResultsComparator comparator) { comparator.compare( simulation.particles, master.getFinalParticles(), simulation.grid, master.getFinalGrid()); } /** * Runs array of runnables simultaneously and waits for them to finish. */ private void runRunnables(Runnable[] runnables) { Thread[] threads = new Thread[runnables.length]; for (int i = 0; i < runnables.length; ++i) { threads[i] = new Thread(runnables[i]); threads[i].start(); } for (Thread t: threads) { try { t.join(); } catch (InterruptedException e) { throw new RuntimeException(e); } } } }