1 | package de.uka.ipd.sdq.scheduler.sensors.impl; |
2 | |
3 | import de.uka.ipd.sdq.scheduler.SchedulerModel; |
4 | import de.uka.ipd.sdq.scheduler.processes.IActiveProcess; |
5 | import de.uka.ipd.sdq.scheduler.processes.PROCESS_STATE; |
6 | import de.uka.ipd.sdq.scheduler.processes.impl.ProcessWithPriority; |
7 | import de.uka.ipd.sdq.scheduler.sensors.IProcessStateSensor; |
8 | |
9 | public class SleepAverageSensor implements IProcessStateSensor { |
10 | |
11 | private SchedulerModel model; |
12 | private PROCESS_STATE last_state; |
13 | private double lastUpdateTime; |
14 | private double sleep_average; |
15 | private double max_sleep_average; |
16 | private int max_bonus; |
17 | private IActiveProcess process; |
18 | private int last_bonus; |
19 | |
20 | private static double FACTOR = 0.5; |
21 | |
22 | public SleepAverageSensor(SchedulerModel model, IActiveProcess process, double max_sleep_average, |
23 | int max_bonus) { |
24 | this.model = model; |
25 | this.lastUpdateTime = model.getSimulationControl().getCurrentSimulationTime(); |
26 | this.last_state = process.getState(); |
27 | this.max_sleep_average = max_sleep_average; |
28 | this.max_bonus = max_bonus; |
29 | this.process = process; |
30 | this.last_bonus = (int) Math.ceil(max_bonus * FACTOR); |
31 | this.sleep_average = interactiveSleep((ProcessWithPriority) process); |
32 | this.update(process.getState()); |
33 | } |
34 | |
35 | public double getSleepAverage() { |
36 | update(last_state); |
37 | return sleep_average; |
38 | } |
39 | |
40 | public double getMaxSleepAverage() { |
41 | return max_sleep_average; |
42 | } |
43 | |
44 | public void update(PROCESS_STATE new_state) { |
45 | double currentTime = model.getSimulationControl().getCurrentSimulationTime(); |
46 | double passedTime = currentTime - lastUpdateTime; |
47 | |
48 | // Process was waiting |
49 | // Please note that the waiting period lasts |
50 | // until the process starts running, i.e., also |
51 | // its time in the ready queue counts as waiting |
52 | // time. |
53 | if (last_state == PROCESS_STATE.WAITING) { |
54 | // sleepAverage cannot exceed its maximum value |
55 | sleep_average = Math.min(max_sleep_average, sleep_average |
56 | + Math.floor(passedTime) ); |
57 | } |
58 | |
59 | // Process was running |
60 | if (last_state == PROCESS_STATE.RUNNING) { |
61 | // corresponds to Linux scheduler code (2.6.22) |
62 | // sched.c, line 3622 |
63 | // run_time /= (CURRENT_BONUS(prev) ? : 1); |
64 | passedTime /= (last_bonus > 0 ? last_bonus : 1); |
65 | sleep_average = Math.max(0, sleep_average - passedTime); |
66 | } |
67 | |
68 | lastUpdateTime = currentTime; |
69 | |
70 | // only remember the new state if we are not in a waiting period |
71 | // otherwise keep the waiting state until the process is running again |
72 | // ... that's the way it is realized in the Linux scheduler. So, don't |
73 | // blame me. |
74 | if (!(last_state == PROCESS_STATE.WAITING && new_state != PROCESS_STATE.RUNNING)) { |
75 | last_state = new_state; |
76 | } |
77 | } |
78 | |
79 | public int getCurrentBonus() { |
80 | // corresponds to Linux scheduler code (2.6.22) |
81 | // sched.c, line 142 |
82 | // #define CURRENT_BONUS(p) \ |
83 | // (NS_TO_JIFFIES((p)->sleep_avg) * MAX_BONUS / \ |
84 | // MAX_SLEEP_AVG) |
85 | |
86 | // update the sleep average to get the priorities right... |
87 | update(last_state); |
88 | |
89 | last_bonus = (int) Math.floor(((double)msToJiffies(sleep_average) * max_bonus) / (double)msToJiffies(max_sleep_average)); |
90 | return last_bonus; |
91 | } |
92 | |
93 | |
94 | /** |
95 | * Converts exact simulation time to the linux' scheduler internal time |
96 | * values called jiffies. A jiffies represent the current time as the number |
97 | * of scheduler clock ticks, i.e. they are less exact. |
98 | * |
99 | * @param time |
100 | * time in milliseconds |
101 | * @return scheduler time in jiffies |
102 | */ |
103 | public int msToJiffies(double time) { |
104 | // Please note that the divisor depends on the actual HZ rate of the scheduler. |
105 | int jiffies = (int) Math.ceil((time) / 10.0 ); |
106 | return jiffies; |
107 | } |
108 | |
109 | public double jiffiesToMs(int jiffies) { |
110 | // Please note that the divisor depends on the actual HZ rate of the scheduler. (1000 / HZ) |
111 | return (double) jiffies * 10; |
112 | } |
113 | |
114 | public double interactiveSleep(ProcessWithPriority p){ |
115 | // #define SCALE(v1,v1_max,v2_max) \ |
116 | // (v1) * (v2_max) / (v1_max) |
117 | // (SCALE(TASK_NICE(p) + 20, 40, MAX_BONUS) |
118 | int scale = ((p.getDynamicPriority().getValue() + 20) * max_bonus) / 40; |
119 | |
120 | // #define DELTA(p) \ |
121 | // (SCALE(TASK_NICE(p) + 20, 40, MAX_BONUS) - 20 * MAX_BONUS / 40 + \ |
122 | // INTERACTIVE_DELTA) |
123 | int delta = scale - (20 * max_bonus) / 40 + 2; |
124 | |
125 | //(MAX_SLEEP_AVG * (MAX_BONUS / 2 + DELTA((p)) + 1) / MAX_BONUS - 1) |
126 | int result = (msToJiffies(max_sleep_average) * (max_bonus / 2 + delta + 1)) / max_bonus - 1; |
127 | |
128 | //JIFFIES_TO_NS(...) |
129 | return jiffiesToMs(result); |
130 | |
131 | // this would be the simplified variant of the code above. |
132 | // return (int) (max_sleep_average * (3.0d / max_bonus + 0.5 + p.getStaticPriority().getValue() / 40.0d) - 1.0); |
133 | } |
134 | } |