package simulator; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.PrintStream; import java.security.InvalidParameterException; import java.text.NumberFormat; import java.util.Calendar; import java.util.Date; import javax.swing.JFileChooser; import javax.swing.filechooser.FileFilter; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.exolab.castor.xml.MarshalException; import org.exolab.castor.xml.ValidationException; import org.joda.time.DateTimeUtilsExt; import org.qcg.broker.schemas.jobdesc.QcgJob; import schedframe.Initializable; import schedframe.ResourceController; import simulator.reader.ResourceReader; import simulator.stats.AccumulatedStatistics; import simulator.stats.implementation.DCWormsStatistics; import simulator.utils.LogErrStream; import simulator.workload.WorkloadLoader; import simulator.workload.reader.archive.AbstractWAReader; import simulator.workload.reader.archive.WAReader; import simulator.workload.reader.xmlJob.QcgXmlJobReader; import simulator.workload.reader.xmlJob.XMLJobReader; import cern.jet.random.Uniform; import cern.jet.random.engine.MersenneTwister64; /** * The main class of the Data Center Workload Scheduling Simulator. It has the * {@link #main(String[])} method used to invoke the program. This class also * provides second possibility to start the simulator, namely one may use the * {@link #performSimulation(ConfigurationOptions, DCWormsStatistics)} method. * In this case, the input parameter, describing the simulation options, must be * earlier prepared. The results of the simulation can be acquired using the * {@link #getAccumulatedStatistics()} method. * * @author Stanislaw Szczepanowski & Wojciech Piatek */ public class DataCenterWorkloadSimulator { /** * The name of the simulator application */ public static final String SIMULATOR_NAME = "Data Center Workload Simulator"; /** * Stores the statistical data of last run of the simulator (it may consist * of several runs of simulations) */ protected static AccumulatedStatistics accumulatedStatistics; protected static int simulationRunNumber = 0; /** * Determines the maximum fraction digits when printing floating point * values */ public static int MAXIMUM_FRACTION_DIGITS = 3; /** * The format of the numbers that will be printed */ public static NumberFormat DFAULT_NUMBER_FORMAT = NumberFormat .getInstance(); static { DFAULT_NUMBER_FORMAT.setMaximumFractionDigits(MAXIMUM_FRACTION_DIGITS); // 0,001 } private Log log = LogFactory.getLog(DataCenterWorkloadSimulator.class); protected String statsOutputPath; /** * Default empty constructor */ public DataCenterWorkloadSimulator() { } /** * The main method to start the simulation the accepted arguments are: * args[0] - the name of the resource bundle file with the configuration * args[1] (optional) - the number of simulations that are to be performed * (the default value is 1) * * @param args * the arguments passed to the application */ public static void main(String[] args) { DataCenterWorkloadSimulator dcworms = new DataCenterWorkloadSimulator(); dcworms.run(args); } public void run(String args[]) { System.setErr(new PrintStream(new LogErrStream(log))); String propertiesFileName = null; if (args.length == 0) { JFileChooser ch = new JFileChooser("."); FileFilter filter = new FileFilter() { @Override public boolean accept(File f) { return f.getName().endsWith(".properties") || f.isDirectory(); } @Override public String getDescription() { return "DCWoRMS experiment file"; } }; ch.setFileFilter(filter); ch.setDialogTitle("Choose the WoRMS simulation experiment file"); int result = ch.showOpenDialog(ch); if (result == JFileChooser.APPROVE_OPTION) { propertiesFileName = ch.getSelectedFile().getAbsolutePath(); } else { if (log.isFatalEnabled()) log.fatal("Resource bundle file name was not provided."); return; } } else if (args.length == 2 && "-multiuser".equals(args[0])) { runMultiuser(args[1], this); return; } else { propertiesFileName = args[0]; } ConfigurationOptions configurationOptions = ConfigurationOptions .getConfiguration(propertiesFileName); int noOfSimulations = 1; // default value is one if(configurationOptions.getNumberOfSimulations() > 1) noOfSimulations = configurationOptions.getNumberOfSimulations(); else if (args.length == 2) {// second parameter is given noOfSimulations = Integer.parseInt(args[1]); if (noOfSimulations < 1) { throw new InvalidParameterException( "Number of simulations cannot be less than 1"); } } if (log.isInfoEnabled()) log.info(":: Starting " + SIMULATOR_NAME + ". " + noOfSimulations + " simulation runs will be performed. ::"); File outputDir = null; try { outputDir = prepareDirecotry(configurationOptions); } catch (Exception e) { if (log.isErrorEnabled()) log.error("FAILED to create the output path", e); return; } File outputPropertiesFile = new File(outputDir, "experiment.properties"); accumulatedStatistics = new AccumulatedStatistics(noOfSimulations); for (int i = 0; i < noOfSimulations; ++i) { simulationRunNumber++; String simulationIdentifier = "Simulation " + (i + 1); try { performSimulation(simulationIdentifier, configurationOptions); // run the simulation } catch (Exception e) { if (log.isErrorEnabled()) log.error("ERROR in simulation run \"" + simulationIdentifier + "\":", e); break; } } if (log.isInfoEnabled()) log.info("Done :: " + SIMULATOR_NAME + " has finished " + noOfSimulations + " simulation runs ::"); System.out.flush(); System.err.flush(); try { copyFile(new File(propertiesFileName), outputPropertiesFile); } catch (IOException e) { log.error("IO exception occured during copying properties file to output path"); } } private void runMultiuser(String rootDirPath, DataCenterWorkloadSimulator dcworms) { throw new RuntimeException("not supported yet"); } /** * Starts a single simulation run. * * @param options * the configuration options according to which the simulation is * to be performed * @param simulationStatistics * the statistics object that is to be filled after the * simulation run * @throws Exception * any exception that may occur */ private void performSimulation(String simulationIdentifier, ConfigurationOptions options) throws Exception { // Startup of the random number generators must be set up with a random // seed that is greater than zero // if seed is not given then all consecutive simulations are the same // if seed < 0 then the random numbers are equal to zero Uniform uniform = new Uniform(new MersenneTwister64(new Date())); // seed should be > 0 and fits to int size (which is also important) long seed = uniform.nextLongFromTo(1, Integer.MAX_VALUE); if (log.isDebugEnabled()) log.debug("Shuffled initial seed: " + seed); assert seed > 0 && seed <= Integer.MAX_VALUE : "Initial seed is <= 0, what is improper"; GridSimWrapper.setSeed(seed); GridSimWrapper.setTraceSettings(); long startSimulation = System.currentTimeMillis(); if (log.isInfoEnabled()) { log.info(":: Starting simulation run: \"" + simulationIdentifier + "\" ::"); log.info(":: In the the mode of "); } WorkloadLoader workload = loadWorkload(options); // BEGIN: Initializing the GridSim: int numUser = 1; // the number of users in the experiment simulation // (default 1) Date date = workload.getSimulationStartTime(); Calendar calendar = Calendar.getInstance(); if (date == null) calendar.setTimeInMillis(0L); else calendar.setTime(date); boolean traceFlag = true; // means: trace GridSim events/activities String[] excludeFromFile = { "" }, excludeFromProcessing = { "" }; GridSimWrapper.init(numUser, calendar, traceFlag, excludeFromFile, excludeFromProcessing, null); DateTimeUtilsExt.initVirtualTimeAccess(calendar); ResourceReader resourceReader = new ResourceReader( options); ResourceController rc = resourceReader.read(); for(Initializable initObj: rc.getToInit()){ initObj.initiate(); } rc.setInitList(null); DCWormsUsers wl = new DCWormsUsers("Users", rc.getScheduler().get_name(), workload); GridSimWrapper.startSimulation(); long stopSimulation = System.currentTimeMillis(); DCWormsStatistics stats = new DCWormsStatistics(simulationIdentifier, options, wl, statsOutputPath, rc); accumulatedStatistics.add(stats); if (log.isInfoEnabled()) log.info("Generating statistics..."); stats.generateStatistics(); long duration = (stopSimulation - startSimulation) / 1000; if (log.isInfoEnabled()) log.info("The simulation run took " + duration + " seconds"); // if necessary generate gifs from sjvg - need to rewrite the SJVG // classes for public methods if (log.isInfoEnabled()) log.info(":: Finished simulation run: \"" + simulationIdentifier + "\" ::"); System.out.flush(); System.err.flush(); } private WorkloadLoader loadWorkload(ConfigurationOptions options) throws IOException, MarshalException, ValidationException{ XMLJobReader xmlJobReader = null; WAReader swfReader = null; String wlFileName = options.inputWorkloadFileName; if (options.inputFolder != null) { File f = null; if (options.inputTar != null) { f = new File(options.inputFolder + File.separator + options.inputTar); } else { f = new File(options.inputFolder); } xmlJobReader = new QcgXmlJobReader(f); wlFileName = options.inputFolder + File.separator + options.inputWorkloadFileName; } swfReader = AbstractWAReader.getInstace(wlFileName); WorkloadLoader workload = new WorkloadLoader(xmlJobReader, swfReader); workload.load(); return workload; } private File prepareDirecotry(ConfigurationOptions options) throws Exception { // String statsOutputPath = null; if (options.createScenario) { File outputFolderFile = new File(options.outputFolder); if (!outputFolderFile.exists()) { if (!outputFolderFile.mkdirs()) throw new IOException("Cannot create the output path: " + statsOutputPath + ". Cause: "); } if (log.isInfoEnabled()) log.info("CREATING SCENARIO ::"); statsOutputPath = options.outputFolder + options.statsOutputSubfolderNameCreate; } else { if (log.isInfoEnabled()) log.info("READING SCENARIO ::"); String prefix = null; if (options.inputFolder != null) { prefix = options.inputFolder; } else if (options.inputWorkloadFileName != null) { prefix = new File(options.inputWorkloadFileName).getParent(); } else { prefix = System.getProperty("user.dir"); } statsOutputPath = prefix + File.separator + options.statsOutputSubfolderNameRerad; } statsOutputPath += File.separator; // create the output folder File statsOutputPathFile = new File(statsOutputPath); if (!statsOutputPathFile.exists()) { if (!statsOutputPathFile.mkdirs()) throw new IOException("Cannot create the output (stats) path: " + statsOutputPath + ". Cause: "); } File folder = new File(statsOutputPath); File fileList[] = folder.listFiles(); for (int i = 0; i < fileList.length; i++) { File tmpFile = fileList[i]; String name = tmpFile.getName(); if (name.length() > 4) { String subName = name.substring(0, 5); if (subName.compareTo("Chart") == 0 || subName.compareTo("Stats") == 0) { tmpFile.delete(); } } } return statsOutputPathFile; } /** * Removes the given directory no matter if it is empty or non empty. If the * given parameter represents a file, it is not deleted. See the description * of the return statement. * * @param dirPath * the file representing the directory to be deleted. * @return true, if the given directory with all its contents have been * remove; false if deletion of any of files ended with error (all * other files are possibly also deleted) */ private static boolean deleteDirectory(File dirPath) { if (dirPath.exists() && dirPath.isDirectory()) { boolean result = true; File[] files = dirPath.listFiles(); for (File file : files) { if (file.isFile()) result |= file.delete(); else result |= deleteDirectory(file); } result |= dirPath.delete(); return result; } return false; // it is not a directory } /** * Static method to move a file from given "from" location to "to" location * * @param from * from location * @param to * to location * @return true if the operation succeeded, false otherwise */ private static boolean moveFile(String from, String to) { File fromFile = new File(from); File toFile = new File(to); if (toFile.exists()) { if (!toFile.delete()) return false; } if (!fromFile.renameTo(toFile)) { return false; } return true; } private void copyFile(File inputFile, File outputFile) throws IOException { FileReader in = new FileReader(inputFile); FileWriter out = new FileWriter(outputFile); int c; while ((c = in.read()) != -1) out.write(c); in.close(); out.close(); } /** * Returns the accumulated simulation statistics from the last run of the * simulator * * @return the accumulated simulation statistics from the last run of the * simulator */ public static AccumulatedStatistics getAccumulatedStatistics() { return accumulatedStatistics; } public static int getSimulationRunNumber(){ return simulationRunNumber; } protected class WorkloadDirectoryFilter implements java.io.FileFilter { public boolean accept(File file) { if (file.isDirectory() && file.getName().startsWith("workload")) return true; else return false; } } protected class PropertiesFileFilter implements java.io.FileFilter { public boolean accept(File file) { if (file.isFile() && file.getName().endsWith(".properties")) return true; else return false; } } }