1 | package de.uka.ipd.sdq.dsexplore.opt4j.optimizer.heuristic.operators.impl; |
2 | |
3 | import java.util.ArrayList; |
4 | import java.util.LinkedList; |
5 | import java.util.List; |
6 | import java.util.Random; |
7 | import java.util.Set; |
8 | |
9 | import org.eclipse.emf.ecore.EObject; |
10 | import org.opt4j.core.problem.Genotype; |
11 | import org.opt4j.operator.copy.Copy; |
12 | |
13 | import de.uka.ipd.sdq.dsexplore.helper.EMFHelper; |
14 | import de.uka.ipd.sdq.dsexplore.launch.DSEWorkflowConfiguration; |
15 | import de.uka.ipd.sdq.dsexplore.opt4j.optimizer.heuristic.operators.AbstractTactic; |
16 | import de.uka.ipd.sdq.dsexplore.opt4j.optimizer.heuristic.operators.TacticsResultCandidate; |
17 | import de.uka.ipd.sdq.dsexplore.opt4j.optimizer.heuristic.operators.UtilisationResultCacheAndHelper; |
18 | import de.uka.ipd.sdq.dsexplore.opt4j.representation.DSEIndividual; |
19 | import de.uka.ipd.sdq.dsexplore.opt4j.representation.DSEIndividualBuilder; |
20 | import de.uka.ipd.sdq.dsexplore.qml.handling.QMLConstantsContainer; |
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.ClassChoice; |
24 | import de.uka.ipd.sdq.pcm.designdecision.ClassDegree; |
25 | import de.uka.ipd.sdq.pcm.resourceenvironment.ProcessingResourceSpecification; |
26 | import de.uka.ipd.sdq.pcm.resourceenvironment.ResourceContainer; |
27 | import de.uka.ipd.sdq.pcm.resourcetype.ResourceType; |
28 | import de.uka.ipd.sdq.pcm.resultdecorator.resourceenvironmentdecorator.UtilisationResult; |
29 | import de.uka.ipd.sdq.pcm.resultdecorator.resourceenvironmentdecorator.impl.ProcessingResourceSpecificationResultImpl; |
30 | |
31 | /** |
32 | * Implements a reallocation heuristic which allocates a component from |
33 | * a highly utilised resource container to a lowly utilised container |
34 | * |
35 | * TODO: Only works for a single resource type so far. |
36 | * |
37 | * @author martens, Tom Beyer |
38 | * |
39 | */ |
40 | public class ReallocationImpl extends AbstractTactic { |
41 | |
42 | /** |
43 | * If utilisation is larger than this double it will be considered |
44 | * a high utilisation |
45 | */ |
46 | private double thresholdUtilisationDifference; |
47 | |
48 | |
49 | private Random generator = new Random(); |
50 | |
51 | private UtilisationResultCacheAndHelper resultsCache = new UtilisationResultCacheAndHelper(); |
52 | |
53 | /** |
54 | * |
55 | * @param copy Used to copy genotype |
56 | * @param individualBuilder Used to build individual |
57 | */ |
58 | public ReallocationImpl(Copy<Genotype> copy, DSEIndividualBuilder individualBuilder, DSEWorkflowConfiguration configuration) { |
59 | super(copy, individualBuilder, configuration, new String[] {QMLConstantsContainer.QUALITY_ATTRIBUTE_DIMENSION_RESPONSETIME_DEFINITION_PATH, |
60 | QMLConstantsContainer.QUALITY_ATTRIBUTE_DIMENSION_THROUGHPUT_DEFINITION_PATH}); |
61 | // set config |
62 | setHeuristicWeight(configuration.getReallocationWeight()); |
63 | thresholdUtilisationDifference = configuration.getReallocationThresholdUtilisationDifference(); |
64 | } |
65 | |
66 | |
67 | /** |
68 | * Check whether there is one server with high utilization |
69 | * and one with low utilization which are both not null |
70 | * @param individual Individual to check |
71 | * @param resourceType |
72 | */ |
73 | public boolean doesMatchPrecondition(DSEIndividual individual, ResourceType resourceType) { |
74 | UtilisationResult minUtilisationResult = resultsCache.getMinProcUtilisationResult(individual, resourceType); |
75 | UtilisationResult maxUtilisationResult = resultsCache.getMaxProcUtilisationResult(individual, resourceType); |
76 | return minUtilisationResult != null && maxUtilisationResult != null && |
77 | maxUtilisationResult.getResourceUtilisation() - minUtilisationResult.getResourceUtilisation() |
78 | >= thresholdUtilisationDifference ; |
79 | } |
80 | |
81 | /** |
82 | * Generates collection of candidates by applying the reallocation heuristic |
83 | * @param individual Individual which the heuristic should be applied to |
84 | */ |
85 | public List<TacticsResultCandidate> getHeuristicCandidates(DSEIndividual individual, UtilisationResultCacheAndHelper resultCache) { |
86 | this.resultsCache = resultCache; |
87 | |
88 | // return value |
89 | List<TacticsResultCandidate> candidates = new ArrayList<TacticsResultCandidate>(); |
90 | |
91 | // for all used resource types |
92 | Set<ResourceType> resourceTypes = this.resultsCache.getResourceTypes(individual); |
93 | |
94 | for (ResourceType resourceType : resourceTypes) { |
95 | |
96 | if (doesMatchPrecondition(individual, resourceType)){ |
97 | // create new candidate (find servers), set priority and add to list candidates |
98 | UtilisationResult minUtilisationResult = resultsCache.getMinProcUtilisationResult(individual, resourceType); |
99 | UtilisationResult maxUtilisationResult = resultCache.getMaxProcUtilisationResult(individual, resourceType); |
100 | // create candidate |
101 | TacticsResultCandidate candidate = individualBuilder.buildCandidate(copy.copy(individual.getGenotype()), individual); |
102 | ProcessingResourceSpecification minProcessingResourceSpec = ((ProcessingResourceSpecificationResultImpl)minUtilisationResult).getProcessingResourceSpecification_ProcessingResourceSpecificationResult(); |
103 | ProcessingResourceSpecification maxProcessingResourceSpec = ((ProcessingResourceSpecificationResultImpl)maxUtilisationResult).getProcessingResourceSpecification_ProcessingResourceSpecificationResult(); |
104 | ResourceContainer targetResourceContainer = ((ResourceContainer)minProcessingResourceSpec.eContainer()); |
105 | ResourceContainer sourceResourceContainer = ((ResourceContainer)maxProcessingResourceSpec.eContainer()); |
106 | if (EMFHelper.checkIdentity(targetResourceContainer, sourceResourceContainer)) { |
107 | return candidates; |
108 | } |
109 | |
110 | List<ClassChoice> potentiallyReallocatedComponents = new LinkedList<ClassChoice>(); |
111 | // iterate through choices and change AllocationDegree |
112 | for (Choice choice : candidate.getGenotype()) { |
113 | if (choice instanceof ClassChoice) { |
114 | ClassChoice classChoice = (ClassChoice)choice; |
115 | if (classChoice.getDegreeOfFreedomInstance() instanceof AllocationDegree) { |
116 | AllocationDegree allocationDegree = (AllocationDegree)classChoice.getDegreeOfFreedomInstance(); |
117 | if (EMFHelper.checkIdentity(classChoice.getChosenValue(), sourceResourceContainer)) { |
118 | // check whether this component may be allocated to the minimum one |
119 | // XXX: Consider several servers with high or low utilization, as there is not necessarily a component that may be allocated from the highest to the lowest. Also consider second highest / lowest if none for the highest can be found. |
120 | for (EObject designOption : allocationDegree.getClassDesignOptions()) { |
121 | if (EMFHelper.checkIdentity(targetResourceContainer, designOption)) { |
122 | // this degree of freedom allows to allocate to the target container, |
123 | // so its component is a possible one to reallocate. |
124 | potentiallyReallocatedComponents.add(classChoice); |
125 | break; |
126 | } |
127 | } |
128 | } |
129 | } |
130 | } |
131 | } |
132 | |
133 | // if the size is one or smaller, there are no components to reallocate. |
134 | // we do not want to reallocate a single component (as that s server consolidation). |
135 | if (potentiallyReallocatedComponents.size() > 1){ |
136 | //reallocate just one component, choose it randomly. TODO: choose it more wisely, e.g. based on its demand. |
137 | int chosenComponentIndex = generator.nextInt(potentiallyReallocatedComponents.size()); |
138 | ClassChoice componentToReallocate = potentiallyReallocatedComponents.get(chosenComponentIndex); |
139 | componentToReallocate.setChosenValue( |
140 | EMFHelper.retrieveEntityByID( |
141 | ((ClassDegree)componentToReallocate.getDegreeOfFreedomInstance()).getClassDesignOptions(), |
142 | targetResourceContainer)); |
143 | |
144 | candidate.setCandidateWeight(getCandidateWeight(minUtilisationResult, maxUtilisationResult)); |
145 | candidate.setHeuristic(this); |
146 | candidates.add(candidate); |
147 | increaseCounterOfGeneratedCandidates(); |
148 | } |
149 | |
150 | } |
151 | } |
152 | return candidates; |
153 | } |
154 | |
155 | /** |
156 | * Calculates weight of the candidate using maxUtil-minUtil |
157 | * @param minUtilisationResult UtilisationResult with minimum utilisation |
158 | * @param maxUtilisationResult UtilisationResult with maximum utilisation |
159 | * @return Weight of candidate |
160 | */ |
161 | private double getCandidateWeight(UtilisationResult minUtilisationResult, |
162 | UtilisationResult maxUtilisationResult) { |
163 | return Math.min(1, maxUtilisationResult.getResourceUtilisation() - minUtilisationResult.getResourceUtilisation()); |
164 | } |
165 | |
166 | } |