1 | package de.uka.ipd.sdq.dsexplore.opt4j.optimizer.heuristic.operators.impl; |
2 | |
3 | import java.util.ArrayList; |
4 | import java.util.Collection; |
5 | import java.util.List; |
6 | import java.util.Set; |
7 | |
8 | import org.opt4j.core.problem.Genotype; |
9 | import org.opt4j.operator.copy.Copy; |
10 | |
11 | import de.uka.ipd.sdq.dsexplore.launch.DSEWorkflowConfiguration; |
12 | import de.uka.ipd.sdq.dsexplore.opt4j.optimizer.heuristic.operators.TacticsResultCandidate; |
13 | import de.uka.ipd.sdq.dsexplore.opt4j.optimizer.heuristic.operators.UtilisationResultCacheAndHelper; |
14 | import de.uka.ipd.sdq.dsexplore.opt4j.representation.DSEIndividual; |
15 | import de.uka.ipd.sdq.dsexplore.opt4j.representation.DSEIndividualBuilder; |
16 | import de.uka.ipd.sdq.dsexplore.qml.handling.QMLConstantsContainer; |
17 | import de.uka.ipd.sdq.pcm.designdecision.ContinousRangeChoice; |
18 | import de.uka.ipd.sdq.pcm.designdecision.ContinuousProcessingRateDegree; |
19 | import de.uka.ipd.sdq.pcm.designdecision.DiscreteRangeChoice; |
20 | import de.uka.ipd.sdq.pcm.designdecision.NumberOfCoresAsListDegree; |
21 | import de.uka.ipd.sdq.pcm.designdecision.NumberOfCoresAsRangeDegree; |
22 | import de.uka.ipd.sdq.pcm.designdecision.NumberOfCoresDegree; |
23 | import de.uka.ipd.sdq.pcm.resourceenvironment.ProcessingResourceSpecification; |
24 | import de.uka.ipd.sdq.pcm.resourcetype.ResourceType; |
25 | import de.uka.ipd.sdq.pcm.resultdecorator.resourceenvironmentdecorator.ProcessingResourceSpecificationResult; |
26 | import de.uka.ipd.sdq.pcm.resultdecorator.resourceenvironmentdecorator.UtilisationResult; |
27 | |
28 | /** |
29 | * This class implements an IHeuristic which increases the processing rate of |
30 | * highly utilized processing resources. |
31 | * |
32 | * XXX increase or decrease processing rate by a randomized demand, e.g. |
33 | * normally distributed around the given parameter value? |
34 | * |
35 | * @author martens, Tom Beyer |
36 | */ |
37 | public class IncreaseProcessingRateImpl extends AbstractProcessingRateTactic { |
38 | |
39 | |
40 | /** |
41 | * Processing rate will be increased by this factor if preconditions are |
42 | * fulfilled |
43 | */ |
44 | private double increaseProcessingRateFactor; |
45 | |
46 | /** |
47 | * If utilisation is larger than this double it will be considered a high |
48 | * utilisation |
49 | */ |
50 | private double thresholdHighUtilisation; |
51 | |
52 | /** |
53 | * @param copy |
54 | * Creates copy of genotypes |
55 | * @param individualBuilder |
56 | * Builds individual |
57 | */ |
58 | public IncreaseProcessingRateImpl(Copy<Genotype> copy, DSEIndividualBuilder individualBuilder, DSEWorkflowConfiguration configuration) { |
59 | super(copy, individualBuilder, configuration, new String[] { |
60 | QMLConstantsContainer.QUALITY_ATTRIBUTE_DIMENSION_RESPONSETIME_DEFINITION_PATH, |
61 | QMLConstantsContainer.QUALITY_ATTRIBUTE_DIMENSION_THROUGHPUT_DEFINITION_PATH, |
62 | QMLConstantsContainer.QUALITY_ATTRIBUTE_DIMENSION_MAX_UTIL_DEFINITION_PATH}); |
63 | // set config |
64 | setHeuristicWeight(configuration.getProcessingRateWeight()); |
65 | increaseProcessingRateFactor = configuration.getProcessingRateIncreaseFactor(); |
66 | thresholdHighUtilisation = configuration.getProcessingRateThresholdHighUtilisation(); |
67 | |
68 | } |
69 | |
70 | /** |
71 | * Returns true if maximum utilisation is above or equals |
72 | * thresholdHighUtilisation and not null |
73 | * |
74 | * @param individual |
75 | * @param resourceType |
76 | * @return |
77 | */ |
78 | private boolean doesMatchHighUtilisation(DSEIndividual individual, UtilisationResultCacheAndHelper resultsCache, ResourceType resourceType) { |
79 | UtilisationResult maxUtilisationResult = resultsCache.getMaxProcUtilisationResult(individual, resourceType); |
80 | return maxUtilisationResult != null |
81 | && maxUtilisationResult.getResourceUtilisation() >= thresholdHighUtilisation; |
82 | } |
83 | |
84 | |
85 | |
86 | /** |
87 | * Check whether individual matches precondition. Precondition: Does a |
88 | * resource exists which is either highly or hardly utilised |
89 | * |
90 | * @param individual |
91 | * Individual to check |
92 | */ |
93 | public boolean doesMatchPrecondition(DSEIndividual individual, UtilisationResultCacheAndHelper resultsCache) { |
94 | |
95 | Set<ResourceType> resourceTypes = resultsCache.getResourceTypes(individual); |
96 | for (ResourceType resourceType : resourceTypes) { |
97 | boolean resourceTypeMatches = doesMatchHighUtilisation(individual, resultsCache, resourceType); |
98 | if (resourceTypeMatches){ |
99 | return true; |
100 | } |
101 | } |
102 | // Check whether there is one server with high or low utilization |
103 | return false; |
104 | } |
105 | |
106 | /** |
107 | * Generates candidates based on given individual |
108 | * |
109 | * @param Indivdual |
110 | * used to apply heuristic |
111 | * @return Collection of generated candidates. |
112 | */ |
113 | public List<TacticsResultCandidate> getHeuristicCandidates(DSEIndividual individual, UtilisationResultCacheAndHelper resultCache) { |
114 | List<TacticsResultCandidate> candidates = new ArrayList<TacticsResultCandidate>(); // return value |
115 | /* |
116 | * 1. Get maximum utilisation |
117 | * 2. Copy current genotype |
118 | * 3. Find processing resource by iterating through genotype and change |
119 | * processing rate and one with increased number of cores, if possible. |
120 | * 4. Add candidate to result collection |
121 | */ |
122 | // for all used resource types |
123 | Set<ResourceType> resourceTypes = resultCache.getResourceTypes(individual); |
124 | |
125 | for (ResourceType resourceType : resourceTypes) { |
126 | |
127 | if (resourceType.getEntityName().equals("DELAY")){ |
128 | continue; |
129 | } |
130 | |
131 | if (doesMatchHighUtilisation(individual, resultCache, resourceType)) { |
132 | addNewCandidatesWithIncreasedProcessingRateOrCores(individual, candidates, resultCache, resourceType); |
133 | } |
134 | |
135 | } |
136 | return candidates; |
137 | } |
138 | |
139 | /** |
140 | * @param individual |
141 | * @param candidates |
142 | * @param resourceType |
143 | */ |
144 | private void addNewCandidatesWithIncreasedProcessingRateOrCores(DSEIndividual individual, |
145 | Collection<TacticsResultCandidate> candidates, |
146 | UtilisationResultCacheAndHelper resultsCache, ResourceType resourceType) { |
147 | // 1. Get maximum utilisation |
148 | ProcessingResourceSpecificationResult maxUtilisationResult = resultsCache.getMaxProcUtilisationResult(individual, resourceType); |
149 | ProcessingResourceSpecification maxUtilProcessingResource = maxUtilisationResult.getProcessingResourceSpecification_ProcessingResourceSpecificationResult(); |
150 | addNewProcRateCandidate(individual, candidates, maxUtilisationResult, |
151 | maxUtilProcessingResource); |
152 | addNewNumberOfCoresCandidate(individual, candidates, maxUtilisationResult, |
153 | maxUtilProcessingResource); |
154 | } |
155 | |
156 | |
157 | |
158 | |
159 | |
160 | @Override |
161 | public double getCandidateWeight(UtilisationResult utilisationResult){ |
162 | return getCandidateWeightForHighUtilisation(utilisationResult); |
163 | } |
164 | |
165 | /** |
166 | * @param continousRangeChoice |
167 | * @param processingRateDegree |
168 | * @return |
169 | */ |
170 | @Override |
171 | protected double getUpdatedProcessingRate(ContinousRangeChoice continousRangeChoice, |
172 | ContinuousProcessingRateDegree processingRateDegree) { |
173 | return getIncreasedProcessingRate(continousRangeChoice, processingRateDegree); |
174 | } |
175 | |
176 | |
177 | |
178 | /** |
179 | * @param continousRangeChoice |
180 | * @param processingRateDegree |
181 | * @return |
182 | */ |
183 | private double getIncreasedProcessingRate(ContinousRangeChoice continousRangeChoice, |
184 | ContinuousProcessingRateDegree processingRateDegree) { |
185 | return Math.min(continousRangeChoice.getChosenValue() * (1 + increaseProcessingRateFactor), |
186 | processingRateDegree.getTo()); |
187 | } |
188 | |
189 | /** |
190 | * Calculates priority based on the following scheme: if utilisation lower than or equal to |
191 | * THRESHOLD_HIGH_UTLISATION then it will return 0, if utilisation equals 1 |
192 | * it will return 1. Values in between are linearly extrapolated. Return |
193 | * values will always be >= 0. |
194 | * |
195 | * @param utilisationResult |
196 | * @return Priority based on utilisationResult's utilisation |
197 | */ |
198 | private double getCandidateWeightForHighUtilisation(UtilisationResult utilisationResult) { |
199 | if (thresholdHighUtilisation >= 1) |
200 | //this case makes no sense, but capture anyway. |
201 | return 0; |
202 | |
203 | // return weight but at most 1 and at least 0. |
204 | return Math.min(1, Math.max(0, (utilisationResult.getResourceUtilisation() - thresholdHighUtilisation) / (1.0 - thresholdHighUtilisation))); |
205 | } |
206 | |
207 | @Override |
208 | protected int getUpdatedNumberOfCores(DiscreteRangeChoice discreteChoice, |
209 | NumberOfCoresDegree numberOfCoresDegree) { |
210 | |
211 | if (numberOfCoresDegree instanceof NumberOfCoresAsRangeDegree){ |
212 | NumberOfCoresAsRangeDegree asRangeDegree = (NumberOfCoresAsRangeDegree)numberOfCoresDegree; |
213 | return Math.min(discreteChoice.getChosenValue() + 1 , |
214 | asRangeDegree.isUpperBoundIncluded() ? asRangeDegree.getTo() : asRangeDegree.getTo() - 1); |
215 | |
216 | } else if (numberOfCoresDegree instanceof NumberOfCoresAsListDegree){ |
217 | NumberOfCoresAsListDegree asListDegree = (NumberOfCoresAsListDegree)numberOfCoresDegree; |
218 | // find next smallest integer after the current one. Do not assume that the list is ordered, although it should be |
219 | int nextLargestInteger = Integer.MAX_VALUE; |
220 | int currentValue = discreteChoice.getChosenValue(); |
221 | for (Integer value : asListDegree.getListOfIntegers()) { |
222 | if (value > currentValue && value <= nextLargestInteger){ |
223 | nextLargestInteger = value; |
224 | } |
225 | } |
226 | if (nextLargestInteger != Integer.MAX_VALUE){ |
227 | return nextLargestInteger; |
228 | } else { |
229 | // no larger value available (assuming max-int is not in the set of values...) |
230 | return currentValue; |
231 | } |
232 | } else throw new RuntimeException("Unknown degree of freedom "+numberOfCoresDegree.getClass().getName()+", please adjust "+this.getClass().getName()); |
233 | |
234 | } |
235 | |
236 | } |