crown
1.0.0
|
00001 /* 00002 Copyright 2015 Nicolas Melot 00003 00004 This file is part of Pelib. 00005 00006 Pelib 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 Pelib 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 Pelib. If not, see <http://www.gnu.org/licenses/>. 00018 */ 00019 00020 #include <pelib/Algebra.hpp> 00021 #include <pelib/Scalar.hpp> 00022 #include <pelib/AmplSolver.hpp> 00023 #include <pelib/Vector.hpp> 00024 #include <pelib/Matrix.hpp> 00025 #include <pelib/AmplInput.hpp> 00026 #include <pelib/time.h> 00027 00028 #include <crown/CrownBinary.hpp> 00029 #include <crown/CrownAllocationFastest.hpp> 00030 #include <crown/CrownMappingLTLG.hpp> 00031 #include <crown/CrownScalingHeight.hpp> 00032 #include <crown/CrownConfigBinary.hpp> 00033 #include <crown/CrownException.hpp> 00034 00035 #include <crown/mapping.h> 00036 #include <crown/scaling.h> 00037 #include <crown/annealing.h> 00038 #include <crown/crown.h> 00039 00040 #ifdef debug 00041 #undef debug 00042 #endif 00043 00044 #define debug(var) cout << "[" << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << "] " << #var << " = \"" << (var) << "\"" << endl; 00045 00046 using namespace std; 00047 using namespace pelib; 00048 using namespace crown; 00049 00050 static const long long int nsec_in_sec = 1000000000; 00051 00052 Algebra 00053 CrownBinary::solve(const Algebra &tg, const Algebra &pt, const pelib::Algebra ¶m, std::map<const std::basic_string<char>, double> &stats) const 00054 { 00055 float p = pt.find<Scalar<float> >("p")->getValue(); 00056 float logp = pow(2, floor(log(p) / log(2))); 00057 Algebra best_schedule; 00058 00059 if(p == logp || 1) 00060 { 00061 struct timespec start, stop, total_time; 00062 Algebra schedule = tg.merge(pt).merge(param); 00063 Algebra best = schedule; 00064 clock_gettime(CLOCK_MONOTONIC, &start); 00065 00066 float threshold = 0.5; 00067 float delta = 0.25; 00068 float derivative, min_derivative = 1; 00069 unsigned int round = 0; 00070 float m = 0; 00071 Algebra current; 00072 float power = 0; 00073 00074 // Compute allocation for maximal parallelization 00075 // This is is to get an allocation if nothing else works 00076 // Yet it is not guaranteed to produce a valid schedule 00077 // because of a still too high makespan presure 00078 00079 set<string> after_alloc; 00080 // Taskgraph 00081 after_alloc.insert(string("M")); 00082 after_alloc.insert(string("Tau")); 00083 after_alloc.insert(string("Wi")); 00084 after_alloc.insert(string("c")); 00085 after_alloc.insert(string("e")); 00086 after_alloc.insert(string("n")); 00087 after_alloc.insert(string("name")); 00088 // Platform 00089 after_alloc.insert(string("F")); 00090 after_alloc.insert(string("Fi")); 00091 after_alloc.insert(string("Fin")); 00092 after_alloc.insert(string("Funit")); 00093 after_alloc.insert(string("p")); 00094 // Param 00095 for(std::map<std::string, const AlgebraData * const>::const_iterator i = param.getAllRecords().begin(); i != param.getAllRecords().end(); i++) 00096 { 00097 after_alloc.insert(string(i->first)); 00098 } 00099 // Alloc step 00100 after_alloc.insert(string("wi")); 00101 // Mapping step 00102 set<string> after_mapping = after_alloc; 00103 after_mapping.insert(string("group")); 00104 // Scaling step 00105 set<string> after_scaling = after_mapping; 00106 after_scaling.insert(string("frequency")); 00107 00108 float emax = 0, emin = 1; 00109 float previous = 1; 00110 map<int, map<int, float> > map_e = tg.find<Matrix<int, int, float> >("e")->getValues(); 00111 map<int, float> map_Wi = tg.find<Vector<int, float> >("Wi")->getValues(); 00112 for(map<int, map<int, float> >::iterator row_iter = map_e.begin(); row_iter != map_e.end(); row_iter++) 00113 { 00114 int task = row_iter->first; 00115 int Wi = (int)map_Wi[task]; 00116 map<int, float> map_row = row_iter->second; 00117 00118 for(map<int, float>::iterator col_iter = map_row.begin(); col_iter != map_row.end() && col_iter->first <= Wi; col_iter++) 00119 { 00120 if(col_iter->second < 1) 00121 { 00122 if(col_iter->second > emax) 00123 { 00124 emax = col_iter->second; 00125 } 00126 00127 if(col_iter->second < emin) 00128 { 00129 emin = col_iter->second; 00130 } 00131 00132 derivative = previous - col_iter->second; 00133 if(derivative < min_derivative) 00134 { 00135 min_derivative = derivative; 00136 } 00137 } 00138 } 00139 } 00140 00141 best = CrownAllocationFastest(0, showOutput, showError).allocate(best, stats).filter(after_alloc); 00142 best = this->mapping->map(best, stats).filter(after_mapping); 00143 best = this->scaling->scale(best, stats); 00144 best = best.merge(param); 00145 float best_power = energy_static_dynamic_busy_idle_active(best); 00146 00147 // Binary search for maximal minimum efficiency for all tasks 00148 bool retry = true; 00149 00150 // Try a whole sequential schedule 00151 current = schedule; 00152 current = CrownAllocationFastest(1, showOutput, showError).allocate(current, stats).filter(after_alloc); 00153 current = this->mapping->map(current, stats).filter(after_mapping); 00154 current = this->scaling->scale(current, stats); 00155 current = current.merge(param); 00156 00157 // Check if this allocation could produce a valid mapping 00158 // m is the minimal slack time 00159 m = current.find<Scalar<float> >("m")->getValue(); 00160 if(m > 0) 00161 { 00162 //power = quality(current); 00163 power = energy_static_dynamic_busy_idle_active(current); 00164 if(power <= best_power) 00165 { 00166 best_power = power; 00167 best = current; 00168 } 00169 } 00170 00171 // Loop while the current threshold is lower than the maximum non-sequential efficiency 00172 // and delta is higher than the minimal efficiency gap between two allocations for any task 00173 // And, if any maximum round was given, this threshold was not reached 00174 while(retry && delta * 2 > min_derivative && ((precision != 0 && round < precision) || precision == 0)) 00175 { 00176 // Reset the current solution to input 00177 current = schedule; 00178 00179 // Allocate with current threshold then run mapping and frequency scaling 00180 current = CrownAllocationFastest(threshold, showOutput, showError).allocate(current, stats).filter(after_alloc); 00181 current = this->mapping->map(current, stats).filter(after_mapping); 00182 current = this->scaling->scale(current, stats); 00183 //Taskgraph ttg(tg); 00184 //Platform ppt(pt); 00185 //sched = new Schedule(getShortDescription(), tg.getName(), p); 00186 00187 00188 // Check if this allocation could produce a valid mapping 00189 // m is the minimal slack time 00190 m = current.find<Scalar<float> >("m")->getValue(); 00191 00192 // Update the threshold after the feasibility 00193 if(m >= 0) 00194 { 00195 current = current.merge(param); 00196 //power = quality(current); 00197 power = energy_static_dynamic_busy_idle_active(current); 00198 // This is a valid schedule 00199 // Retry if current threshold is lower than maximal efficiency 00200 retry = threshold < emax; 00201 00202 // Increase threshold by delta 00203 threshold = threshold + delta; 00204 00205 // Keep this schedule as the best found so far 00206 if(power < best_power) 00207 { 00208 best = current; 00209 best_power = power; 00210 } 00211 } 00212 else 00213 { 00214 // This was an invalid schedule 00215 retry = true; 00216 00217 // Allow lower efficiency 00218 threshold = threshold - delta; 00219 } 00220 // Reduce the delta 00221 delta = delta / 2; 00222 00223 // Count the number of rounds 00224 round++; 00225 } 00226 00227 clock_gettime(CLOCK_MONOTONIC, &stop); 00228 00229 // Report mapping quality 00230 stats.insert(pair<string, double>("quality", best_power)); 00231 00232 // Report optimization time 00233 pelib_timespec_subtract(&total_time, &stop, &start); 00234 float time = (float)(total_time.tv_sec * nsec_in_sec + total_time.tv_nsec) / (float)nsec_in_sec; 00235 stats.insert(pair<string, double>("time", time)); 00236 return best; 00237 } 00238 else 00239 { 00240 throw CrownException("Consolidation scheduler cannot handle non-power of two number of cores"); 00241 } 00242 } 00243 00244 Schedule 00245 CrownBinary::schedule(const Taskgraph &tg, const Platform &pt, const Algebra ¶m, map<const string, double> &statistics) const 00246 { 00247 // Take task names apart 00248 Algebra taskgraph = tg.buildAlgebra(pt); 00249 Vector<int, string> name = *taskgraph.find<Vector<int, string> >("name"); 00250 taskgraph.remove("name"); 00251 00252 Algebra p = param.merge(config->configure(tg, pt, param, statistics)); 00253 p = solve(taskgraph, pt.buildAlgebra(), p, statistics); 00254 00255 float time = 0; 00256 map<const string, double>::iterator i = statistics.find("time_allocation"); 00257 if(i != statistics.end()) 00258 { 00259 time += i->second; 00260 } 00261 i = statistics.find("time_mapping"); 00262 if(i != statistics.end()) 00263 { 00264 time += i->second; 00265 } 00266 i = statistics.find("time_scaling"); 00267 if(i != statistics.end()) 00268 { 00269 time += i->second; 00270 } 00271 i = statistics.find("time_global"); 00272 if(i != statistics.end()) 00273 { 00274 statistics.erase(i); 00275 } 00276 statistics.insert(pair<const string, double>("time_global", time)); 00277 00278 // Put back task names 00279 p.insert(new Vector<int, string>(name)); 00280 00281 p = crownToSchedule(p); 00282 p = Schedule::addStartTime(p, tg, pt); 00283 00284 // report scheduling complexity 00285 float complexity = this->complexity(tg, pt, param); 00286 statistics.insert(pair<string, double>("complexity", complexity)); 00287 00288 // Report feasibility 00289 Schedule *sched; 00290 float M = tg.getDeadline(pt); 00291 float m = p.find<Scalar<float> >("m")->getValue(); 00292 if(m < 0 && M > 0) 00293 { 00294 statistics.insert(pair<string, double>("feasible", 0)); 00295 sched = new Schedule(getShortDescription(), tg.getName(), Schedule::table()); 00296 } 00297 else 00298 { 00299 statistics.insert(pair<string, double>("feasible", 1)); 00300 sched = new Schedule(getShortDescription(), tg.getName(), p); 00301 } 00302 00303 Schedule final = *sched; 00304 delete sched; 00305 return final; 00306 //Schedule sched(getShortDescription(), tg.getName(), p); 00307 //return sched; 00308 } 00309 00310 Schedule 00311 CrownBinary::schedule(const Taskgraph &tg, const Platform &pt, map<const string, double> &statistics) const 00312 { 00313 return schedule(tg, pt, param, statistics); 00314 } 00315 00316 float 00317 CrownBinary::complexity(const Algebra &problem) const 00318 { 00319 return 0; 00320 //float complexity = pt.getCores().size() * 1 * (AllocationFastest().complexity(problem) + this->mapping->complexity(problem) + this->scaling->complexity(problem)); 00321 } 00322 00323 float 00324 CrownBinary::complexity(const Taskgraph &tg, const Platform &pt, const Algebra ¶m) const 00325 { 00326 return 0; 00327 } 00328 00329 CrownBinary* 00330 CrownBinary::clone() const 00331 { 00332 return new CrownBinary(*this); 00333 } 00334 00335 void 00336 CrownBinary::initialize(const CrownMapping *map, const CrownScaling *scale) 00337 { 00338 CrownAllocationFastest alloc(0, showOutput, showError); 00339 if(map == NULL) 00340 { 00341 this->mapping = new CrownMappingLTLG(config, &alloc, showOutput, showError); 00342 } 00343 else 00344 { 00345 this->mapping = map->clone(); 00346 } 00347 00348 if(scale == NULL) 00349 { 00350 this->scaling = new CrownScalingHeight(config, &alloc, mapping, showOutput, showError); 00351 } 00352 else 00353 { 00354 this->scaling = scale->clone(); 00355 } 00356 } 00357 00358 CrownBinary::CrownBinary(const CrownConfig *config, const CrownMapping *mapping, const CrownScaling *scaling, size_t precision, bool showOutput, bool showError) : CrownScheduler(config, showOutput, showError) 00359 { 00360 initialize(mapping, scaling); 00361 00362 // TODO: restore arbitrary configuration 00363 //delete this->config; 00364 //this->config = new CrownConfigBinary(); 00365 this->precision = precision; 00366 } 00367 00368 CrownBinary::CrownBinary(const Algebra ¶m, const CrownConfig *config, const CrownMapping *mapping, const CrownScaling *scaling, size_t precision, bool showOutput, bool showError) : CrownScheduler(config, showOutput, showError) 00369 { 00370 initialize(mapping, scaling); 00371 00372 // TODO: restore arbitrary configuration 00373 //delete this->config; 00374 //this->config = new CrownConfigBinary(); 00375 this->precision = precision; 00376 } 00377 00378 CrownBinary::CrownBinary(const Taskgraph &tg, const Platform &pt, const Algebra ¶m, const CrownConfig*, const CrownMapping *mapping, const CrownScaling *scaling, size_t precision, bool showOutput, bool showError) : CrownScheduler(config, showOutput, showError) 00379 { 00380 initialize(mapping, scaling); 00381 00382 // TODO: restore arbitrary configuration 00383 //delete this->config; 00384 //this->config = new CrownConfigBinary(); 00385 this->precision = precision; 00386 } 00387 00388 CrownBinary::CrownBinary(const CrownBinary &src) : CrownScheduler(src.tg, src.pt, src.param, src.config, src.showOutput, src.showError) 00389 { 00390 initialize(src.mapping, src.scaling); 00391 00392 // TODO: restore arbitrary configuration 00393 //delete this->config; 00394 //this->config = new CrownConfigBinary(); 00395 this->precision = src.precision; 00396 } 00397 00398 CrownBinary::~CrownBinary() 00399 { 00400 delete this->mapping; 00401 delete this->scaling; 00402 } 00403 00404 string 00405 CrownBinary::getShortDescription() const 00406 { 00407 float alpha = this->param.find<Scalar<float> >("alpha")->getValue(); 00408 float kappa = this->param.find<Scalar<float> >("kappa")->getValue(); 00409 float eta = this->param.find<Scalar<float> >("eta")->getValue(); 00410 float zeta = this->param.find<Scalar<float> >("zeta")->getValue(); 00411 stringstream ss; 00412 00413 const CrownConfig *config = this->config; 00414 if(config == NULL) 00415 { 00416 config = getDefaultConfig(); 00417 } 00418 00419 std::streamsize p = ss.precision(); 00420 ss.precision(4); 00421 string alloc = CrownAllocationFastest().getShortDescription(); 00422 string mapping = this->mapping->getShortDescription(); 00423 string scaling = this->scaling->getShortDescription(); 00424 string conf = this->config->getShortDescription(); 00425 ss << "Cr-Bin-"; 00426 ss << alloc << "-"; 00427 ss << mapping << "-"; 00428 ss << scaling << "-"; 00429 ss << conf << "(a="; 00430 ss << alpha << ",k="; 00431 ss << kappa << ",e="; 00432 ss << eta << ",z="; 00433 ss << zeta << ")"; 00434 ss.precision(p); 00435 00436 if(this->config == NULL) 00437 { 00438 delete config; 00439 } 00440 00441 return ss.str(); 00442 } 00443 00444 const Algebra* 00445 CrownBinary::solve() const 00446 { 00447 map<const string, double> statistics; 00448 Algebra *sol = new Algebra(schedule(tg, pt, param, statistics).buildAlgebra()); 00449 return sol; 00450 } 00451 00452 const Algebra* 00453 CrownBinary::solve(map<const string, double> &statistics) const 00454 { 00455 Algebra *sol = new Algebra(schedule(tg, pt, param, statistics).buildAlgebra()); 00456 return sol; 00457 } 00458