1 | package de.uka.ipd.sdq.simucomframework.resources; |
2 | |
3 | import java.util.ArrayList; |
4 | import java.util.HashMap; |
5 | import java.util.List; |
6 | import java.util.Map; |
7 | |
8 | import org.apache.log4j.Logger; |
9 | |
10 | import scheduler.configuration.ActiveResourceConfiguration; |
11 | import de.uka.ipd.sdq.reliability.core.FailureStatistics; |
12 | import de.uka.ipd.sdq.scheduler.IActiveResource; |
13 | import de.uka.ipd.sdq.scheduler.ISchedulableProcess; |
14 | import de.uka.ipd.sdq.scheduler.sensors.IActiveResourceStateSensor; |
15 | import de.uka.ipd.sdq.simucomframework.Context; |
16 | import de.uka.ipd.sdq.simucomframework.SimuComSimProcess; |
17 | import de.uka.ipd.sdq.simucomframework.entities.SimuComEntity; |
18 | import de.uka.ipd.sdq.simucomframework.exceptions.FailureException; |
19 | import de.uka.ipd.sdq.simucomframework.model.SimuComModel; |
20 | import de.uka.ipd.sdq.simucomframework.simucomstatus.ActiveResouce; |
21 | import de.uka.ipd.sdq.simucomframework.simucomstatus.SimucomstatusFactory; |
22 | import de.uka.ipd.sdq.simulation.abstractsimengine.AbstractSimEntityDelegator; |
23 | |
24 | /** |
25 | * Base class of all resources which have their own scheduler, i.e., active |
26 | * resources in the PCM. Contains generic code to instrument the resource to |
27 | * report its results to the sensorframework |
28 | * |
29 | * @author Steffen Becker |
30 | * |
31 | */ |
32 | public abstract class AbstractScheduledResource extends SimuComEntity implements IActiveResourceStateSensor { |
33 | |
34 | public final static double EPSILON = Math.pow(10, -9); |
35 | |
36 | protected static Logger logger = Logger |
37 | .getLogger(AbstractScheduledResource.class.getName()); |
38 | |
39 | // each instance maintains its own list of state listeners |
40 | private Map<Integer, List<IStateListener>> stateListener; |
41 | private List<IDemandListener> demandListener; |
42 | private List<IOverallUtilizationListener> overallUtilizationListener; |
43 | protected ActiveResourceConfiguration resourceConf = null; |
44 | |
45 | // For resources that can become unavailable (SimulatedActiveResources): |
46 | protected double mttf = 0.0; |
47 | protected double mttr = 0.0; |
48 | protected boolean canBeUnavailable = false; |
49 | protected boolean isAvailable = true; |
50 | protected boolean requiredByContainer = false; |
51 | |
52 | protected ResourceFailedEvent failedEvent; |
53 | protected ResourceRepairedEvent repairedEvent; |
54 | |
55 | // For resources that can fail (SimulatedLinkingResources): |
56 | protected boolean canFail = false; |
57 | protected double failureProbability = 0.0; |
58 | |
59 | private ActiveResouce myResourceStatus; |
60 | |
61 | protected IActiveResource aResource = null; |
62 | |
63 | protected String resourceTypeID; |
64 | private String resourceContainerID; |
65 | |
66 | private boolean isStopped = false; |
67 | |
68 | protected String description; |
69 | |
70 | protected int numberOfInstances; |
71 | |
72 | protected SchedulingStrategy schedulingStrategy; |
73 | protected AbstractSimulatedResourceContainer resourceContainer = null; |
74 | |
75 | public AbstractScheduledResource(SimuComModel myModel, String typeID, |
76 | String resourceContainerID, String resourceTypeID, |
77 | String description, SchedulingStrategy strategy, |
78 | int numberOfInstances, boolean requiredByContainer) { |
79 | super(myModel, typeID); |
80 | this.description = description; |
81 | this.numberOfInstances = numberOfInstances; |
82 | this.schedulingStrategy = strategy; |
83 | this.resourceTypeID = resourceTypeID; |
84 | this.resourceContainerID = resourceContainerID; |
85 | this.requiredByContainer = requiredByContainer; |
86 | |
87 | logger.info("Creating Simulated Active Resource: " + this.getName()); |
88 | |
89 | myResourceStatus = SimucomstatusFactory.eINSTANCE.createActiveResouce(); |
90 | myResourceStatus.setId(this.getName()); |
91 | myModel.getSimulationStatus().getResourceStatus().getActiveResources() |
92 | .add(myResourceStatus); |
93 | resourceContainer = myModel.getResourceRegistry().getResourceContainer(resourceContainerID); |
94 | if (resourceContainer == null) { |
95 | logger.warn("Resource container " +resourceContainerID + " is not available!"); |
96 | } |
97 | |
98 | stateListener = new HashMap<Integer, List<IStateListener>>(); |
99 | for (int instance = 0; instance < numberOfInstances; instance++) { |
100 | stateListener.put(instance, new ArrayList<IStateListener>()); |
101 | } |
102 | overallUtilizationListener = new ArrayList<IOverallUtilizationListener>(); |
103 | demandListener = new ArrayList<IDemandListener>(); |
104 | |
105 | this.aResource = createActiveResource(myModel); |
106 | this.aResource.addObserver(this); |
107 | } |
108 | |
109 | /** |
110 | * Subclasses are responsible for creating the {@link IActiveResource} to |
111 | * use internally. Is called in the constructor. |
112 | * |
113 | * @return the {@link IActiveResource} resource to use as determined by the |
114 | * subclasses. |
115 | */ |
116 | protected abstract IActiveResource createActiveResource( |
117 | SimuComModel simuComModel); |
118 | |
119 | /** |
120 | * Called by client of this resource to make the resource simulate resource |
121 | * processing. This is the queueing network service center part of our |
122 | * simulation |
123 | * |
124 | * @param thread |
125 | * The thread or job requesting the processing of its demand |
126 | * @param resourceServiceID |
127 | * The id of the resource service to be called for resource |
128 | * consumption |
129 | * @param demand |
130 | * The resource demand the client wishes to be processed by the |
131 | * resource |
132 | */ |
133 | public abstract void consumeResource(SimuComSimProcess thread, |
134 | int resourceServiceID, double demand); |
135 | |
136 | public abstract double getRemainingDemandForProcess(SimuComSimProcess thread); |
137 | |
138 | public abstract void updateDemand(SimuComSimProcess thread, double demand); |
139 | |
140 | /** |
141 | * Template method. Implementers have to use the given demand and return the |
142 | * time span needed to process the demand on this resource. |
143 | * |
144 | * @param demand |
145 | * The demand issued to this resource in units understood by the |
146 | * resource |
147 | * @return The service time, given in seconds |
148 | */ |
149 | protected abstract double calculateDemand(double demand); |
150 | |
151 | /** |
152 | * Called by the framework to inform that the resource should start its |
153 | * lifecycle |
154 | */ |
155 | public void activateResource() { |
156 | logger.debug("Starting resource " + this.getName()); |
157 | if (canBeUnavailable) { |
158 | double t = getFailureTime(); |
159 | failedEvent.schedule(this, t); |
160 | } |
161 | } |
162 | |
163 | /** |
164 | * Called by the framework to inform the resource that the simulation has |
165 | * been stopped. Fires a {@link IStateListener#stateChanged()} event. |
166 | */ |
167 | public void deactivateResource() { |
168 | if (!this.isStopped) { |
169 | logger.debug("Stopping resource " + this.getName()); |
170 | this.isStopped = true; |
171 | for (int instance = 0; instance < numberOfInstances; instance++) { |
172 | fireStateEvent(0, instance); |
173 | } |
174 | this.getModel().getSimulationStatus().getResourceStatus() |
175 | .getActiveResources().remove(myResourceStatus); |
176 | if (this.canBeUnavailable) { |
177 | this.failedEvent.removeEvent(); |
178 | this.repairedEvent.removeEvent(); |
179 | } |
180 | } |
181 | } |
182 | |
183 | public abstract IActiveResource getScheduledResource(); |
184 | |
185 | /** |
186 | * Marks the resource as being available or unavailable. |
187 | * |
188 | * @param isAvailable |
189 | * the target state to set |
190 | */ |
191 | public void setAvailable(boolean isAvailable) { |
192 | this.isAvailable = isAvailable; |
193 | double time = this.getModel().getSimulationControl() |
194 | .getCurrentSimulationTime(); |
195 | String status = (this.isAvailable) ? "available" : "unavailable"; |
196 | logger.debug("Resource " + this.getName() + " " + status |
197 | + " at sim time " + time); |
198 | } |
199 | |
200 | /** |
201 | * Retrieves the current availability status of this resource. |
202 | * |
203 | * @return TRUE if the resource is available; FALSE otherwise |
204 | */ |
205 | public boolean isAvailable() { |
206 | return isAvailable; |
207 | } |
208 | |
209 | /** |
210 | * Asks if a processing resource is required by its surrounding container. |
211 | * @return TRUE if resource is required; FALSE otherwise |
212 | */ |
213 | public boolean isRequiredByContainer() { |
214 | return requiredByContainer; |
215 | } |
216 | |
217 | /** |
218 | * Returns the failure time for this resource (or -1.0 if the resource |
219 | * cannot fail). |
220 | * |
221 | * @return the failure time for the resource |
222 | */ |
223 | public double getFailureTime() { |
224 | if (!canBeUnavailable) { |
225 | throw new RuntimeException( |
226 | "getFailureTime() should not be invoked as resource cannot fail"); |
227 | } |
228 | double failureTimeSample = (Double) Context.evaluateStatic("Exp(1 / " |
229 | + "(" + this.mttf + ")" + ")", Double.class); |
230 | logger.debug("Resource " + this.getDescription() |
231 | + " will fail at sim time +" + failureTimeSample); |
232 | return failureTimeSample; |
233 | } |
234 | |
235 | /** |
236 | * Returns the repair time for this resource (or -1.0 if the resource cannot |
237 | * fail). |
238 | * |
239 | * @return the repair time for the resource |
240 | */ |
241 | public double getRepairTime() { |
242 | if (!canBeUnavailable) { |
243 | throw new RuntimeException( |
244 | "getRepairTime() should not be invoked as resource cannot fail"); |
245 | } |
246 | double repairTimeSample = (Double) Context.evaluateStatic("Exp(1/" |
247 | + this.mttr + ")", Double.class); |
248 | logger.debug("Resource " + this.getDescription() |
249 | + " will be repaired at sim time +" + repairTimeSample); |
250 | return repairTimeSample; |
251 | } |
252 | |
253 | /** |
254 | * Retrieves the failure probability of the resource (if it can fail). |
255 | * |
256 | * @return the failure probability |
257 | */ |
258 | public double getFailureProbability() { |
259 | return (canFail) ? failureProbability : 0.0; |
260 | } |
261 | |
262 | /** |
263 | * Creates the events that let the resource fail and be repaired. |
264 | * |
265 | * @param model |
266 | * the SimuComModel |
267 | */ |
268 | protected void createAvailabilityEvents(final SimuComModel model) { |
269 | this.failedEvent = new ResourceFailedEvent(model, "ResourceFailed"); |
270 | this.repairedEvent = new ResourceRepairedEvent(model, |
271 | "ResourceRepaired"); |
272 | this.failedEvent.setResource(this); |
273 | this.failedEvent.setRepairedEvent(repairedEvent); |
274 | this.repairedEvent.setResource(this); |
275 | this.repairedEvent.setFailedEvent(failedEvent); |
276 | } |
277 | |
278 | /** |
279 | * Asserts that the resource is currently available; if not, an |
280 | * EnvironmentFailureException is thrown. |
281 | */ |
282 | protected void assertAvailability() { |
283 | if (!isAvailable) { |
284 | FailureException.raise(FailureStatistics.getInstance() |
285 | .getInternalHardwareFailureType(resourceContainerID, |
286 | resourceTypeID)); |
287 | } |
288 | } |
289 | |
290 | public String getDescription() { |
291 | return description; |
292 | } |
293 | |
294 | public int getNumberOfInstances() { |
295 | return numberOfInstances; |
296 | } |
297 | |
298 | public void addStateListener(IStateListener listener, int instance) { |
299 | stateListener.get(instance).add(listener); |
300 | } |
301 | |
302 | public void addOverallUtilizationListener( |
303 | IOverallUtilizationListener listener) { |
304 | overallUtilizationListener.add(listener); |
305 | } |
306 | |
307 | /** |
308 | * @see IStateListener |
309 | */ |
310 | protected void fireStateEvent(int queueLength, int instance) { |
311 | for (IStateListener l : stateListener.get(instance)) { |
312 | l.stateChanged(queueLength, instance); |
313 | } |
314 | } |
315 | |
316 | protected void fireOverallUtilization(double resourceDemand, |
317 | double totalTime) { |
318 | for (IOverallUtilizationListener l : overallUtilizationListener) { |
319 | l.utilizationChanged(resourceDemand, totalTime); |
320 | } |
321 | } |
322 | |
323 | public void addDemandListener(IDemandListener listener) { |
324 | demandListener.add(listener); |
325 | } |
326 | |
327 | protected void fireDemand(double demand) { |
328 | for (IDemandListener l : demandListener) { |
329 | l.demand(demand); |
330 | } |
331 | } |
332 | |
333 | public void update(int state, int instanceId) { |
334 | fireStateEvent(state, instanceId); |
335 | } |
336 | |
337 | public void demandCompleted(ISchedulableProcess simProcess) { |
338 | for (IDemandListener l : demandListener) { |
339 | l.demandCompleted(simProcess); |
340 | } |
341 | } |
342 | |
343 | public String getResourceTypeId() { |
344 | return resourceTypeID; |
345 | } |
346 | } |