| 1 | package de.uka.ipd.sdq.dsexplore.opt4j.optimizer.heuristic.operators; |
| 2 | |
| 3 | import java.util.ArrayList; |
| 4 | import java.util.Collection; |
| 5 | import java.util.Comparator; |
| 6 | import java.util.HashMap; |
| 7 | import java.util.HashSet; |
| 8 | import java.util.List; |
| 9 | import java.util.Map; |
| 10 | import java.util.Set; |
| 11 | |
| 12 | import org.eclipse.emf.common.util.EList; |
| 13 | import org.eclipse.emf.ecore.EObject; |
| 14 | import org.opt4j.core.Objective; |
| 15 | |
| 16 | import de.uka.ipd.sdq.dsexplore.helper.EMFHelper; |
| 17 | import de.uka.ipd.sdq.dsexplore.opt4j.genotype.DesignDecisionGenotype; |
| 18 | import de.uka.ipd.sdq.dsexplore.opt4j.representation.DSEIndividual; |
| 19 | import de.uka.ipd.sdq.dsexplore.opt4j.representation.DSEObjectives; |
| 20 | import de.uka.ipd.sdq.pcm.core.entity.Entity; |
| 21 | import de.uka.ipd.sdq.pcm.designdecision.AllocationDegree; |
| 22 | import de.uka.ipd.sdq.pcm.designdecision.Choice; |
| 23 | import de.uka.ipd.sdq.pcm.designdecision.DecisionSpace; |
| 24 | import de.uka.ipd.sdq.pcm.designdecision.DegreeOfFreedomInstance; |
| 25 | import de.uka.ipd.sdq.pcm.designdecision.ClassChoice; |
| 26 | import de.uka.ipd.sdq.pcm.designdecision.ProcessingResourceDegree; |
| 27 | import de.uka.ipd.sdq.pcm.resourceenvironment.ProcessingResourceSpecification; |
| 28 | import de.uka.ipd.sdq.pcm.resourceenvironment.ResourceContainer; |
| 29 | import de.uka.ipd.sdq.pcm.resourcetype.ResourceType; |
| 30 | import de.uka.ipd.sdq.pcm.resultdecorator.ResultDecoratorRepository; |
| 31 | import de.uka.ipd.sdq.pcm.resultdecorator.resourceenvironmentdecorator.LinkingResourceResults; |
| 32 | import de.uka.ipd.sdq.pcm.resultdecorator.resourceenvironmentdecorator.ProcessingResourceSpecificationResult; |
| 33 | import de.uka.ipd.sdq.pcm.resultdecorator.resourceenvironmentdecorator.UtilisationResult; |
| 34 | |
| 35 | /** |
| 36 | * Cache for one individual. |
| 37 | * |
| 38 | * TODO check individual when passed to this{@link #getUnusedAvailableResourceContainers(DSEIndividual)} |
| 39 | * to make sure it is still the same one. |
| 40 | * |
| 41 | * XXX also cache min result etc. |
| 42 | * |
| 43 | * @author martens |
| 44 | * |
| 45 | */ |
| 46 | public class UtilisationResultCacheAndHelper { |
| 47 | |
| 48 | private Collection<ResourceContainer> unusedAvailableResourceContainers; |
| 49 | private Collection<ResourceContainer> availableResourceContainer; |
| 50 | |
| 51 | // maps must permit null values, as resource type is null if any resource in meant. |
| 52 | private Map<ResourceType, ProcessingResourceSpecificationResult> minProcResultMap = new HashMap<ResourceType, ProcessingResourceSpecificationResult>(); |
| 53 | private Map<ResourceType, ProcessingResourceSpecificationResult> maxProcResultMap = new HashMap<ResourceType, ProcessingResourceSpecificationResult>(); |
| 54 | |
| 55 | private LinkingResourceResults maxLinkResult; |
| 56 | private Set<ResourceType> resourceTypes; |
| 57 | |
| 58 | /** |
| 59 | * Get all resource containers that are available in the design decisions but that have no components. |
| 60 | * Determines unused containers based on the allocation degrees of freedom. |
| 61 | * @param individual |
| 62 | * @return |
| 63 | */ |
| 64 | public Collection<ResourceContainer> getUnusedAvailableResourceContainers(DSEIndividual individual) { |
| 65 | if (this.unusedAvailableResourceContainers == null){ |
| 66 | this.unusedAvailableResourceContainers = determineUnusedAvailableResourceContainers(individual); |
| 67 | } |
| 68 | return this.unusedAvailableResourceContainers; |
| 69 | } |
| 70 | |
| 71 | /** |
| 72 | * Return all {@link ResourceContainer}s available in the design decisions. |
| 73 | * @param individual |
| 74 | * @return |
| 75 | */ |
| 76 | public Collection<ResourceContainer> getAvailableResourceContainers( |
| 77 | DSEIndividual individual) { |
| 78 | if (this.availableResourceContainer == null){ |
| 79 | this.availableResourceContainer = determineAvailaibleResourceContainer(individual); |
| 80 | } |
| 81 | return this.availableResourceContainer; |
| 82 | } |
| 83 | |
| 84 | private Collection<ResourceContainer> determineAvailaibleResourceContainer( |
| 85 | DSEIndividual individual) { |
| 86 | Collection<ResourceContainer> availableResourceContainers = new ArrayList<ResourceContainer>(); |
| 87 | DesignDecisionGenotype genotype = individual.getGenotype(); |
| 88 | |
| 89 | // add all resource containers that can be found in the design decisions |
| 90 | for (Choice choice : genotype) { |
| 91 | if (choice instanceof ClassChoice) { |
| 92 | ClassChoice ClassChoice = (ClassChoice) choice; |
| 93 | if (ClassChoice.getDegreeOfFreedomInstance() instanceof AllocationDegree) { |
| 94 | AllocationDegree allocationDegree = (AllocationDegree) ClassChoice.getDegreeOfFreedomInstance(); |
| 95 | for (EObject entity : allocationDegree.getClassDesignOptions()) { |
| 96 | if (entity instanceof ResourceContainer) { |
| 97 | availableResourceContainers.add((ResourceContainer)entity); |
| 98 | } |
| 99 | } |
| 100 | } |
| 101 | } |
| 102 | } |
| 103 | return availableResourceContainers; |
| 104 | } |
| 105 | |
| 106 | |
| 107 | private Collection<ResourceContainer> determineUnusedAvailableResourceContainers(DSEIndividual individual) { |
| 108 | |
| 109 | DesignDecisionGenotype genotype = individual.getGenotype(); |
| 110 | |
| 111 | Collection<ResourceContainer> unusedResourceContainers = new HashSet<ResourceContainer>(); |
| 112 | unusedResourceContainers.addAll(this.getAvailableResourceContainers(individual)); |
| 113 | |
| 114 | // remove all resource containers that are used |
| 115 | for (Choice choice : genotype) { |
| 116 | if (choice instanceof ClassChoice) { |
| 117 | ClassChoice classChoice = (ClassChoice) choice; |
| 118 | unusedResourceContainers.remove(classChoice.getChosenValue()); |
| 119 | } |
| 120 | } |
| 121 | return unusedResourceContainers; |
| 122 | } |
| 123 | |
| 124 | public ProcessingResourceSpecificationResult getMinProcUtilisationResult(DSEIndividual individual) { |
| 125 | return this.getMinProcUtilisationResult(individual, null); |
| 126 | } |
| 127 | |
| 128 | /** |
| 129 | * Returns the {@link ProcessingResourceSpecificationResult} with the lowest utilisation. |
| 130 | * Only of used resource containers. |
| 131 | * @param individual |
| 132 | * @param resourceType may be null if any resource type is fine |
| 133 | * @return |
| 134 | */ |
| 135 | public ProcessingResourceSpecificationResult getMinProcUtilisationResult(DSEIndividual individual, ResourceType resourceType) { |
| 136 | |
| 137 | ProcessingResourceSpecificationResult minProcResult = minProcResultMap.get(resourceType); |
| 138 | if (minProcResult == null){ |
| 139 | |
| 140 | EList<UtilisationResult> utilisationResults = getUtilisationResult(individual); |
| 141 | ProcessingResourceSpecificationResult minUtilisationResult = null; |
| 142 | if (utilisationResults != null) { |
| 143 | for (UtilisationResult currentUtilisationResult : utilisationResults) { |
| 144 | if (currentUtilisationResult instanceof ProcessingResourceSpecificationResult){ |
| 145 | ProcessingResourceSpecificationResult procUtilisationResult = (ProcessingResourceSpecificationResult)currentUtilisationResult; |
| 146 | // only look at used servers |
| 147 | if (EMFHelper.contains(this.getAvailableResourceContainers(individual), |
| 148 | procUtilisationResult.getProcessingResourceSpecification_ProcessingResourceSpecificationResult().getResourceContainer_ProcessingResourceSpecification()) |
| 149 | && !EMFHelper.contains(this.getUnusedAvailableResourceContainers(individual), |
| 150 | procUtilisationResult.getProcessingResourceSpecification_ProcessingResourceSpecificationResult().getResourceContainer_ProcessingResourceSpecification() ) |
| 151 | // and has matching resource type if resource type is not null |
| 152 | && checkResourceType(procUtilisationResult, resourceType)){ |
| 153 | |
| 154 | if (minUtilisationResult == null |
| 155 | || minUtilisationResult.getResourceUtilisation() > procUtilisationResult.getResourceUtilisation()) { |
| 156 | minUtilisationResult = procUtilisationResult; |
| 157 | } |
| 158 | } |
| 159 | } |
| 160 | } |
| 161 | minProcResultMap.put(resourceType, minProcResult); |
| 162 | minProcResult = minUtilisationResult; |
| 163 | } |
| 164 | } |
| 165 | return minProcResult; |
| 166 | |
| 167 | } |
| 168 | |
| 169 | private boolean checkResourceType(ProcessingResourceSpecificationResult procUtilisationResult, ResourceType resourceType) { |
| 170 | return resourceType != null |
| 171 | ? (EMFHelper.checkIdentity(procUtilisationResult.getProcessingResourceSpecification_ProcessingResourceSpecificationResult().getActiveResourceType_ActiveResourceSpecification(),resourceType) |
| 172 | && !resourceType.getEntityName().equals("DELAY")) |
| 173 | : true; |
| 174 | } |
| 175 | |
| 176 | /** |
| 177 | * Link Resource types are not distinguished. |
| 178 | * @param individual |
| 179 | * @return |
| 180 | */ |
| 181 | public LinkingResourceResults getMaxLinkUtilisationResult(DSEIndividual individual){ |
| 182 | if (maxLinkResult == null){ |
| 183 | EList<UtilisationResult> utilisationResults = getUtilisationResult(individual); |
| 184 | LinkingResourceResults maxUtilisationResult = null; |
| 185 | if (utilisationResults != null) { |
| 186 | for (UtilisationResult currentUtilisationResult : utilisationResults) { |
| 187 | if (currentUtilisationResult instanceof LinkingResourceResults){ |
| 188 | LinkingResourceResults linkUtilisationResult = (LinkingResourceResults)currentUtilisationResult; |
| 189 | // only look at used links, decide by utilisation |
| 190 | if (linkUtilisationResult.getResourceUtilisation() > 0){ |
| 191 | if (maxUtilisationResult == null |
| 192 | || maxUtilisationResult.getResourceUtilisation() < linkUtilisationResult.getResourceUtilisation()) { |
| 193 | maxUtilisationResult = linkUtilisationResult; |
| 194 | } |
| 195 | } |
| 196 | } |
| 197 | } |
| 198 | maxLinkResult = maxUtilisationResult; |
| 199 | } |
| 200 | } |
| 201 | return maxLinkResult; |
| 202 | } |
| 203 | |
| 204 | public ProcessingResourceSpecificationResult getMaxProcUtilisationResult(DSEIndividual individual) { |
| 205 | return this.getMaxProcUtilisationResult(individual, null); |
| 206 | } |
| 207 | |
| 208 | /** |
| 209 | * Returns the {@link ProcessingResourceSpecificationResult} with the highest utilisation. |
| 210 | * Only of used resource containers. |
| 211 | * @param individual |
| 212 | * @param resourceType may be null if any resource type is fine |
| 213 | * @return |
| 214 | */ |
| 215 | public ProcessingResourceSpecificationResult getMaxProcUtilisationResult(DSEIndividual individual, ResourceType resourceType) { |
| 216 | |
| 217 | ProcessingResourceSpecificationResult maxProcResult = maxProcResultMap.get(resourceType); |
| 218 | if (maxProcResult == null){ |
| 219 | |
| 220 | EList<UtilisationResult> utilisationResults = getUtilisationResult(individual); |
| 221 | ProcessingResourceSpecificationResult maxUtilisationResult = null; |
| 222 | if (utilisationResults != null) { |
| 223 | for (UtilisationResult currentUtilisationResult : utilisationResults) { |
| 224 | if (currentUtilisationResult instanceof ProcessingResourceSpecificationResult){ |
| 225 | ProcessingResourceSpecificationResult procUtilisationResult = (ProcessingResourceSpecificationResult)currentUtilisationResult; |
| 226 | // only look at used servers |
| 227 | if (EMFHelper.contains(this.getAvailableResourceContainers(individual), procUtilisationResult.getProcessingResourceSpecification_ProcessingResourceSpecificationResult().getResourceContainer_ProcessingResourceSpecification()) |
| 228 | // and has matching resource type if resource type is not null |
| 229 | && checkResourceType(procUtilisationResult, resourceType) ){ |
| 230 | if (maxUtilisationResult == null || maxUtilisationResult.getResourceUtilisation() < procUtilisationResult.getResourceUtilisation()) { |
| 231 | maxUtilisationResult = procUtilisationResult; |
| 232 | } |
| 233 | } |
| 234 | } |
| 235 | } |
| 236 | maxProcResultMap.put(resourceType, maxUtilisationResult); |
| 237 | maxProcResult = maxUtilisationResult; |
| 238 | } |
| 239 | } |
| 240 | return maxProcResult; |
| 241 | } |
| 242 | |
| 243 | /** |
| 244 | * Gets utilisation result of an individual |
| 245 | * @param individual |
| 246 | * @return |
| 247 | */ |
| 248 | private static EList<UtilisationResult> getUtilisationResult(DSEIndividual individual) { |
| 249 | DSEObjectives objectives = (DSEObjectives) individual.getObjectives(); |
| 250 | Objective resonseTimeObjective = null; |
| 251 | //FIXME get name not hard coded |
| 252 | for (Objective o : objectives.getKeys()) { |
| 253 | if (o.getName().contains("response time") |
| 254 | || o.getName().contains("performance") |
| 255 | || o.getName().contains("throughput")) { |
| 256 | resonseTimeObjective = o; |
| 257 | } |
| 258 | } |
| 259 | ResultDecoratorRepository resultDecoratorRepository = objectives.getResultDecoratorFor(resonseTimeObjective); |
| 260 | |
| 261 | if (resultDecoratorRepository != null) { |
| 262 | return resultDecoratorRepository.getUtilisationResults_ResultDecoratorRepository(); |
| 263 | } else { |
| 264 | return null; |
| 265 | } |
| 266 | } |
| 267 | |
| 268 | |
| 269 | public static List<ProcessingResourceSpecificationResult> getProcessingResourceUtilisationResults(DSEIndividual individual){ |
| 270 | List<UtilisationResult> utilisationResults = getUtilisationResult(individual); |
| 271 | List<ProcessingResourceSpecificationResult> procUtils = new ArrayList<ProcessingResourceSpecificationResult>(utilisationResults.size()); |
| 272 | for (UtilisationResult utilisationResult : utilisationResults) { |
| 273 | if (utilisationResult instanceof ProcessingResourceSpecificationResult){ |
| 274 | procUtils.add((ProcessingResourceSpecificationResult)utilisationResult); |
| 275 | } |
| 276 | } |
| 277 | return procUtils; |
| 278 | } |
| 279 | |
| 280 | |
| 281 | |
| 282 | /** |
| 283 | * Compares two UtilisationResults based on their resourceUtilisation. |
| 284 | * The compare method returns the same as calling |
| 285 | * {@link Double#compare(double, double)} with o1.getResourceUtilisation() and |
| 286 | * o2.getResourceUtilisation(). |
| 287 | * |
| 288 | * @author martens |
| 289 | * |
| 290 | */ |
| 291 | public static class UtilisationComparator implements Comparator<UtilisationResult>{ |
| 292 | |
| 293 | @Override |
| 294 | public int compare(UtilisationResult o1, UtilisationResult o2) { |
| 295 | double utilO1 = o1.getResourceUtilisation(); |
| 296 | double utilO2 = o2.getResourceUtilisation(); |
| 297 | return Double.compare(utilO1, utilO2); |
| 298 | } |
| 299 | |
| 300 | } |
| 301 | |
| 302 | |
| 303 | |
| 304 | public Set<ResourceType> getResourceTypes(DSEIndividual individual) { |
| 305 | |
| 306 | if (this.resourceTypes == null){ |
| 307 | resourceTypes = new HashSet<ResourceType>(); |
| 308 | |
| 309 | DecisionSpace problem = individual.getProblem(); |
| 310 | for (DegreeOfFreedomInstance dof : problem.getDegreesOfFreedom()) { |
| 311 | if (dof instanceof AllocationDegree){ |
| 312 | List<EObject> entities = ((AllocationDegree) dof).getClassDesignOptions(); |
| 313 | for (EObject entity : entities) { |
| 314 | if (entity instanceof ResourceContainer){ |
| 315 | List<ProcessingResourceSpecification> resources = |
| 316 | ((ResourceContainer) entity) |
| 317 | .getActiveResourceSpecifications_ResourceContainer(); |
| 318 | for (ProcessingResourceSpecification processingResourceSpecification : resources) { |
| 319 | resourceTypes.add(processingResourceSpecification.getActiveResourceType_ActiveResourceSpecification()); |
| 320 | } |
| 321 | } |
| 322 | } |
| 323 | |
| 324 | } else if (dof instanceof ProcessingResourceDegree){ |
| 325 | resourceTypes.add(((ProcessingResourceDegree) dof).getProcessingresourcetype()); |
| 326 | } |
| 327 | } |
| 328 | |
| 329 | } |
| 330 | |
| 331 | return this.resourceTypes; |
| 332 | } |
| 333 | |
| 334 | } |
| 335 | |
| 336 | |
| 337 | |
| 338 | |
| 339 | |
| 340 | |