1 | package de.uka.ipd.sdq.scheduler.resources.active; |
2 | |
3 | import java.util.ArrayDeque; |
4 | import java.util.Deque; |
5 | import java.util.Hashtable; |
6 | import java.util.Map.Entry; |
7 | |
8 | import de.uka.ipd.sdq.probfunction.math.util.MathTools; |
9 | import de.uka.ipd.sdq.scheduler.IRunningProcess; |
10 | import de.uka.ipd.sdq.scheduler.ISchedulableProcess; |
11 | import de.uka.ipd.sdq.scheduler.LoggingWrapper; |
12 | import de.uka.ipd.sdq.scheduler.SchedulerModel; |
13 | import de.uka.ipd.sdq.simulation.abstractsimengine.AbstractSimEventDelegator; |
14 | |
15 | public class SimFCFSResource extends AbstractActiveResource { |
16 | |
17 | private class ProcessingFinishedEvent extends AbstractSimEventDelegator<ISchedulableProcess> { |
18 | |
19 | public ProcessingFinishedEvent(SchedulerModel model) { |
20 | super(model, ProcessingFinishedEvent.class.getName()); |
21 | } |
22 | |
23 | @Override |
24 | public void eventRoutine(ISchedulableProcess process) { |
25 | ISchedulableProcess first = process; |
26 | toNow(); |
27 | assert MathTools.equalsDouble(0, running_processes.get(first)); |
28 | running_processes.remove(first); |
29 | processQ.remove(first); |
30 | fireStateChange(processQ.size(), 0); |
31 | fireDemandCompleted(first); |
32 | LoggingWrapper.log("Demand of Process "+ first + " finished."); |
33 | scheduleNextEvent(); |
34 | first.activate(); |
35 | } |
36 | |
37 | } |
38 | |
39 | private ProcessingFinishedEvent processingFinished; |
40 | private Deque<ISchedulableProcess> processQ = new ArrayDeque<ISchedulableProcess>(); |
41 | private Hashtable<ISchedulableProcess, Double> running_processes = new Hashtable<ISchedulableProcess, Double>(); |
42 | private double last_time; |
43 | |
44 | public SimFCFSResource(SchedulerModel model, String name, String id, int capacity) { |
45 | super(model, capacity, name, id); |
46 | processingFinished = new ProcessingFinishedEvent(model); |
47 | } |
48 | |
49 | public void scheduleNextEvent() { |
50 | ISchedulableProcess first = processQ.peek(); |
51 | processingFinished.removeEvent(); |
52 | if (first != null) { |
53 | double time = running_processes.get(first); |
54 | processingFinished.schedule(first, time); |
55 | } |
56 | } |
57 | |
58 | private void toNow() { |
59 | double now = getModel().getSimulationControl().getCurrentSimulationTime(); |
60 | double passed_time = now - last_time; |
61 | if (MathTools.less(0, passed_time)) { |
62 | ISchedulableProcess first = processQ.peek(); |
63 | if (first != null) { |
64 | double demand = running_processes.get(first); |
65 | demand -= passed_time; |
66 | |
67 | // avoid trouble caused by rounding issues |
68 | demand = MathTools.equalsDouble(demand, 0) ? 0.0 : demand; |
69 | |
70 | assert demand >= 0 : "Remaining demand ("+ demand +") smaller than zero!"; |
71 | |
72 | running_processes.put(first, demand); |
73 | } |
74 | } |
75 | last_time = now; |
76 | |
77 | } |
78 | |
79 | public void start() { |
80 | } |
81 | |
82 | @Override |
83 | protected void dequeue(ISchedulableProcess process) { |
84 | } |
85 | |
86 | @Override |
87 | protected void doProcessing(ISchedulableProcess process, int resourceServiceID, double demand) { |
88 | toNow(); |
89 | LoggingWrapper.log("FCFS: " + process + " demands " + demand); |
90 | running_processes.put(process, demand); |
91 | processQ.add(process); |
92 | fireStateChange(processQ.size(), 0); |
93 | scheduleNextEvent(); |
94 | process.passivate(); |
95 | } |
96 | |
97 | @Override |
98 | public double getRemainingDemand(ISchedulableProcess process) { |
99 | if (!running_processes.contains(process)) { |
100 | return 0.0; |
101 | } |
102 | toNow(); |
103 | return running_processes.get(process); |
104 | } |
105 | |
106 | @Override |
107 | public void updateDemand(ISchedulableProcess process, double demand) { |
108 | for (Entry<ISchedulableProcess,Double> e : running_processes.entrySet()) { |
109 | if (e.getKey().equals(process)) { |
110 | e.setValue(demand); |
111 | break; |
112 | } |
113 | } |
114 | scheduleNextEvent(); |
115 | } |
116 | |
117 | @Override |
118 | protected void enqueue(ISchedulableProcess process) { |
119 | } |
120 | |
121 | public void stop() { |
122 | // TODO: why are these fields not empty when the simulation stops, although AbstractActiveResource.cleanProcesses() |
123 | // is being called? This should be investigated, and the following cleanup should not be necessary. |
124 | // (this problem has been encountered for a linking resource) |
125 | processQ.clear(); |
126 | running_processes.clear(); |
127 | } |
128 | |
129 | public void registerProcess(IRunningProcess runningProcess) { |
130 | } |
131 | |
132 | public int getQueueLengthFor(SimResourceInstance simResourceInstance) { |
133 | return this.processQ.size(); |
134 | } |
135 | } |