crown
1.0.0
|
00001 /* 00002 Copyright 2015 Nicolas Melot 00003 00004 This file is part of Crown. 00005 00006 Crown is free software: you can redistribute it and/or modify 00007 it under the terms of the GNU General Public License as published by 00008 the Free Software Foundation, either version 3 of the License, or 00009 (at your option) any later version. 00010 00011 Crown is distributed in the hope that it will be useful, 00012 but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 GNU General Public License for more details. 00015 00016 You should have received a copy of the GNU General Public License 00017 along with Crown. If not, see <http://www.gnu.org/licenses/>. 00018 00019 */ 00020 00021 00022 #include <fstream> 00023 #include <set> 00024 00025 #include <cstdlib> 00026 00027 #include <crown/allocation.h> 00028 #include <crown/mapping.h> 00029 #include <crown/scaling.h> 00030 #include <crown/crown.h> 00031 00032 #include <pelib/AmplInput.hpp> 00033 #include <pelib/AmplOutput.hpp> 00034 #include <pelib/Vector.hpp> 00035 #include <pelib/Matrix.hpp> 00036 #include <pelib/Set.hpp> 00037 00038 #include <crown/allocation.h> 00039 #include <crown/CrownScheduler.hpp> 00040 00041 #ifdef debug 00042 #undef debug 00043 #endif 00044 00045 #if 01 00046 #define debug(var) cout << "[" << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << "] " << #var << " = \"" << var << "\"" << endl; 00047 #else 00048 #define debug(var) 00049 #endif 00050 00051 using namespace pelib; 00052 using namespace std; 00053 00054 namespace pelib 00055 { 00056 namespace crown 00057 { 00058 00059 Algebra 00060 neighbor_allocation(const Algebra &solution, float tasks, float cores) 00061 { 00062 Algebra schedule = solution; 00063 // distance == 1 -> change all neighbors by +- Wi processors 00064 // distance == 0 -> change only one neighbor by 1 processor 00065 00066 map<int, float> vector_wi = schedule.find<Vector<int, float> >("wi")->getValues(); 00067 int b = (int)schedule.find<Scalar<float> >("b")->getValue(); 00068 int p = (int)schedule.find<Scalar<float> >("p")->getValue(); 00069 const Vector<int, float> *Wi = schedule.find<Vector<int, float> >("Wi"); 00070 map<int, float> vector_Wi = Wi->getValues(); 00071 int n = vector_wi.size(); 00072 00073 int num_tasks = ((int)((float)rand() / (float)RAND_MAX * n * tasks)); 00074 while (num_tasks > 0 && vector_Wi.size() > 0) 00075 { 00076 int size = vector_Wi.size(); 00077 map<int, float>::iterator itask = vector_Wi.begin(); 00078 int index = rand() % size; 00079 00080 for(int i = 0; i < index; i++) 00081 { 00082 itask++; 00083 } 00084 00085 // If a task is sequential, there is no neighbor to find there, remove that task from list and continue 00086 if(itask->second < 2) 00087 { 00088 vector_Wi.erase(itask); 00089 continue; 00090 } 00091 00092 // Task maximal width > 1 (Wit > 0) 00093 int task = itask->first; 00094 int Wit = (int)vector_Wi[task]; 00095 Wit = Wit > p ? p : Wit; 00096 Wit = (int)(log(Wit) / log(b)); 00097 00098 // task current allocated width 00099 int wi = (int)(log(vector_wi.find(task)->second) / log(b)); 00100 00101 int amplitude = Wit * (int)cores; // + 1 to count the number of possibilities, -1 to remove the current allocation from possible new allocation 00102 amplitude = amplitude < 1 ? 1 : amplitude; // Make sure at least one transformation is performed 00103 00104 // Count how many spots are available below and above current wi 00105 int avail_lower = wi; 00106 int avail_higher = Wit - wi; 00107 00108 // Cound how many spots we need below and above current wi 00109 int wi_lower, wi_higher; 00110 if(rand() % 2 == 0) 00111 { 00112 wi_lower = (int)floor((float)amplitude / 2); 00113 wi_higher = (int)ceil((float)amplitude / 2); 00114 } 00115 else 00116 { 00117 wi_lower = (int)ceil((float)amplitude / 2); 00118 wi_higher = (int)floor((float)amplitude / 2); 00119 } 00120 00121 int len_lower, len_higher; 00122 if(avail_lower >= wi_lower && avail_higher >=wi_higher) 00123 { 00124 len_lower = wi_lower; 00125 len_higher = wi_higher; 00126 } 00127 else if(avail_lower < wi_lower) 00128 { 00129 len_lower = avail_lower; 00130 len_higher = wi_higher + (wi_lower - avail_lower); 00131 } 00132 else if(avail_higher < wi_higher) 00133 { 00134 len_higher = avail_higher; 00135 len_lower = wi_lower + (wi_higher - avail_higher); 00136 } 00137 else 00138 { 00139 // Not enough space to fit the amplitude, aborting 00140 cerr << "# Not enough allocation opportunities to fit the amplitude" << endl; 00141 cerr << "# Task " << task << "; p = " << p << "; log2(Wi) = " << Wit << "; log2(wi) = " << wi << "; amplitude = " << amplitude << "; avail_lower = " << avail_lower << "; avail_higher = " << avail_higher << "; wi_lower = " << wi_lower << "; wi_higher = " << wi_higher << endl; 00142 abort(); 00143 } 00144 00145 int alternative = ((int)rand() % (amplitude)) + 1; // Start counting the new allocation number with 1 00146 int new_wi = 0; 00147 if(alternative <= len_lower) 00148 { 00149 new_wi = wi - (len_lower - alternative + 1); 00150 } 00151 else if(alternative <= len_lower + len_higher) 00152 { 00153 new_wi = wi + alternative - len_lower; 00154 } 00155 else 00156 { 00157 cerr << "# Chosen alternative is beyond the spots available" << endl; 00158 cerr << "# Task " << task << "; p = " << p << "; log2(Wi) = " << Wit << "; log2(wi) = " << wi << "; amplitude = " << amplitude << "; avail_lower = " << avail_lower << "; avail_higher = " << avail_higher << "; wi_lower = " << wi_lower << "; wi_higher = " << wi_higher << "; alternative = " << alternative << endl; 00159 len_lower = avail_lower; 00160 len_higher = wi_higher + (wi_lower - avail_lower); 00161 } 00162 00163 if(wi == new_wi || new_wi > Wit || new_wi < 0) 00164 { 00165 cerr << "# Task " << task << "; Wi " << Wit << "; wi " << wi << "; amplitude " << amplitude << "; new_wi " << new_wi << endl; 00166 abort(); 00167 } 00168 00169 new_wi = (int)pow((double)b, (double)new_wi); 00170 if(new_wi == 64) 00171 { 00172 cerr << "# Task " << task << "; Wi " << Wit << "; wi " << wi << "; amplitude " << amplitude << "; new_wi " << new_wi << endl; 00173 } 00174 vector_wi[task] = new_wi; 00175 00176 // Done with this task, continue with the next 00177 vector_Wi.erase(itask); 00178 num_tasks--; 00179 00180 } 00181 00182 Vector<int, float> wi("wi", vector_wi); 00183 schedule.insert(&wi); 00184 00185 return schedule; 00186 } 00187 00188 Algebra 00189 neighbor_allocation_full(const Algebra &solution, float distance) 00190 { 00191 return neighbor_allocation(solution, distance, distance); 00192 } 00193 00194 Algebra 00195 neighbor_allocation_tasks(const Algebra &solution, float distance) 00196 { 00197 return neighbor_allocation(solution, distance, 0); 00198 } 00199 00200 Algebra 00201 neighbor_allocation_cores(const Algebra &solution, float distance) 00202 { 00203 return neighbor_allocation(solution, 0, distance); 00204 } 00205 00206 Algebra 00207 neighbor_efficiency(const Algebra &solution, float distance) 00208 { 00209 Algebra schedule = solution; 00210 00211 const Scalar<float> *gemin = schedule.find<Scalar<float> >("gemin"); 00212 if(gemin == NULL) 00213 { 00214 gemin = new Scalar<float>("gemin", 0); 00215 schedule.insert(gemin); 00216 delete gemin; 00217 gemin = schedule.find<Scalar<float> >("gemin"); 00218 } 00219 float gemin_val = gemin->getValue(); 00220 00221 const Scalar<float> *gemax = schedule.find<Scalar<float> >("gemax"); 00222 if(gemax == NULL) 00223 { 00224 gemax = new Scalar<float>("gemax", 1); 00225 schedule.insert(gemax); 00226 delete gemax; 00227 gemax = schedule.find<Scalar<float> >("gemax"); 00228 } 00229 float gemax_val = gemax->getValue(); 00230 00231 // The whole universe we can vary the global minimal efficiency in 00232 float universe = gemax_val - gemin_val; 00233 00234 const Scalar<float> *geuse = schedule.find<Scalar<float> >("geuse"); 00235 float geuse_val = 0; 00236 if(geuse == NULL) 00237 { 00238 // The initial value is somewhere between gemin and gemax ( = gemin + rand() * universe ) 00239 geuse = new Scalar<float>("geuse", gemin_val + (universe * ((float)rand() / RAND_MAX))); 00240 schedule.insert(geuse); 00241 delete geuse; 00242 geuse = schedule.find<Scalar<float> >("geuse"); 00243 } 00244 else 00245 { 00246 geuse_val = geuse->getValue(); 00247 float random = (float)rand() / RAND_MAX; 00248 geuse_val = geuse_val + (random * universe * distance); 00249 00250 if(geuse_val < gemin_val) 00251 { 00252 geuse_val += gemin_val - geuse_val; 00253 } 00254 else if(geuse_val > gemax_val) 00255 { 00256 geuse_val -= geuse_val - gemax_val; 00257 } 00258 00259 if (geuse_val < gemin_val || geuse_val > gemax_val) 00260 { 00261 // Something went terribly wrong 00262 cerr << "Geuse val went off the chart despite (or because of) the out-of-universe problem fix" << endl; 00263 cerr << "geuse_val = " << geuse_val << "; gemin = " << gemin_val << "; gemax = " << gemax_val << "; universe = " << universe << "; random = " << random << ";distance = " << distance << endl; 00264 } 00265 } 00266 00267 // Reallocate 00268 return allocation_gemin(schedule, geuse_val); 00269 } 00270 00271 float 00272 quality_simple(const Algebra &schedule) 00273 { 00274 //int n = schedule.find<Scalar<float> >("n")->getValue(); 00275 int p = (int)schedule.find<Scalar<float> >("p")->getValue(); 00276 float alpha = schedule.find<Scalar<float> >("alpha")->getValue(); 00277 float zeta = schedule.find<Scalar<float> >("zeta")->getValue(); 00278 float M = schedule.find<Scalar<float> >("M")->getValue(); 00279 Vector<int, float> tau = schedule.find<Vector<int, float> >("Tau"); 00280 Vector<int, float> Wi = schedule.find<Vector<int, float> >("Wi"); 00281 Vector<int, float> wi = schedule.find<Vector<int, float> >("wi"); 00282 Vector<int, float> frequency = schedule.find<Vector<int, float> >("frequency"); 00283 Vector<int, float> group = schedule.find<Vector<int, float> >("group"); 00284 Matrix<int, int, float> e = schedule.find<Matrix<int, int, float> >("e"); 00285 00286 double static_energy = M * p; 00287 double dynamic_energy = 0; 00288 00289 // Now evaluate the quality of this schedule 00290 for(map<int, float>::const_iterator i = group.getValues().begin(); i != group.getValues().end(); i++) 00291 { 00292 int task = i->first; 00293 00294 float tau_t = tau.find(task); 00295 int width_t = (int)wi.find(task); 00296 width_t = width_t > p ? p : width_t; 00297 int f_t = (int)frequency.find(task); 00298 00299 double area = (double)tau_t / (double)(e.find(width_t, task)) / (double)frequency.find(task); 00300 static_energy -= area; 00301 dynamic_energy += area * pow(f_t, alpha); 00302 } 00303 00304 return dynamic_energy + zeta * static_energy; 00305 } 00306 00307 float 00308 energy_static_dynamic_busy_idle_active(const Algebra &solution) 00309 { 00310 Algebra rec = CrownScheduler::crownToSchedule(solution); 00311 int n = rec.find<Scalar<float> >("n")->getValue(); 00312 int p = rec.find<Scalar<float> >("p")->getValue(); 00313 float M = rec.find<Scalar<float> >("M")->getValue(); 00314 float kappa = rec.find<Scalar<float> >("kappa")->getValue(); 00315 float eta = rec.find<Scalar<float> >("eta")->getValue(); 00316 float zeta = rec.find<Scalar<float> >("zeta")->getValue(); 00317 float alpha = rec.find<Scalar<float> >("alpha")->getValue(); 00318 Vector<int, float> tau = rec.find<Vector<int, float> >("Tau"); 00319 const Vector<int, string> *nameptr = rec.find<Vector<int, string> >("name"); 00320 Vector<int, string> name("name", nameptr != NULL ? nameptr->getValues() : map<int, string>()); 00321 00322 Vector<int, float> Wi = rec.find<Vector<int, float> >("Wi"); 00323 Vector<int, float> frequency = rec.find<Vector<int, float> >("frequency"); 00324 Set<float> F = rec.find<Set<float> >("F"); 00325 Matrix<int, int, float> e = rec.find<Matrix<int, int, float> >("e"); 00326 Matrix<int, int, float> schedule = rec.find<Matrix<int, int, float> >("schedule"); 00327 Vector<int, float> wi = rec.find<Vector<int, float> >("wi"); 00328 vector<double> busy_task(n, 0); 00329 vector<double> area_task(n, 0); 00330 vector<double> met_task(n, 0); 00331 00332 float lowest_freq = *(F.getValues().begin()); 00333 kappa = kappa * lowest_freq; 00334 eta = eta * (zeta * pow(lowest_freq, alpha) + (1 - zeta) * (lowest_freq + kappa)) / zeta; 00335 double idle_energy = p * M * pow(lowest_freq, alpha); 00336 double busy_energy = 0; 00337 00338 map<float, int> core_active; 00339 for(size_t i = 0; i < (size_t)p; i++) 00340 { 00341 core_active[i + 1] = 0; 00342 } 00343 int total_core_active = 0; 00344 00345 // Iterate through all task names until we find the dummy task; 00346 vector<size_t> dummy_index; 00347 size_t index = 0; 00348 for(map<int, string>::const_iterator i = name.getValues().begin(); i != name.getValues().end(); i++, index++) 00349 { 00350 stringstream ss; 00351 ss << DUMMY_TASK << " " << index + 1; 00352 if(string(i->second).compare(ss.str()) == 0) 00353 { 00354 dummy_index.push_back(index + 1); 00355 } 00356 } 00357 00358 // Now evaluate the quality of this schedule 00359 float total_area = 0; 00360 for(map<int, map<int, float> >::const_iterator i = schedule.getValues().begin(); i != schedule.getValues().end(); i++) 00361 { 00362 //int core = i->first; 00363 for(map<int, float>::const_iterator j = i->second.begin(); j != i->second.end(); j++) 00364 { 00365 //int index = j->first; 00366 int task = j->second; 00367 //cout << "Core " << core << ", task " << task << endl; 00368 00369 // Check if the task index is a dummy task 00370 bool dummy = false; 00371 for(size_t k = 0; k < dummy_index.size(); k++) 00372 { 00373 if((size_t)task == dummy_index[k]) 00374 { 00375 dummy = true; 00376 break; 00377 } 00378 } 00379 00380 // We don't take dummy task power consumption into account 00381 if(task > 0 && !dummy) 00382 { 00383 float width_t = wi.getValues().find(task)->second; 00384 double time = (double)tau.find(task) / (width_t * e.find(width_t, task) * (double)frequency.find(task)); 00385 total_area += time; 00386 float power = (zeta * pow(frequency.find(task), alpha) + (1 - zeta) * (frequency.find(task) + kappa)) / zeta; 00387 busy_energy += time * power; 00388 00389 // Mark this core as active 00390 if(core_active[i->first] == 0) 00391 { 00392 core_active[i->first] = 1; 00393 total_core_active++; 00394 } 00395 } 00396 } 00397 } 00398 00399 idle_energy = (M * (total_core_active) - total_area) * eta; 00400 00401 return zeta * busy_energy + (1 - zeta) * idle_energy; 00402 } 00403 00404 static 00405 float 00406 energy_static_idle(const Algebra &schedule, float epsilon) 00407 { 00408 int p = (int)schedule.find<Scalar<float> >("p")->getValue(); 00409 float alpha = schedule.find<Scalar<float> >("alpha")->getValue(); 00410 float zeta = schedule.find<Scalar<float> >("zeta")->getValue(); 00411 float minF = *(schedule.find<Set<float> >("F")->getValues().begin()); 00412 00413 float M; 00414 const Scalar<float> *float_M = schedule.find<Scalar<float> >("M"); 00415 if(float_M != NULL) 00416 { 00417 M = float_M->getValue(); 00418 } 00419 else 00420 { 00421 const Scalar<float> *int_M = schedule.find<Scalar<float> >("M"); 00422 M = int_M->getValue(); 00423 } 00424 00425 Vector<int, float> tau = schedule.find<Vector<int, float> >("Tau"); 00426 Vector<int, float> Wi = schedule.find<Vector<int, float> >("Wi"); 00427 Vector<int, float> wi = schedule.find<Vector<int, float> >("wi"); 00428 Vector<int, float> frequency = schedule.find<Vector<int, float> >("frequency"); 00429 Vector<int, float> group = schedule.find<Vector<int, float> >("group"); 00430 Matrix<int, int, float> e = schedule.find<Matrix<int, int, float> >("e"); 00431 00432 double idle_energy = 0; 00433 double busy_energy = 0; 00434 double total_area = 0; 00435 00436 // Now evaluate the quality of this schedule 00437 for(map<int, float>::const_iterator i = group.getValues().begin(); i != group.getValues().end(); i++) 00438 { 00439 int task = i->first; 00440 00441 float tau_t = tau.find(task); 00442 float width_t = wi.find(task); 00443 width_t = width_t > p ? p : width_t; 00444 //double e_wt = e.find(width_t, task); 00445 float f_t = frequency.find(task); 00446 00447 double area = (double)tau_t / (double)(e.find((int)width_t, task)) / (double)frequency.find(task); 00448 00449 total_area += area; 00450 busy_energy += area * pow(f_t, alpha) + zeta * f_t; 00451 } 00452 idle_energy = (p * M - total_area) * pow(minF, alpha) + zeta * minF; 00453 00454 return busy_energy + epsilon * idle_energy; 00455 } 00456 00457 float 00458 quality_generic(const Algebra &schedule) 00459 { 00460 int p = (int)schedule.find<Scalar<float> >("p")->getValue(); 00461 float alpha = schedule.find<Scalar<float> >("alpha")->getValue(); 00462 float alpha_static = schedule.find<Scalar<float> >("alpha-static")->getValue(); 00463 float zeta = schedule.find<Scalar<float> >("zeta")->getValue(); 00464 float epsilon = schedule.find<Scalar<float> >("epsilon")->getValue(); 00465 float minF = *(schedule.find<Set<float> >("F")->getValues().begin()); 00466 00467 float M; 00468 const Scalar<float> *float_M = schedule.find<Scalar<float> >("M"); 00469 if(float_M != NULL) 00470 { 00471 M = float_M->getValue(); 00472 } 00473 else 00474 { 00475 const Scalar<float> *int_M = schedule.find<Scalar<float> >("M"); 00476 M = int_M->getValue(); 00477 } 00478 00479 Vector<int, float> tau = schedule.find<Vector<int, float> >("Tau"); 00480 Vector<int, float> Wi = schedule.find<Vector<int, float> >("Wi"); 00481 Vector<int, float> wi = schedule.find<Vector<int, float> >("wi"); 00482 Vector<int, float> frequency = schedule.find<Vector<int, float> >("frequency"); 00483 Vector<int, float> group = schedule.find<Vector<int, float> >("group"); 00484 Matrix<int, int, float> e = schedule.find<Matrix<int, int, float> >("e"); 00485 00486 double idle_energy = 0; 00487 double busy_energy = 0; 00488 double total_area = 0; 00489 00490 // Now evaluate the quality of this schedule 00491 for(map<int, float>::const_iterator i = group.getValues().begin(); i != group.getValues().end(); i++) 00492 { 00493 int task = i->first; 00494 00495 float tau_t = tau.find(task); 00496 float width_t = wi.find(task); 00497 width_t = width_t > p ? p : width_t; 00498 float f_t = frequency.find(task); 00499 00500 double area = (double)tau_t / (double)(e.find((int)width_t, task)) / (double)frequency.find(task); 00501 00502 total_area += area; 00503 busy_energy += area * pow(f_t, alpha) + zeta * f_t; 00504 } 00505 idle_energy = (p * M - total_area) * pow(minF, alpha_static) + zeta * minF; 00506 00507 return busy_energy + epsilon * idle_energy; 00508 } 00509 00510 float 00511 quality_idle(const Algebra &schedule) 00512 { 00513 return energy_static_idle(schedule, 0.5); 00514 } 00515 00516 float 00517 quality_off(const Algebra &schedule) 00518 { 00519 return energy_static_idle(schedule, 0); 00520 } 00521 00522 // This is not possible now that we allow energy saving 00523 // by switchingu nused cores off 00524 #if RETURN_EARLY 00525 #define return_now_if_best(solution) if(solution.find<Scalar<float> >("all_sequential")->getValue() == 1 && solution.find<Scalar<float> >("frequency_optimal")->getValue() == 1) return solution 00526 #else 00527 #define return_now_if_best(solution) 00528 #endif 00529 00530 Algebra 00531 annealing(const Algebra &initial, const Algebra &initial_best, float (*quality)(const Algebra &solution), Algebra (*neighbor)(const Algebra &solution, float distance), float temperature, float cooling, float final, int max_transform, int max_new_state, float distance) 00532 { 00533 Algebra schedule = initial; 00534 schedule = neighbor(schedule, distance); 00535 00536 float m; 00537 int counter = 0; 00538 float T = temperature; 00539 00540 Algebra best = initial_best; 00541 float best_q = quality(best); 00542 Vector<int, float> *best_solution = initial_best.find<Vector<int, float> >("wi")->clone(); 00543 float q = quality(schedule); 00544 00545 while (T > final) 00546 { 00547 int new_state = 0; 00548 00549 for(int i = 0; i < max_transform; i++) 00550 { 00551 // Keep track of the solution of last iteration 00552 Vector<int, float> *old_solution = schedule.find<Vector<int, float> >("wi")->clone(); 00553 float old_q = q; 00554 00555 // Transform the solution 00556 schedule = neighbor(schedule, distance); 00557 schedule = mapping_ltlg(schedule); 00558 schedule = frequency_height(schedule); 00559 00560 m = schedule.find<Scalar<float> >("m")->getValue(); 00561 q = quality(schedule); 00562 00563 // If the new energy is lower than the previous one, then we accept this solution 00564 if (q - old_q <= 0 && m >= 0) 00565 { 00566 delete old_solution; 00567 00568 // If this solution is better than the best found so far, then keep this best solution 00569 if (q < best_q) 00570 { 00571 best_solution = schedule.find<Vector<int, float> >("wi")->clone(); 00572 best_q = q; 00573 } 00574 00575 // One new state validated 00576 new_state++; 00577 } 00578 else 00579 { 00580 // Randomly accept a degrading solution, more likely when the temperature is higher 00581 if (rand() / RAND_MAX <= exp(-(q - old_q) / T) && m >= 0) 00582 { 00583 // Update current solution 00584 delete old_solution; 00585 00586 // One new state validated 00587 new_state++; 00588 } 00589 else 00590 { 00591 // Revert old solution 00592 schedule.insert(old_solution); 00593 q = old_q; 00594 } 00595 } 00596 00597 // Too much successful transformations 00598 if(new_state == max_new_state) 00599 { 00600 break; 00601 } 00602 } 00603 00604 T = T * cooling; 00605 counter++; 00606 } 00607 00608 schedule.insert(best_solution); 00609 schedule = mapping_ltlg(schedule); 00610 schedule = frequency_height(schedule); 00611 00612 return schedule; 00613 } 00614 00615 float 00616 annealing_complexity(float temperature, float cooling, float final, int max_transform, int max_new_state, float distance) 00617 { 00618 return max_transform * ceil(log(temperature / final) / log(1 / cooling)); 00619 } 00620 00621 } 00622 }