| 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 | } |