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 javax.management.RuntimeErrorException; |
9 | |
10 | import org.opt4j.core.problem.Genotype; |
11 | import org.opt4j.operator.copy.Copy; |
12 | |
13 | import de.uka.ipd.sdq.dsexplore.exception.InvalidChoiceForDegreeException; |
14 | import de.uka.ipd.sdq.dsexplore.launch.DSEWorkflowConfiguration; |
15 | import de.uka.ipd.sdq.dsexplore.opt4j.optimizer.heuristic.operators.TacticsResultCandidate; |
16 | import de.uka.ipd.sdq.dsexplore.opt4j.optimizer.heuristic.operators.UtilisationResultCacheAndHelper; |
17 | import de.uka.ipd.sdq.dsexplore.opt4j.representation.DSEIndividual; |
18 | import de.uka.ipd.sdq.dsexplore.opt4j.representation.DSEIndividualBuilder; |
19 | import de.uka.ipd.sdq.dsexplore.qml.handling.QMLConstantsContainer; |
20 | import de.uka.ipd.sdq.pcm.designdecision.ContinousRangeChoice; |
21 | import de.uka.ipd.sdq.pcm.designdecision.ContinuousProcessingRateDegree; |
22 | import de.uka.ipd.sdq.pcm.designdecision.DiscreteRangeChoice; |
23 | import de.uka.ipd.sdq.pcm.designdecision.NumberOfCoresAsListDegree; |
24 | import de.uka.ipd.sdq.pcm.designdecision.NumberOfCoresAsRangeDegree; |
25 | import de.uka.ipd.sdq.pcm.designdecision.NumberOfCoresDegree; |
26 | import de.uka.ipd.sdq.pcm.resourceenvironment.ProcessingResourceSpecification; |
27 | import de.uka.ipd.sdq.pcm.resourcetype.ResourceType; |
28 | import de.uka.ipd.sdq.pcm.resultdecorator.resourceenvironmentdecorator.ProcessingResourceSpecificationResult; |
29 | import de.uka.ipd.sdq.pcm.resultdecorator.resourceenvironmentdecorator.UtilisationResult; |
30 | |
31 | /** |
32 | * This class implements an IHeuristic which decreases the processing rate of |
33 | * hardly utilized processing resources. |
34 | * |
35 | * XXX increase or decrease processing rate by a randomized demand, e.g. |
36 | * normally distributed around the given parameter value? |
37 | * |
38 | * @author martens, Tom Beyer |
39 | */ |
40 | public class DecreaseProcessingRateImpl extends AbstractProcessingRateTactic { |
41 | |
42 | /** |
43 | * Processing rate will be decreased by this factor if preconditions are |
44 | * fulfilled |
45 | */ |
46 | private double decreaseProcessingRateFactor; |
47 | |
48 | /** |
49 | * If utilisation is smaller than this double it will be considered a low |
50 | * utilisation |
51 | */ |
52 | private double thresholdLowUtilisation; |
53 | |
54 | public DecreaseProcessingRateImpl(Copy<Genotype> copy, |
55 | DSEIndividualBuilder individualBuilder, |
56 | DSEWorkflowConfiguration configuration) { |
57 | super(copy, individualBuilder, configuration, new String[] {QMLConstantsContainer.QUALITY_ATTRIBUTE_DIMENSION_COST_DEFINITION_PATH}); |
58 | setHeuristicWeight(configuration.getProcessingRateWeight()); |
59 | |
60 | decreaseProcessingRateFactor = configuration.getProcessingRateDecreaseFactor(); |
61 | thresholdLowUtilisation = configuration.getProcessingRateThresholdLowUtilisation(); |
62 | } |
63 | |
64 | public boolean doesMatchPrecondition(DSEIndividual i, UtilisationResultCacheAndHelper resultsCache) { |
65 | Set<ResourceType> resourceTypes = resultsCache.getResourceTypes(i); |
66 | |
67 | for (ResourceType resourceType : resourceTypes) { |
68 | boolean matches = doesMatchLowUtilisation(i, resultsCache, resourceType); |
69 | if (matches){ |
70 | return true; |
71 | } |
72 | } |
73 | return false; |
74 | } |
75 | |
76 | /** |
77 | * Generates candidates based on given individual |
78 | * |
79 | * @param Indivdual |
80 | * used to apply heuristic |
81 | * @return Collection of generated candidates. |
82 | */ |
83 | @Override |
84 | public List<TacticsResultCandidate> getHeuristicCandidates(DSEIndividual individual, UtilisationResultCacheAndHelper resultCache) { |
85 | List<TacticsResultCandidate> candidates = new ArrayList<TacticsResultCandidate>(); // return value |
86 | /* |
87 | * 1. Get minimum utilisation 2. Copy current genotype 3. Find |
88 | * processing resource by iterating through genotype and change |
89 | * processing rate 4. Add candidate to result collection |
90 | */ |
91 | Set<ResourceType> resourceTypes = resultCache.getResourceTypes(individual); |
92 | |
93 | for (ResourceType resourceType : resourceTypes) { |
94 | |
95 | if (resourceType.getEntityName().equals("DELAY")){ |
96 | continue; |
97 | } |
98 | |
99 | if (doesMatchLowUtilisation(individual, resultCache, resourceType)) { |
100 | addNewCandidateWithDecreasedProcessingRate(individual, candidates, resultCache, resourceType); |
101 | } |
102 | } |
103 | return candidates; |
104 | } |
105 | |
106 | /** |
107 | * Returns true if maximum utilisation is below or equals |
108 | * thresholdLowUtilisation and not null |
109 | * |
110 | * @param individual |
111 | * @param resourceType |
112 | * @return |
113 | */ |
114 | private boolean doesMatchLowUtilisation(DSEIndividual individual, UtilisationResultCacheAndHelper resultsCache, ResourceType resourceType) { |
115 | UtilisationResult minUtilisationResult = resultsCache.getMinProcUtilisationResult(individual, resourceType); |
116 | return minUtilisationResult != null |
117 | && minUtilisationResult.getResourceUtilisation() <= thresholdLowUtilisation; |
118 | } |
119 | |
120 | /** |
121 | * @param continousRangeChoice |
122 | * @param processingRateDegree |
123 | * @return |
124 | */ |
125 | private double getDecreasedProcessingRate(ContinousRangeChoice continousRangeChoice, |
126 | ContinuousProcessingRateDegree processingRateDegree) { |
127 | return Math.max(continousRangeChoice.getChosenValue() |
128 | * (1 - decreaseProcessingRateFactor), processingRateDegree.getFrom()); |
129 | } |
130 | |
131 | /** |
132 | * @param continousRangeChoice |
133 | * @param processingRateDegree |
134 | * @return |
135 | */ |
136 | @Override |
137 | protected double getUpdatedProcessingRate(ContinousRangeChoice continousRangeChoice, |
138 | ContinuousProcessingRateDegree processingRateDegree) { |
139 | return getDecreasedProcessingRate(continousRangeChoice, processingRateDegree); |
140 | } |
141 | |
142 | /** |
143 | * This first checks for the highest result, and then tries to find the |
144 | * respective degree of freedom. However, if the resource with the highest utilisation is not changeable, |
145 | * this method fails to provide a candidate. |
146 | * TODO: Find the highest utilisation among those resources that can be modified. |
147 | * @param individual |
148 | * @param candidates |
149 | * @param resourceType |
150 | */ |
151 | private void addNewCandidateWithDecreasedProcessingRate(DSEIndividual individual, |
152 | Collection<TacticsResultCandidate> candidates, |
153 | UtilisationResultCacheAndHelper resultsCache, ResourceType resourceType) { |
154 | // 1. Get minimum utilisation |
155 | ProcessingResourceSpecificationResult minUtilisationResult = resultsCache.getMinProcUtilisationResult(individual, resourceType); |
156 | ProcessingResourceSpecification minUtilProcessingResource = minUtilisationResult.getProcessingResourceSpecification_ProcessingResourceSpecificationResult(); |
157 | addNewProcRateCandidate(individual, candidates, minUtilisationResult, |
158 | minUtilProcessingResource); |
159 | } |
160 | |
161 | @Override |
162 | public double getCandidateWeight(UtilisationResult utilisationResult){ |
163 | return getCandidateWeightForLowUtilisation(utilisationResult); |
164 | } |
165 | |
166 | /** |
167 | * Calculates weight based on the following scheme: if utilisation higher than or equal to |
168 | * THRESHOLD_LOW_UTLISATION then it will return 0, if utilisation equals 0 |
169 | * it will return 1. Values in between are linearly extrapolated. Return |
170 | * values will always be >= 0. |
171 | * |
172 | * @param utilisationResult |
173 | * @return Weight based on utilisationResult's utilisation |
174 | */ |
175 | private double getCandidateWeightForLowUtilisation(UtilisationResult utilisationResult) { |
176 | if (thresholdLowUtilisation <= 0){ |
177 | // makes no sense, but capture anyways |
178 | return 0; |
179 | } |
180 | return Math.min(1, Math.max(thresholdLowUtilisation - utilisationResult.getResourceUtilisation() / thresholdLowUtilisation, 0.0)); |
181 | } |
182 | |
183 | |
184 | |
185 | @Override |
186 | protected int getUpdatedNumberOfCores(DiscreteRangeChoice discreteChoice, |
187 | NumberOfCoresDegree numberOfCoresDegree) { |
188 | if (numberOfCoresDegree instanceof NumberOfCoresAsRangeDegree){ |
189 | NumberOfCoresAsRangeDegree asRangeDegree = (NumberOfCoresAsRangeDegree)numberOfCoresDegree; |
190 | return Math.max(discreteChoice.getChosenValue() -1 , |
191 | asRangeDegree.isLowerBoundIncluded() ? asRangeDegree.getFrom() : asRangeDegree.getFrom() + 1); |
192 | } else if (numberOfCoresDegree instanceof NumberOfCoresAsListDegree){ |
193 | NumberOfCoresAsListDegree asListDegree = (NumberOfCoresAsListDegree)numberOfCoresDegree; |
194 | // find next smallest integer after the current one. Do not assume that the list is ordered, although it should be |
195 | int nextSmallestInteger = Integer.MIN_VALUE; |
196 | int currentValue = discreteChoice.getChosenValue(); |
197 | for (Integer value : asListDegree.getListOfIntegers()) { |
198 | if (value < currentValue && value >= nextSmallestInteger){ |
199 | nextSmallestInteger = value; |
200 | } |
201 | } |
202 | if (nextSmallestInteger != Integer.MIN_VALUE){ |
203 | return nextSmallestInteger; |
204 | } else { |
205 | // no smaller value available (assuming min-int is not in the set of values...) |
206 | return currentValue; |
207 | } |
208 | } else throw new RuntimeException("Unknown degree of freedom "+numberOfCoresDegree.getClass().getName()+", please adjust "+this.getClass().getName()); |
209 | |
210 | } |
211 | |
212 | } |