diff options
| author | Jeremy Erickson <jerickso@cs.unc.edu> | 2012-09-20 20:41:44 -0400 |
|---|---|---|
| committer | Jeremy Erickson <jerickso@cs.unc.edu> | 2012-09-25 12:39:56 -0400 |
| commit | 37dbd04e4f9d8956cf4be1c196e282760aa37011 (patch) | |
| tree | d2d2994c5dd697ec493555b22bbce999e1bfe4ba /native/src | |
| parent | 8ba27be920e6bd47442e33946783a38c0fa37356 (diff) | |
Initial GEL Piecewise Linear implementation
Diffstat (limited to 'native/src')
| -rw-r--r-- | native/src/edf/gel_pl.cpp | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/native/src/edf/gel_pl.cpp b/native/src/edf/gel_pl.cpp new file mode 100644 index 0000000..53ae575 --- /dev/null +++ b/native/src/edf/gel_pl.cpp | |||
| @@ -0,0 +1,206 @@ | |||
| 1 | #include "tasks.h" | ||
| 2 | |||
| 3 | #include "edf/gel_pl.h" | ||
| 4 | |||
| 5 | #include <vector> | ||
| 6 | #include <limits> | ||
| 7 | #include <algorithm> | ||
| 8 | #include <cmath> | ||
| 9 | |||
| 10 | static bool reversed_order(double first, double second) { | ||
| 11 | return second < first; | ||
| 12 | } | ||
| 13 | |||
| 14 | GELPl::GELPl(Scheduler sched, unsigned int num_processors, const TaskSet& ts, | ||
| 15 | unsigned int num_rounds) | ||
| 16 | :no_cpus(num_processors), tasks(ts), rounds(num_rounds) | ||
| 17 | { | ||
| 18 | std::vector<unsigned long> pps; | ||
| 19 | double S; | ||
| 20 | std::vector<double> Y_ints; | ||
| 21 | |||
| 22 | int task_count = tasks.get_task_count(); | ||
| 23 | // Reserve capacity in all vectors to minimize allocation costs. | ||
| 24 | pps.reserve(task_count); | ||
| 25 | Y_ints.reserve(task_count); | ||
| 26 | S_i.reserve(task_count); | ||
| 27 | G_i.reserve(task_count); | ||
| 28 | |||
| 29 | // For faster lookups | ||
| 30 | utilizations.reserve(task_count); | ||
| 31 | for (int i = 0; i < task_count; i++) { | ||
| 32 | utilizations.push_back(double(tasks[i].get_wcet()) | ||
| 33 | / double(tasks[i].get_period())); | ||
| 34 | } | ||
| 35 | |||
| 36 | unsigned long min_pp = std::numeric_limits<unsigned long>::max(); | ||
| 37 | |||
| 38 | // Compute initial priority points, including minimum. | ||
| 39 | for (int i = 0; i < task_count; i++) { | ||
| 40 | const Task& task = tasks[i]; | ||
| 41 | unsigned long new_pp = task.get_deadline(); | ||
| 42 | if (sched == GFL) { | ||
| 43 | new_pp -= ((num_processors - 1) * task.get_wcet()) / num_processors; | ||
| 44 | } | ||
| 45 | pps.push_back(new_pp); | ||
| 46 | if (new_pp < min_pp) { | ||
| 47 | min_pp = new_pp; | ||
| 48 | } | ||
| 49 | } | ||
| 50 | |||
| 51 | // Reduce to compute minimum. Also compute Y intercepts, S_i values, and | ||
| 52 | // S. | ||
| 53 | S = 0.0; | ||
| 54 | for (int i = 0; i < task_count; i++) { | ||
| 55 | pps[i] -= min_pp; | ||
| 56 | const Task& task = tasks[i]; | ||
| 57 | double wcet = double(task.get_wcet()); | ||
| 58 | double period = double(task.get_period()); | ||
| 59 | S_i[i] = std::max(0.0, wcet * (1.0 - double(pps[i])/ period)); | ||
| 60 | S += S_i[i]; | ||
| 61 | Y_ints.push_back((0.0 - wcet/no_cpus) * (wcet / period) | ||
| 62 | + task.get_wcet() - S_i[i]); | ||
| 63 | } | ||
| 64 | |||
| 65 | double s; | ||
| 66 | if (rounds == 0) { | ||
| 67 | s = compute_exact_s(S, Y_ints); | ||
| 68 | } | ||
| 69 | else { | ||
| 70 | s = compute_binsearch_s(S, Y_ints); | ||
| 71 | } | ||
| 72 | |||
| 73 | for (int i = 0; i < task_count; i++) { | ||
| 74 | bounds.push_back(pps[i] | ||
| 75 | + tasks[i].get_wcet() | ||
| 76 | + (unsigned long)std::ceil( | ||
| 77 | s - (double(tasks[i].get_wcet() / double(no_cpus))))); | ||
| 78 | G_i.push_back(Y_ints[i] + s * utilizations[i]); | ||
| 79 | } | ||
| 80 | } | ||
| 81 | |||
| 82 | double GELPl::compute_exact_s(double S, const std::vector<double>& Y_ints) { | ||
| 83 | int task_count = tasks.get_task_count(); | ||
| 84 | |||
| 85 | std::vector<ReplacementType> replacements; | ||
| 86 | for (int i = 0; i < task_count; i++) { | ||
| 87 | for (int j = i + 1; j < task_count; j++) { | ||
| 88 | // We can ignore parallel and identical lines - either don't | ||
| 89 | // intersect or we don't care which is picked. | ||
| 90 | if (utilizations[i] != utilizations[j]) { | ||
| 91 | double intersect = (Y_ints[j] - Y_ints[i]) | ||
| 92 | / (utilizations[i] - utilizations[j]); | ||
| 93 | ReplacementType replacement; | ||
| 94 | replacement.location = intersect; | ||
| 95 | if (intersect >= 0.0) { | ||
| 96 | if (utilizations[i] < utilizations[j]) { | ||
| 97 | replacement.old_task = i; | ||
| 98 | replacement.old_task_utilization = utilizations[i]; | ||
| 99 | replacement.new_task = j; | ||
| 100 | } | ||
| 101 | else { | ||
| 102 | replacement.old_task = j; | ||
| 103 | replacement.old_task_utilization = utilizations[j]; | ||
| 104 | replacement.new_task = i; | ||
| 105 | } | ||
| 106 | replacements.push_back(replacement); | ||
| 107 | } | ||
| 108 | } | ||
| 109 | } | ||
| 110 | } | ||
| 111 | std::sort(replacements.begin(), replacements.end()); | ||
| 112 | |||
| 113 | std::vector<bool> task_pres; | ||
| 114 | task_pres.assign(task_count, false); | ||
| 115 | |||
| 116 | double current_value = S; | ||
| 117 | double current_slope = -1 * no_cpus; | ||
| 118 | |||
| 119 | std::vector<TaggedValue> init_pairs; | ||
| 120 | init_pairs.reserve(task_count); | ||
| 121 | for (int i = 0; i < task_count; i++) { | ||
| 122 | TaggedValue new_pair; | ||
| 123 | new_pair.task = i; | ||
| 124 | new_pair.value = Y_ints[i]; | ||
| 125 | init_pairs.push_back(new_pair); | ||
| 126 | } | ||
| 127 | |||
| 128 | // Allows us to efficiently compute sum of top m-1 elements. They may not | ||
| 129 | // be in order but must be the correct choices. | ||
| 130 | std::nth_element(init_pairs.begin(), init_pairs.begin() + no_cpus - 2, | ||
| 131 | init_pairs.end()); | ||
| 132 | |||
| 133 | for (int i = 0; i < no_cpus - 1; i++) { | ||
| 134 | unsigned int task_index = init_pairs[i].task; | ||
| 135 | task_pres[task_index] = true; | ||
| 136 | current_value += init_pairs[i].value; | ||
| 137 | current_slope += utilizations[task_index]; | ||
| 138 | } | ||
| 139 | |||
| 140 | unsigned int rindex = 0; | ||
| 141 | double next_s = 0.0; | ||
| 142 | double zero = std::numeric_limits<double>::infinity(); | ||
| 143 | while (zero > next_s) { | ||
| 144 | double current_s = next_s; | ||
| 145 | zero = current_s - current_value / current_slope; | ||
| 146 | if (rindex < replacements.size()) { | ||
| 147 | ReplacementType replacement = replacements[rindex]; | ||
| 148 | next_s = replacement.location; | ||
| 149 | current_value += (next_s - current_s) * current_slope; | ||
| 150 | // Apply replacement, if appropriate | ||
| 151 | if (task_pres[replacement.old_task] | ||
| 152 | && !task_pres[replacement.new_task]) { | ||
| 153 | task_pres[replacement.old_task] = false; | ||
| 154 | current_slope -= utilizations[replacement.old_task]; | ||
| 155 | task_pres[replacement.new_task] = true; | ||
| 156 | current_slope += utilizations[replacement.new_task]; | ||
| 157 | } | ||
| 158 | rindex++; | ||
| 159 | } | ||
| 160 | else { | ||
| 161 | next_s = std::numeric_limits<double>::infinity(); | ||
| 162 | } | ||
| 163 | } | ||
| 164 | return zero; | ||
| 165 | } | ||
| 166 | |||
| 167 | double GELPl::compute_binsearch_s(double S, const std::vector<double>& Y_ints) { | ||
| 168 | double min_s = 0.0; | ||
| 169 | double max_s = 1.0; | ||
| 170 | while (compute_M(max_s, S, Y_ints) > 0) { | ||
| 171 | min_s = max_s; | ||
| 172 | max_s *= 2.0; | ||
| 173 | } | ||
| 174 | |||
| 175 | for (int i = 0; i < rounds; i++) { | ||
| 176 | double middle = (min_s + max_s) / 2.0; | ||
| 177 | if (compute_M(middle, S, Y_ints) < 0) { | ||
| 178 | max_s = middle; | ||
| 179 | } | ||
| 180 | else { | ||
| 181 | min_s = middle; | ||
| 182 | } | ||
| 183 | } | ||
| 184 | |||
| 185 | // max_s is guaranteed to be a legal bound. | ||
| 186 | return max_s; | ||
| 187 | } | ||
| 188 | |||
| 189 | double GELPl::compute_M(double s, double S, const std::vector<double>& Y_ints) { | ||
| 190 | std::vector<double> Gvals; | ||
| 191 | int task_count = tasks.get_task_count(); | ||
| 192 | for (int i = 0; i < task_count; i++) { | ||
| 193 | Gvals.push_back(Y_ints[i] + utilizations[i] * s); | ||
| 194 | } | ||
| 195 | |||
| 196 | // Again, more efficient computation by not totally sorting. | ||
| 197 | std::nth_element(Gvals.begin(), Gvals.begin() + no_cpus - 2, Gvals.end(), | ||
| 198 | reversed_order); | ||
| 199 | double to_return = S - no_cpus * s; | ||
| 200 | |||
| 201 | for (int i = 0; i < no_cpus - 1; i++) { | ||
| 202 | to_return += Gvals[i]; | ||
| 203 | } | ||
| 204 | |||
| 205 | return to_return; | ||
| 206 | } | ||
