| 1 | package de.uka.ipd.sdq.simucomframework; |
| 2 | |
| 3 | import java.util.Observable; |
| 4 | import java.util.Observer; |
| 5 | |
| 6 | import org.apache.log4j.Level; |
| 7 | import org.apache.log4j.Logger; |
| 8 | |
| 9 | import de.uka.ipd.sdq.errorhandling.dialogs.issues.DisplayIssuesDialog; |
| 10 | import de.uka.ipd.sdq.probespec.framework.calculator.Calculator; |
| 11 | import de.uka.ipd.sdq.simucomframework.model.SimuComModel; |
| 12 | import de.uka.ipd.sdq.simucomframework.resources.IResourceContainerFactory; |
| 13 | import de.uka.ipd.sdq.simucomframework.simucomstatus.SimuComStatus; |
| 14 | import de.uka.ipd.sdq.simucomframework.simucomstatus.SimucomstatusFactory; |
| 15 | import de.uka.ipd.sdq.simucomframework.usage.IWorkloadDriver; |
| 16 | import de.uka.ipd.sdq.simulation.AbstractSimulationConfig; |
| 17 | import de.uka.ipd.sdq.simulation.IStatusObserver; |
| 18 | import de.uka.ipd.sdq.simulation.SimulationResult; |
| 19 | import de.uka.ipd.sdq.simulation.abstractsimengine.ISimEngineFactory; |
| 20 | import de.uka.ipd.sdq.simulation.preferences.SimulationPreferencesHelper; |
| 21 | |
| 22 | /** |
| 23 | * Base class for simulation instances. It contains a generic simulation start |
| 24 | * and stop logic as well as basic error handling mechanisms. |
| 25 | * |
| 26 | * The code generated for each SimuCom instance contains the class |
| 27 | * main.SimuComControl that inherits from this one and provides the missing |
| 28 | * information. |
| 29 | * |
| 30 | * Excerpt from main.SimuComControl: public class SimuComControl extends |
| 31 | * de.uka.ipd.sdq.simucomframework.AbstractMain |
| 32 | * |
| 33 | * @author Steffen Becker |
| 34 | * |
| 35 | */ |
| 36 | public abstract class AbstractMain implements de.uka.ipd.sdq.simulation.ISimulationControl, |
| 37 | org.osgi.framework.BundleActivator { |
| 38 | |
| 39 | // Service registry entry for registering this object in Eclipse's service |
| 40 | // registry where |
| 41 | // it can be found by the simulation runner |
| 42 | private org.osgi.framework.ServiceRegistration serviceRegistryEntry; |
| 43 | |
| 44 | /* |
| 45 | * (non-Javadoc) |
| 46 | * |
| 47 | * @see |
| 48 | * org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext |
| 49 | * ) |
| 50 | */ |
| 51 | @SuppressWarnings("unchecked") |
| 52 | public void start(org.osgi.framework.BundleContext context) throws Exception { |
| 53 | // register the service |
| 54 | serviceRegistryEntry = context.registerService(de.uka.ipd.sdq.simulation.ISimulationControl.class |
| 55 | .getName(), this, new java.util.Hashtable()); |
| 56 | } |
| 57 | |
| 58 | /* |
| 59 | * (non-Javadoc) |
| 60 | * |
| 61 | * @see |
| 62 | * org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) |
| 63 | */ |
| 64 | public void stop(org.osgi.framework.BundleContext context) throws Exception { |
| 65 | serviceRegistryEntry.unregister(); |
| 66 | } |
| 67 | |
| 68 | private SimuComModel model = null; |
| 69 | private SimuComStatus simuComStatus; |
| 70 | private static Logger logger = Logger.getLogger(AbstractMain.class.getName()); |
| 71 | |
| 72 | /** |
| 73 | * Run a simulation using the given configuration and report to the given |
| 74 | * observer |
| 75 | * |
| 76 | * @param statusObserver |
| 77 | * Observer to notify about the simulation's progress |
| 78 | * @param config |
| 79 | * Configuration options for the simulation |
| 80 | * @param isRemoteRun |
| 81 | * True if this simulation runs remotely and has no access to the |
| 82 | * local sensorframework |
| 83 | * @return A status code indicating success or failure of the simulation |
| 84 | */ |
| 85 | protected SimulationResult run(final IStatusObserver statusObserver, SimuComConfig config, boolean isRemoteRun) { |
| 86 | |
| 87 | logger.info("Starting Simulation"); |
| 88 | |
| 89 | final long SIM_STOP_TIME = config.getSimuTime(); |
| 90 | |
| 91 | model.getSimulationControl().addTimeObserver(new Observer() { |
| 92 | |
| 93 | public void update(Observable clock, Object data) { |
| 94 | int timePercent = (int) (model.getSimulationControl().getCurrentSimulationTime() * 100 / SIM_STOP_TIME); |
| 95 | int measurementsPercent = (int) (model.getMainMeasurementsCount() * 100 / model.getConfig() |
| 96 | .getMaxMeasurementsCount()); |
| 97 | statusObserver.updateStatus(timePercent < measurementsPercent ? measurementsPercent : timePercent, |
| 98 | model.getSimulationControl().getCurrentSimulationTime(), model.getMainMeasurementsCount()); |
| 99 | } |
| 100 | |
| 101 | }); |
| 102 | getStatus().setCurrentSimulationTime(0); |
| 103 | double simRealTime = ExperimentRunner.run(model, SIM_STOP_TIME); |
| 104 | model.getProbeSpecContext().finish(); |
| 105 | // check if there are accuracy influence analysis issues |
| 106 | if (model.getIssues().size() > 0) { |
| 107 | logger.info(model.getIssues().size() + " issues experience during the simulation run."); |
| 108 | DisplayIssuesDialog runner = new DisplayIssuesDialog(model.getIssues()); |
| 109 | DisplayIssuesDialog.showDialogSync(runner); |
| 110 | } |
| 111 | |
| 112 | logger.info("Simulation stopped. It took " + (simRealTime / Math.pow(10, 9)) |
| 113 | + " seconds real time to terminate"); |
| 114 | |
| 115 | // TODO |
| 116 | // storeRunDescription(config.getExperimentRunDescriptor()); |
| 117 | |
| 118 | model.getConfig().disposeRandomGenerator(); |
| 119 | return model.getErrorStatus(); |
| 120 | } |
| 121 | |
| 122 | /** |
| 123 | * TODO: Where to put this code? |
| 124 | * |
| 125 | * If a sensitivity analysis has been conducted we need to store the current |
| 126 | * parameter values. |
| 127 | * |
| 128 | * @param descriptor |
| 129 | * @param run |
| 130 | */ |
| 131 | // private void storeRunDescription( |
| 132 | // ExperimentRunDescriptor descriptor) { |
| 133 | // if (descriptor == null) return; |
| 134 | // |
| 135 | // // TODO: Save data in clean model after migration to EDP2 |
| 136 | // for(ParameterDescriptor p : descriptor.getParameters()){ |
| 137 | // TimeSpanSensor s = createSensor(p.getName()); |
| 138 | // storeValue(s, p.getValue()); |
| 139 | // } |
| 140 | // |
| 141 | // } |
| 142 | // |
| 143 | // private void storeValue(TimeSpanSensor s, double value) { |
| 144 | // if (model.getCurrentExperimentRun() instanceof |
| 145 | // SimuComExperimentRunDecorator){ |
| 146 | // SimuComExperimentRunDecorator erd = (SimuComExperimentRunDecorator) |
| 147 | // model.getCurrentExperimentRun(); |
| 148 | // erd.addTimeSpanMeasurementAfterRun(s, 0, value); |
| 149 | // } |
| 150 | // |
| 151 | // } |
| 152 | // |
| 153 | // private TimeSpanSensor createSensor(String name) { |
| 154 | // return SensorHelper.createOrReuseTimeSensor(model.getDAOFactory(), |
| 155 | // model.getExperimentDatastore(), name); |
| 156 | // } |
| 157 | |
| 158 | /** |
| 159 | * Setup log4j |
| 160 | * |
| 161 | * @param config |
| 162 | * SimuCom config which is queried for the logging settings |
| 163 | */ |
| 164 | private void initializeLogger(SimuComConfig config) { |
| 165 | Logger simuComLogger = Logger.getLogger("de.uka.ipd.sdq.simucomframework"); |
| 166 | if (config.getVerboseLogging()) |
| 167 | // Set to Level.ALL if verbose logging is enabled, |
| 168 | simuComLogger.setLevel(Level.ALL); |
| 169 | else { |
| 170 | // Set to INFO if verbose level is not enabled but global logging |
| 171 | // level |
| 172 | // is lower than INFO, otherwise keep global level. |
| 173 | // In this way the global logging settings |
| 174 | // are kept if they are INFO, WARN or ERROR |
| 175 | Level currentLevel = simuComLogger.getEffectiveLevel(); |
| 176 | if (!currentLevel.isGreaterOrEqual(Level.INFO)) { |
| 177 | simuComLogger.setLevel(Level.INFO); |
| 178 | } |
| 179 | } |
| 180 | logger.debug("Extended Simulation Logging enabled!"); |
| 181 | |
| 182 | // Set this class' log level to info to see start and stop messages of |
| 183 | // SimuCom |
| 184 | logger.setLevel(Level.INFO); |
| 185 | } |
| 186 | |
| 187 | /** |
| 188 | * Request a simulation stop |
| 189 | */ |
| 190 | protected void stop() { |
| 191 | model.getSimulationControl().stop(); |
| 192 | } |
| 193 | |
| 194 | /** |
| 195 | * @return The simucom model used in this simulation run |
| 196 | */ |
| 197 | public SimuComModel getModel() { |
| 198 | return model; |
| 199 | } |
| 200 | |
| 201 | /** |
| 202 | * @return An error object in case an exception occurred during simulation |
| 203 | * execution |
| 204 | */ |
| 205 | public Throwable getErrorThrowable() { |
| 206 | return model.getErrorThrowable(); |
| 207 | } |
| 208 | |
| 209 | /* |
| 210 | * (non-Javadoc) |
| 211 | * |
| 212 | * @see |
| 213 | * de.uka.ipd.sdq.simucomframework.ISimuComControl#startSimulation(de.uka |
| 214 | * .ipd.sdq.simucomframework.SimuComConfig, |
| 215 | * de.uka.ipd.sdq.simucomframework.IStatusObserver, boolean) |
| 216 | */ |
| 217 | public void prepareSimulation(AbstractSimulationConfig config, IStatusObserver observer, boolean isRemoteRun) { |
| 218 | // load factory for the preferred simulation engine |
| 219 | ISimEngineFactory factory = SimulationPreferencesHelper.getPreferredSimulationEngine(); |
| 220 | if (factory == null) { |
| 221 | throw new RuntimeException("There is no simulation engine available. Install at least one engine."); |
| 222 | } |
| 223 | |
| 224 | // create simulation model |
| 225 | model = new SimuComModel((SimuComConfig) config, getStatus(), factory, isRemoteRun); |
| 226 | |
| 227 | // initialse simulation model |
| 228 | model.initialiseResourceContainer(getResourceContainerFactory()); |
| 229 | model.setUsageScenarios(getWorkloads((SimuComConfig) config)); |
| 230 | setupCalculators((SimuComConfig) config); |
| 231 | } |
| 232 | |
| 233 | /* |
| 234 | * (non-Javadoc) |
| 235 | * |
| 236 | * @see |
| 237 | * de.uka.ipd.sdq.simucomframework.ISimuComControl#startSimulation(de.uka |
| 238 | * .ipd.sdq.simucomframework.SimuComConfig, |
| 239 | * de.uka.ipd.sdq.simucomframework.IStatusObserver, boolean) |
| 240 | */ |
| 241 | public de.uka.ipd.sdq.simulation.SimulationResult startSimulation(AbstractSimulationConfig config, |
| 242 | IStatusObserver observer, boolean isRemoteRun) { |
| 243 | return run(observer, (SimuComConfig) config, isRemoteRun); |
| 244 | } |
| 245 | |
| 246 | /* |
| 247 | * (non-Javadoc) |
| 248 | * |
| 249 | * @see de.uka.ipd.sdq.simucomframework.ISimuComControl#stopSimulation() |
| 250 | */ |
| 251 | public void stopSimulation() { |
| 252 | stop(); |
| 253 | } |
| 254 | |
| 255 | /** |
| 256 | * Template method pattern. Child classes have to implement this to return |
| 257 | * workload drivers to use in the simulation. The workload drivers are used |
| 258 | * to generate the simulated users. |
| 259 | * |
| 260 | * @param config |
| 261 | * the simulation configuration data |
| 262 | * @return Workload drivers to use in the simulation run |
| 263 | */ |
| 264 | protected abstract IWorkloadDriver[] getWorkloads(SimuComConfig config); |
| 265 | |
| 266 | /** |
| 267 | * Template method to return a factory which can be used to instanciate the |
| 268 | * simulated resource environment. |
| 269 | * |
| 270 | * @return A factory which is used to create the simulated resource |
| 271 | * environment |
| 272 | */ |
| 273 | protected abstract IResourceContainerFactory getResourceContainerFactory(); |
| 274 | |
| 275 | /** |
| 276 | * Template method. Child classes implement this method to set up |
| 277 | * {@link Calculator}s before the simulation begins. |
| 278 | * |
| 279 | * @param config |
| 280 | * the simulation configuration data |
| 281 | */ |
| 282 | protected abstract void setupCalculators(SimuComConfig config); |
| 283 | |
| 284 | /* |
| 285 | * (non-Javadoc) |
| 286 | * |
| 287 | * @see de.uka.ipd.sdq.simucomframework.ISimuComControl#getStatus() |
| 288 | */ |
| 289 | public SimuComStatus getStatus() { |
| 290 | if (this.simuComStatus == null) { |
| 291 | this.simuComStatus = SimucomstatusFactory.eINSTANCE.createSimuComStatus(); |
| 292 | this.simuComStatus.setProcessStatus(SimucomstatusFactory.eINSTANCE.createSimulatedProcesses()); |
| 293 | this.simuComStatus.setResourceStatus(SimucomstatusFactory.eINSTANCE.createSimulatedResources()); |
| 294 | } |
| 295 | return this.simuComStatus; |
| 296 | } |
| 297 | |
| 298 | } |