diff options
| author | Bjoern Brandenburg <bbb@mpi-sws.org> | 2012-05-16 12:01:56 -0400 |
|---|---|---|
| committer | Bjoern Brandenburg <bbb@mpi-sws.org> | 2012-05-16 12:01:56 -0400 |
| commit | 546b17c0f6360f4e83e6f0dda8db99656aa94077 (patch) | |
| tree | c5e52133b35b2fe5fd0e76b6ddafc71232e04e7a /native/src/blocking | |
| parent | f906d6f40b3f447fd1ba65df3f5e4406972a2331 (diff) | |
Move MPPC++: Break out the MPCP code into own file
Part of refactoring sharedres.cpp.
Diffstat (limited to 'native/src/blocking')
| -rw-r--r-- | native/src/blocking/mpcp.cpp | 320 |
1 files changed, 320 insertions, 0 deletions
diff --git a/native/src/blocking/mpcp.cpp b/native/src/blocking/mpcp.cpp new file mode 100644 index 0000000..8b87556 --- /dev/null +++ b/native/src/blocking/mpcp.cpp | |||
| @@ -0,0 +1,320 @@ | |||
| 1 | #include "sharedres.h" | ||
| 2 | #include "blocking.h" | ||
| 3 | |||
| 4 | #include "stl-helper.h" | ||
| 5 | #include "math-helper.h" | ||
| 6 | |||
| 7 | // *************************** MPCP ****************************************** | ||
| 8 | |||
| 9 | |||
| 10 | typedef std::vector<unsigned int> PriorityCeilings; | ||
| 11 | |||
| 12 | static void determine_priority_ceilings(const Resources& resources, | ||
| 13 | PriorityCeilings& ceilings) | ||
| 14 | { | ||
| 15 | ceilings.reserve(resources.size()); | ||
| 16 | |||
| 17 | foreach(resources, it) | ||
| 18 | { | ||
| 19 | unsigned int ceiling = UINT_MAX; | ||
| 20 | const ContentionSet& cs = *it; | ||
| 21 | |||
| 22 | foreach(cs, jt) | ||
| 23 | { | ||
| 24 | const RequestBound* req = *jt; | ||
| 25 | ceiling = std::min(ceiling, req->get_task()->get_priority()); | ||
| 26 | } | ||
| 27 | |||
| 28 | ceilings.push_back(ceiling); | ||
| 29 | } | ||
| 30 | } | ||
| 31 | |||
| 32 | typedef std::vector<unsigned long> ResponseTimes; | ||
| 33 | typedef std::vector<ResponseTimes> TaskResponseTimes; | ||
| 34 | typedef std::vector<TaskResponseTimes> ClusterResponseTimes; | ||
| 35 | |||
| 36 | static unsigned long get_max_gcs_length(const TaskInfo* tsk, | ||
| 37 | const PriorityCeilings& ceilings, | ||
| 38 | unsigned int preempted_ceiling) | ||
| 39 | { | ||
| 40 | unsigned long gcs_length = 0; | ||
| 41 | |||
| 42 | foreach(tsk->get_requests(), it) | ||
| 43 | { | ||
| 44 | unsigned int prio = ceilings[it->get_resource_id()]; | ||
| 45 | if (prio < preempted_ceiling) | ||
| 46 | gcs_length = std::max(gcs_length, | ||
| 47 | (unsigned long) it->get_request_length()); | ||
| 48 | } | ||
| 49 | |||
| 50 | return gcs_length; | ||
| 51 | } | ||
| 52 | |||
| 53 | static void determine_gcs_response_times(const TaskInfo* tsk, | ||
| 54 | const Cluster& cluster, | ||
| 55 | const PriorityCeilings& ceilings, | ||
| 56 | ResponseTimes& times) | ||
| 57 | { | ||
| 58 | times.reserve(tsk->get_requests().size()); | ||
| 59 | |||
| 60 | foreach(tsk->get_requests(), it) | ||
| 61 | { | ||
| 62 | unsigned long resp = it->get_request_length(); | ||
| 63 | unsigned int prio = ceilings[it->get_resource_id()]; | ||
| 64 | |||
| 65 | // Equation (2) in LNR:09. | ||
| 66 | // One request of each local gcs that can preempt our ceiling, | ||
| 67 | // but at most one per task (since tasks are sequential). | ||
| 68 | |||
| 69 | foreach(cluster, jt) | ||
| 70 | { | ||
| 71 | const TaskInfo* t = *jt; | ||
| 72 | |||
| 73 | if (t != tsk) | ||
| 74 | resp += get_max_gcs_length(t, ceilings, prio); | ||
| 75 | } | ||
| 76 | |||
| 77 | times.push_back(resp); | ||
| 78 | } | ||
| 79 | } | ||
| 80 | |||
| 81 | static void determine_gcs_response_times(const Cluster& cluster, | ||
| 82 | const PriorityCeilings& ceilings, | ||
| 83 | TaskResponseTimes& times) | ||
| 84 | { | ||
| 85 | times.reserve(cluster.size()); | ||
| 86 | foreach(cluster, it) | ||
| 87 | { | ||
| 88 | times.push_back(ResponseTimes()); | ||
| 89 | determine_gcs_response_times(*it, cluster, ceilings, | ||
| 90 | times.back()); | ||
| 91 | } | ||
| 92 | } | ||
| 93 | |||
| 94 | static void determine_gcs_response_times(const Clusters& clusters, | ||
| 95 | const PriorityCeilings& ceilings, | ||
| 96 | ClusterResponseTimes& times) | ||
| 97 | { | ||
| 98 | times.reserve(clusters.size()); | ||
| 99 | foreach(clusters, it) | ||
| 100 | { | ||
| 101 | times.push_back(TaskResponseTimes()); | ||
| 102 | determine_gcs_response_times(*it, ceilings, times.back()); | ||
| 103 | } | ||
| 104 | } | ||
| 105 | |||
| 106 | static unsigned long response_time_for(unsigned int res_id, | ||
| 107 | unsigned long interval, | ||
| 108 | const TaskInfo* tsk, | ||
| 109 | const ResponseTimes& resp, | ||
| 110 | bool multiple) | ||
| 111 | { | ||
| 112 | const Requests& requests = tsk->get_requests(); | ||
| 113 | unsigned int i = 0; | ||
| 114 | |||
| 115 | for (i = 0; i < requests.size(); i++) | ||
| 116 | if (requests[i].get_resource_id() == res_id) | ||
| 117 | { | ||
| 118 | if (multiple) | ||
| 119 | { | ||
| 120 | // Equation (3) in LNR:09. | ||
| 121 | // How many jobs? | ||
| 122 | unsigned long num_jobs; | ||
| 123 | num_jobs = divide_with_ceil(interval, tsk->get_period()); | ||
| 124 | num_jobs += 1; | ||
| 125 | |||
| 126 | // Note: this may represent multiple gcs, so multiply. | ||
| 127 | return num_jobs * resp[i] * requests[i].get_num_requests(); | ||
| 128 | } | ||
| 129 | else | ||
| 130 | // Just one request. | ||
| 131 | return resp[i]; | ||
| 132 | } | ||
| 133 | // if we get here, then the task does not access res_id | ||
| 134 | return 0; | ||
| 135 | } | ||
| 136 | |||
| 137 | static unsigned long mpcp_remote_blocking(unsigned int res_id, | ||
| 138 | unsigned long interval, | ||
| 139 | const TaskInfo* tsk, | ||
| 140 | const Cluster& cluster, | ||
| 141 | const TaskResponseTimes times, | ||
| 142 | unsigned long& max_lower) | ||
| 143 | { | ||
| 144 | unsigned int i; | ||
| 145 | unsigned long blocking = 0; | ||
| 146 | |||
| 147 | // consider each task in cluster | ||
| 148 | for (i = 0; i < cluster.size(); i++) | ||
| 149 | { | ||
| 150 | const TaskInfo* t = cluster[i]; | ||
| 151 | if (t != tsk) | ||
| 152 | { | ||
| 153 | if (t->get_priority() < tsk->get_priority()) | ||
| 154 | // This is a higher-priority task; | ||
| 155 | // it can block multiple times. | ||
| 156 | blocking += response_time_for(res_id, interval, | ||
| 157 | t, times[i], true); | ||
| 158 | else | ||
| 159 | // This is a lower-priority task; | ||
| 160 | // it can block only once. | ||
| 161 | max_lower = std::max(max_lower, | ||
| 162 | response_time_for(res_id, interval, | ||
| 163 | t, times[i], false)); | ||
| 164 | } | ||
| 165 | } | ||
| 166 | |||
| 167 | return blocking; | ||
| 168 | } | ||
| 169 | |||
| 170 | static unsigned long mpcp_remote_blocking(unsigned int res_id, | ||
| 171 | unsigned long interval, | ||
| 172 | const TaskInfo* tsk, | ||
| 173 | const Clusters& clusters, | ||
| 174 | const ClusterResponseTimes times, | ||
| 175 | unsigned long& max_lower) | ||
| 176 | { | ||
| 177 | unsigned int i; | ||
| 178 | unsigned long blocking; | ||
| 179 | |||
| 180 | max_lower = 0; | ||
| 181 | blocking = 0; | ||
| 182 | |||
| 183 | for (i = 0; i < clusters.size(); i++) | ||
| 184 | { | ||
| 185 | blocking += mpcp_remote_blocking(res_id, interval, | ||
| 186 | tsk, clusters[i], times[i], | ||
| 187 | max_lower); | ||
| 188 | } | ||
| 189 | return blocking; | ||
| 190 | } | ||
| 191 | |||
| 192 | static unsigned long mpcp_remote_blocking(unsigned int res_id, | ||
| 193 | const TaskInfo* tsk, | ||
| 194 | const Clusters& clusters, | ||
| 195 | const ClusterResponseTimes times) | ||
| 196 | { | ||
| 197 | unsigned long interval; | ||
| 198 | unsigned long blocking = 1; | ||
| 199 | unsigned long max_lower; | ||
| 200 | |||
| 201 | do | ||
| 202 | { | ||
| 203 | // last bound | ||
| 204 | interval = blocking; | ||
| 205 | // Bail out if it doesn't converge. | ||
| 206 | if (interval > tsk->get_response()) | ||
| 207 | return UNLIMITED; | ||
| 208 | |||
| 209 | blocking = mpcp_remote_blocking(res_id, interval, | ||
| 210 | tsk, clusters, times, | ||
| 211 | max_lower); | ||
| 212 | |||
| 213 | // Account for the maximum lower-priority gcs | ||
| 214 | // that could get in the way. | ||
| 215 | blocking += max_lower; | ||
| 216 | |||
| 217 | // Loop until it converges. | ||
| 218 | } while ( interval != blocking ); | ||
| 219 | |||
| 220 | return blocking; | ||
| 221 | } | ||
| 222 | |||
| 223 | static unsigned long mpcp_remote_blocking(const TaskInfo* tsk, | ||
| 224 | const Clusters& clusters, | ||
| 225 | const ClusterResponseTimes times) | ||
| 226 | { | ||
| 227 | unsigned long blocking = 0; | ||
| 228 | |||
| 229 | |||
| 230 | const Requests& requests = tsk->get_requests(); | ||
| 231 | unsigned int i = 0; | ||
| 232 | |||
| 233 | for (i = 0; i < requests.size(); i++) | ||
| 234 | { | ||
| 235 | unsigned int b; | ||
| 236 | b = mpcp_remote_blocking(requests[i].get_resource_id(), | ||
| 237 | tsk, clusters, times); | ||
| 238 | if (b != UNLIMITED) | ||
| 239 | // may represent multiple, multiply accordingly | ||
| 240 | blocking += b * requests[i].get_num_requests(); | ||
| 241 | else | ||
| 242 | // bail out if it didn't converge | ||
| 243 | return b; | ||
| 244 | } | ||
| 245 | |||
| 246 | return blocking; | ||
| 247 | } | ||
| 248 | |||
| 249 | static unsigned long mpcp_arrival_blocking(const TaskInfo* tsk, | ||
| 250 | const Cluster& cluster, | ||
| 251 | bool virtual_spinning) | ||
| 252 | { | ||
| 253 | unsigned int prio = tsk->get_priority(); | ||
| 254 | unsigned int blocking = 0; | ||
| 255 | unsigned int i; | ||
| 256 | |||
| 257 | for (i = 0; i < cluster.size(); i++) | ||
| 258 | if (cluster[i] != tsk && cluster[i]->get_priority() >= prio) | ||
| 259 | blocking += cluster[i]->get_max_request_length(); | ||
| 260 | |||
| 261 | if (virtual_spinning) | ||
| 262 | // Equation (4) in LNR:09. | ||
| 263 | return blocking; | ||
| 264 | else | ||
| 265 | // Equation (1) in LNR:09. | ||
| 266 | return blocking * tsk->get_num_arrivals(); | ||
| 267 | } | ||
| 268 | |||
| 269 | BlockingBounds* mpcp_bounds(const ResourceSharingInfo& info, | ||
| 270 | bool use_virtual_spinning) | ||
| 271 | { | ||
| 272 | Resources resources; | ||
| 273 | Clusters clusters; | ||
| 274 | |||
| 275 | split_by_resource(info, resources); | ||
| 276 | split_by_cluster(info, clusters); | ||
| 277 | |||
| 278 | // 2) Determine priority ceiling for each request. | ||
| 279 | PriorityCeilings gc; | ||
| 280 | determine_priority_ceilings(resources, gc); | ||
| 281 | |||
| 282 | |||
| 283 | // 3) For each request, determine response time. This only depends on the | ||
| 284 | // priority ceiling for each request. | ||
| 285 | ClusterResponseTimes responses; | ||
| 286 | determine_gcs_response_times(clusters, gc, responses); | ||
| 287 | |||
| 288 | unsigned int i; | ||
| 289 | |||
| 290 | BlockingBounds* _results = new BlockingBounds(info); | ||
| 291 | BlockingBounds& results = *_results; | ||
| 292 | |||
| 293 | for (i = 0; i < info.get_tasks().size(); i++) | ||
| 294 | { | ||
| 295 | const TaskInfo& tsk = info.get_tasks()[i]; | ||
| 296 | |||
| 297 | unsigned long remote, local = 0; | ||
| 298 | |||
| 299 | // 4) Determine remote blocking for each request. This depends on the | ||
| 300 | // response times for each remote request. | ||
| 301 | remote = mpcp_remote_blocking(&tsk, clusters, responses); | ||
| 302 | |||
| 303 | // 5) Determine arrival blocking for each task. | ||
| 304 | if (remote != UNLIMITED) | ||
| 305 | local = mpcp_arrival_blocking(&tsk, clusters[tsk.get_cluster()], | ||
| 306 | use_virtual_spinning); | ||
| 307 | |||
| 308 | // 6) Sum up blocking: remote blocking + arrival blocking. | ||
| 309 | results[i].total_length = remote + local; | ||
| 310 | |||
| 311 | |||
| 312 | Interference inf; | ||
| 313 | inf.total_length = remote; | ||
| 314 | results.set_remote_blocking(i, inf); | ||
| 315 | } | ||
| 316 | |||
| 317 | return _results; | ||
| 318 | } | ||
| 319 | |||
| 320 | |||
