package mior.controler; import java.io.IOException; import java.util.Arrays; import javax.swing.SwingUtilities; import javax.swing.UIManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import mcmas.core.MCMChrono; import mior.model.IMiorModel; import mior.model.ModelFactory; import mior.view.MiorResultWriter; import mior.view.MiorView; import joptsimple.OptionParser; import joptsimple.OptionSet; public class MiorLauncher { private final ModelFactory factory; private int modelVersion; private boolean topologyOnly; private boolean guiEnabled; private String outputFile; private String prefix; private int nbRepetitions; private int nbSimulations; //private int nbKernels; private final static Logger logger = LoggerFactory.getLogger(MiorLauncher.class); public MiorLauncher() { this.modelVersion = 4; this.factory = new ModelFactory(); this.topologyOnly = false; this.guiEnabled = false; this.outputFile = "output.dat"; this.prefix = ""; this.nbRepetitions = 0; //this.nbKernels = 0; this.nbSimulations = 0; } public void setTopologyOnly(boolean topologyOnly) { this.topologyOnly = topologyOnly; } public boolean isTopologyOnly() { return topologyOnly; } public String getPrefix() { return prefix; } public void setPrefix(String prefix) { this.prefix = prefix; } public int getModelVersion() { return modelVersion; } public void setModelVersion(int modelVersion) { this.modelVersion = modelVersion; } public void setBatchSize(int batchSize) { this.nbRepetitions = batchSize; } public int getBatchSize() { return nbRepetitions; } /* public void setNbKernels(int nbKernels) { this.nbKernels = nbKernels; } public int getNbKernels() { return nbKernels; }*/ public void setTotalSize(int totalSize) { this.nbSimulations = totalSize; } public int getTotalSize() { return nbSimulations; } public String getOutputFile() { return outputFile; } public void setOutputFile(String outputFile) { this.outputFile = outputFile; } public boolean isGuiEnabled() { return guiEnabled; } public void setGuiEnabled(boolean guiEnabled) { this.guiEnabled = guiEnabled; } public ModelFactory getFactory() { return factory; } public void start(int nbMM, int nbOM, int scale) { logger.info("Simulation size: " + nbMM + "x" + nbOM + " (scale: " + scale + ")"); IMiorModel model = factory.createModel(nbMM, nbOM, scale, modelVersion); model.addUpdateListener(new MiorResultWriter(outputFile)); if (guiEnabled) { startGUI(model); } if ((nbRepetitions < 1 || nbSimulations < 1) && !guiEnabled) { throw new RuntimeException("No GUI and no simulation to execute"); } System.err.println("# Running " + nbRepetitions + " time(s) the simulation"); //System.out.println(guiEnabled); //System.out.println(nbKernels); long [] results = new long[nbRepetitions]; final int groupSize = getFactory().getGroupSize(); final int nbKernels = (nbSimulations % groupSize == 0 ? nbSimulations / groupSize : nbSimulations / groupSize + 1); final int actualTotalSize = nbKernels * groupSize; final double correctionFactor = (1.0d * nbSimulations) / actualTotalSize; System.err.println("# " + correctionFactor); for (int i = 0; i < nbRepetitions; i++) { MCMChrono simChrono = new MCMChrono("Mior simulation"); System.err.println("# Running " + nbKernels + " times(s) a kernel of size " + groupSize + " to complete the simulation"); simChrono.start(); for (int j = 0; j < nbKernels; j++) { if (topologyOnly) { model.reset(); model.doTopology(); } else { model.reset(); model.doAutoLive(); } } results[i] = (long) (simChrono.stop().getValue() * correctionFactor); } //System.out.println(Arrays.toString(results)); if (nbRepetitions != 0) { printStats(results); } if (! guiEnabled) { model.release(); } } private void startGUI(IMiorModel model) { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (final Exception e) { e.printStackTrace(); } final MiorView view = new MiorView(model, "MIOR Model version: " + modelVersion); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { view.getFrame().setVisible(true); } }); } private void printStats(long [] rawResults) { // Sort the results long [] results = rawResults.clone(); //Arrays.copyOf(rawResults, rawResults.length); Arrays.sort(results); // Remove the min and max if we have more than 5 values if (results.length >= 5) { results = Arrays.copyOfRange(results, 1, results.length - 1); } // Min and max time final long min = results[0]; final long max = results[results.length - 1]; // Algebric mean double totalTime = 0; for (long time : results) { totalTime += time; } final double mean = totalTime / results.length; // ET computation long totalET = 0; for (long time : results) { totalET += (time - mean) * (time - mean); } final double ET = Math.sqrt(totalET / results.length); // Display System.out.println("# Min Max Avg ET"); System.out.println((prefix != null ? prefix + " " : "") + min + " " + max + " " + mean + " " + ET); } public static void main(String[] args) { final MiorLauncher simulation = new MiorLauncher(); OptionParser parser = new OptionParser(); parser.acceptsAll(Arrays.asList("o", "output"), "Output File") .withRequiredArg().ofType(String.class) .defaultsTo("output.dat"); /* * batchSize : Number of time to repeat (and average results) the whole simulation * totalSize : Total number of MIOR simulations to execute * kernelSize : Total number of MIOR to execute in the same kernel (par. implementations only) */ parser.acceptsAll(Arrays.asList("b", "batchSize", "r", "repeat"), "Number of time to repeat (for stats) the whole simulation") .withOptionalArg().ofType(Integer.class).defaultsTo(20); parser.acceptsAll(Arrays.asList("ts", "totalSize", "n", "nbSimulations"), "Total number of MIOR simulations to execute") .withRequiredArg().ofType(Integer.class).defaultsTo(0); parser.acceptsAll(Arrays.asList("ks", "kernelSize", "groupSize"), "Number of simulations to execute each kernel (PAR. IMPLEMENTATIONS ONLY)") .withRequiredArg().ofType(Integer.class); parser.acceptsAll(Arrays.asList("r", "random", "randomizePopulations"), "Enable randomization of Mior models").withOptionalArg() .ofType(Boolean.class).defaultsTo(true); parser.acceptsAll(Arrays.asList("c", "copy", "alwaysCopy"), "Always copy data between GPU and CPU").withOptionalArg() .ofType(Boolean.class).defaultsTo(true); parser.acceptsAll(Arrays.asList("j", "java"), "Use the Java implementation"); parser.acceptsAll(Arrays.asList("s", "scale"), "Scale the model by the given factor").withRequiredArg() .ofType(Integer.class).defaultsTo(1); parser.accepts("mm", "Number of MM to use").withRequiredArg() .ofType(Integer.class).defaultsTo(38); parser.accepts("om", "Number of OM to use").withRequiredArg() .ofType(Integer.class).defaultsTo(310); parser.acceptsAll(Arrays.asList("v", "version"), "Use this OpenCL implementation version").withRequiredArg() .ofType(Integer.class).defaultsTo(5); parser.acceptsAll(Arrays.asList("p", "prefix"), "Prefix to use for output").withRequiredArg() .ofType(String.class); parser.acceptsAll(Arrays.asList("t", "topoOnly"), "Execute only the topology step").withOptionalArg() .ofType(Boolean.class).defaultsTo(false); parser.acceptsAll(Arrays.asList("g", "gui"), "Enable GUI") .withOptionalArg().ofType(Boolean.class).defaultsTo(true); parser.acceptsAll(Arrays.asList("h", "help"), "Print this help"); OptionSet options = parser.parse(args); /** * HELP */ if (options.has("help")) { try { parser.printHelpOn(System.out); return; } catch (IOException e) { System.err.println("Failed to print help to standard output"); e.printStackTrace(); } } /** * PARALLELIZATION SETTINGS */ if (options.has("batchSize")) { simulation.getFactory().setBatchModeEnabled(true); simulation.setBatchSize((Integer) options.valueOf("batchSize")); } if (options.has("totalSize")) { int totalSize = (Integer) options.valueOf("totalSize"); simulation.setTotalSize(totalSize); if (options.has("kernelSize")) { int kernelSize = (Integer) options.valueOf("kernelSize"); if (kernelSize < 1) { throw new RuntimeException("kernelSize must be a divider of the total number of simulations (" + totalSize + ")"); } //simulation.setNbKernels(totalSize % kernelSize == 0 ? totalSize / kernelSize : (totalSize / kernelSize) + 1); simulation.getFactory().setGroupSize(kernelSize); } else { //simulation.setNbKernels(totalSize); simulation.getFactory().setGroupSize(1); } } if (options.has("blockSize")) { simulation.getFactory().setBlockSize((Integer) options.valueOf("blockSize")); } if (options.has("random")) { final boolean random = (Boolean) options.valueOf("random"); simulation.getFactory().setRandomEnabled(random); } if (options.has("alwaysCopy")) { final boolean copy = (Boolean) options.valueOf("alwaysCopy"); simulation.getFactory().setBatchModeEnabled(!copy); } /** * MODEL VERSION SETTINGS */ if (options.has("java")) { if (! options.has("version")) { simulation.setModelVersion(0); } else { System.err.println("Error: Java and OpenCL implementation can't be used at the same time."); System.exit(1); } } else { simulation.setModelVersion((Integer) options.valueOf("version")); } /** * OTHER PARAMETERS */ if (options.has("gui")) { simulation.setGuiEnabled((Boolean) options.valueOf("gui")); } else if (simulation.getFactory().getGroupSize() == 0) { simulation.setGuiEnabled(true); } simulation.setTopologyOnly((Boolean) options.valueOf("topoOnly")); simulation.setOutputFile((String) options.valueOf("output")); simulation.setPrefix((String) options.valueOf("prefix")); final int nbMM = (Integer) options.valueOf("mm"); final int nbOM = (Integer) options.valueOf("om"); final int scale = (Integer) options.valueOf("scale"); simulation.start(nbMM, nbOM, scale); } }