1 | package de.uka.ipd.sdq.scheduler.loaddistribution.balancers; |
2 | |
3 | import java.util.List; |
4 | |
5 | import de.uka.ipd.sdq.scheduler.SchedulerModel; |
6 | import de.uka.ipd.sdq.scheduler.processes.IActiveProcess; |
7 | import de.uka.ipd.sdq.scheduler.processes.impl.PreemptiveProcess; |
8 | import de.uka.ipd.sdq.scheduler.resources.IResourceInstance; |
9 | |
10 | /** |
11 | * Ensures that the load of two resource instances does not differ more than |
12 | * 'threshold'. The threshold is a relative value between 0 and 1. If 0 the load |
13 | * of both instances must be equal, if 1 the load of both instances is never |
14 | * balanced. |
15 | * |
16 | * @author jens.happe |
17 | * |
18 | */ |
19 | public class ToThresholdBalancer extends AbstractLoadBalancer { |
20 | |
21 | private SchedulerModel model; |
22 | private double last_balanced = 0; |
23 | private int threshold; |
24 | |
25 | public ToThresholdBalancer(SchedulerModel model, double balancing_interval, |
26 | boolean prio_increasing, boolean queue_ascending, int threshold) { |
27 | super(balancing_interval, prio_increasing, queue_ascending); |
28 | this.model = model; |
29 | this.threshold = threshold; |
30 | } |
31 | |
32 | public void activelyBalance(IResourceInstance instance) { |
33 | double now = model.getSimulationControl().getCurrentSimulationTime(); |
34 | if ((now - last_balanced) > balancing_interval) { |
35 | balance(getBusiest(), getLaziest()); |
36 | last_balanced = now; |
37 | } |
38 | } |
39 | |
40 | public void onFork(IResourceInstance instance) { |
41 | balance(instance, getLaziest()); |
42 | } |
43 | |
44 | public void onSleep(IResourceInstance instance) { |
45 | if (load(instance) == 0) { |
46 | balance(getBusiest(), instance); |
47 | } |
48 | } |
49 | |
50 | public void onTerminate(IResourceInstance instance) { |
51 | if (load(instance) == 0) { |
52 | balance(getBusiest(), instance); |
53 | } |
54 | } |
55 | |
56 | public void onWake(IResourceInstance instance) { |
57 | balance(instance,getLaziest()); |
58 | } |
59 | |
60 | private void balance(IResourceInstance sender, IResourceInstance receiver) { |
61 | if (sender != null && receiver != null) { |
62 | if (!sender.equals(receiver)) { |
63 | int distance = load(sender) - load(receiver); |
64 | if (distance > threshold) { |
65 | List<IActiveProcess> processList = queue_holder |
66 | .getRunQueueFor(sender).identifyMovableProcesses( |
67 | receiver, prio_increasing, queue_ascending, |
68 | distance / 2); |
69 | for (IActiveProcess process : processList) { |
70 | fakeThreadLoadBalancing(process, sender, receiver); |
71 | //queue_holder.move(process, sender, receiver); |
72 | } |
73 | } |
74 | } |
75 | } |
76 | } |
77 | |
78 | /** |
79 | * From the beautiful method name, the careful reader might have guessed |
80 | * that things get a bit, well, messy at this point. Fact is, that Windows |
81 | * (or Java ?) balances threads differently from processes by simply |
82 | * changing the association between light weight processes and (user level) |
83 | * threads. That makes things a bit difficult as heavy weight and light |
84 | * weight processes as well as threads would have to be reflected in the |
85 | * model. |
86 | * |
87 | * Sorry for anyone responsible fixing this, but I hope this comment helps. |
88 | * Further discussion can be found in class 'SimResourceInstance' at |
89 | * variable 'last_running_process'. |
90 | * |
91 | * @param process |
92 | * moved process |
93 | * @param sender |
94 | * sending resource instance |
95 | * @param receiver |
96 | * receiving resource instance |
97 | */ |
98 | private void fakeThreadLoadBalancing(IActiveProcess process, |
99 | IResourceInstance sender, IResourceInstance receiver) { |
100 | if (receiver.getLastRunningProcess() != null) { |
101 | PreemptiveProcess p = (PreemptiveProcess) receiver.getLastRunningProcess(); |
102 | |
103 | // here we assume that the waiting process is in fact a thread that |
104 | // belongs to the same process as the thread (process) to move. |
105 | // the following assigns the waiting thread to the resource of |
106 | // the sender. This fakes the switch of LWPs. |
107 | if (p.isWaiting()) { |
108 | p.setLastInstance(process.getLastInstance()); |
109 | p.setIdealInstance(process.getIdealInstance()); |
110 | } |
111 | } |
112 | queue_holder.move(process, sender, receiver); |
113 | } |
114 | |
115 | |
116 | private IResourceInstance getLaziest() { |
117 | IResourceInstance result = null; |
118 | for (IResourceInstance ri : queue_holder.getResourceInstances()) { |
119 | if (result == null || load(ri) < load(result)) { |
120 | result = ri; |
121 | } |
122 | } |
123 | return result; |
124 | } |
125 | |
126 | private IResourceInstance getBusiest() { |
127 | IResourceInstance result = null; |
128 | for (IResourceInstance ri : queue_holder.getResourceInstances()) { |
129 | if (result == null || load(ri) > load(result)) { |
130 | result = ri; |
131 | } |
132 | } |
133 | return result; |
134 | } |
135 | } |