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