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