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 | } |