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/Vector.hpp> 00023 #include <pelib/Matrix.hpp> 00024 #include <pelib/Set.hpp> 00025 #include <pelib/AmplSolver.hpp> 00026 #include <pelib/Matrix.hpp> 00027 #include <pelib/AmplInput.hpp> 00028 00029 #include <crown/CrownScheduler.hpp> 00030 #include <crown/CrownConfigBinary.hpp> 00031 #include <crown/CrownException.hpp> 00032 00033 #ifdef debug 00034 #undef debug 00035 #endif 00036 00037 #define debug(var) cout << "[" << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << "] " << #var << " = \"" << (var) << "\"" << endl; 00038 00039 using namespace std; 00040 using namespace pelib; 00041 using namespace crown; 00042 00043 CrownConfig* 00044 CrownScheduler::getDefaultConfig() const 00045 { 00046 return new CrownConfigBinary(); 00047 } 00048 00049 Algebra 00050 CrownScheduler::addCrownConfig(const Taskgraph &tg, const Platform &pt, const Algebra &p, std::map<const string, double> &stats) const 00051 { 00052 Algebra param = p; 00053 if(config != NULL) 00054 { 00055 // Use config generator to create crown configuration 00056 if(param.find<Matrix <int, int, float> >(CrownConfig::crownConfigGroups) != NULL) 00057 { 00058 param.remove(CrownConfig::crownConfigGroups); 00059 } 00060 00061 if(param.find<Matrix <int, int, float> >(CrownConfig::crownConfigTree) != NULL) 00062 { 00063 param.remove(CrownConfig::crownConfigTree); 00064 } 00065 00066 Algebra crownConfig = config->configure(tg, pt, p, stats); 00067 const Matrix<int, int, float> *conf = crownConfig.find<Matrix<int, int, float> >(CrownConfig::crownConfigGroups); 00068 param.insert(conf); 00069 conf = crownConfig.find<Matrix<int, int, float> >(CrownConfig::crownConfigTree); 00070 param.insert(conf); 00071 } 00072 else if(param.find<Matrix <int, int, float> >(CrownConfig::crownConfigGroups) == NULL || 00073 param.find<Matrix <int, int, float> >(CrownConfig::crownConfigTree) == NULL) 00074 { 00075 // No config generator, use balanced binary tree 00076 if(param.find<Matrix <int, int, float> >(CrownConfig::crownConfigGroups) != NULL) 00077 { 00078 param.remove(CrownConfig::crownConfigGroups); 00079 } 00080 00081 if(param.find<Matrix <int, int, float> >(CrownConfig::crownConfigTree) != NULL) 00082 { 00083 param.remove(CrownConfig::crownConfigTree); 00084 } 00085 00086 CrownConfig *config = this->getDefaultConfig(); 00087 Algebra crownConfig = config->configure(tg, pt, p, stats); 00088 delete config; 00089 const Matrix<int, int, float> *conf = crownConfig.find<Matrix<int, int, float> >(CrownConfig::crownConfigGroups); 00090 param.insert(conf); 00091 conf = crownConfig.find<Matrix<int, int, float> >(CrownConfig::crownConfigTree); 00092 param.insert(conf); 00093 } 00094 00095 return param; 00096 } 00097 00098 void 00099 CrownScheduler::initialize(const CrownConfig *config) 00100 { 00101 if(config == NULL) 00102 { 00103 this->config = new CrownConfigBinary(); 00104 } 00105 else 00106 { 00107 this->config = config->clone(); 00108 } 00109 } 00110 00111 CrownScheduler::CrownScheduler(const CrownConfig* config, bool showOutput, bool showError) 00112 { 00113 param.insert(new Scalar<float>("alpha", 3)); 00114 param.insert(new Scalar<float>("eta", 0.018611)); 00115 param.insert(new Scalar<float>("zeta", 0.649)); 00116 param.insert(new Scalar<float>("kappa", 52.639161335)); 00117 this->showError = showError; 00118 this->showOutput = showOutput; 00119 initialize(config); 00120 } 00121 00122 CrownScheduler::CrownScheduler(const Algebra ¶m, const CrownConfig* config, bool showOutput, bool showError) 00123 { 00124 this->param = param; 00125 this->showError = showError; 00126 this->showOutput = showOutput; 00127 initialize(config); 00128 } 00129 00130 CrownScheduler::CrownScheduler(const Taskgraph &tg, const Platform &pt, const Algebra &p, const CrownConfig* config, bool showOutput, bool showError) 00131 { 00132 this->tg = tg; 00133 this->pt = pt; // This one is the culprit 00134 this->param = p; 00135 this->showError = showError; 00136 this->showOutput = showOutput; 00137 initialize(config); 00138 } 00139 00140 CrownScheduler::CrownScheduler(const CrownScheduler &src) 00141 { 00142 this->tg = src.tg; 00143 this->pt = src.pt; // This one is the culprit 00144 this->param = src.param; 00145 this->showError = src.showError; 00146 this->showOutput = src.showOutput; 00147 initialize(src.config); 00148 } 00149 00150 string 00151 CrownScheduler::getShortDescription() const 00152 { 00153 float alpha = this->param.find<Scalar<float> >("alpha")->getValue(); 00154 float kappa = this->param.find<Scalar<float> >("kappa")->getValue(); 00155 float eta = this->param.find<Scalar<float> >("eta")->getValue(); 00156 float zeta = this->param.find<Scalar<float> >("zeta")->getValue(); 00157 stringstream ss; 00158 ss << "Crown-" << this->config->getShortDescription() << "(a=" << alpha << ",k=" << kappa << ",e=" << eta << ",z=" << zeta << ")"; 00159 return ss.str(); 00160 } 00161 00162 const int b = 2; 00163 typedef map<int, float> TaskWidthVector; 00164 typedef map<int, float> TaskScheduleVector; 00165 typedef map<int, TaskScheduleVector> ProcScheduleMatrix; 00166 00167 static 00168 int 00169 group_size(int group, int p, int b, const Vector<int, float> *size) 00170 { 00171 if(size == NULL) 00172 { 00173 return p / (int)pow(b, floor((log(group) / log(b)))); 00174 } 00175 else 00176 { 00177 return size->getValues().find(group)->second; 00178 } 00179 } 00180 00181 struct cmp 00182 { 00183 bool operator()(void *a, void *b) 00184 { 00185 set<void*, cmp> *aa = (set<void*, cmp>*)a; 00186 set<void*, cmp> *bb = (set<void*, cmp>*)b; 00187 00188 if((size_t)a == (size_t)b) 00189 { 00190 return false; 00191 } 00192 00193 if(aa->size() == bb->size()) 00194 { 00195 return (size_t)a < (size_t)b; 00196 } 00197 else 00198 { 00199 return aa->size() < bb->size(); 00200 } 00201 } 00202 }; 00203 00204 static size_t 00205 build_schedule(set<void*, cmp> groups[], const set<void*, cmp> *root, const map<int, map<int, float> > &members, const map<int, float> &mapping, map<int, map<int, float> > &schedule) 00206 { 00207 // Get number of cores 00208 size_t group = ((size_t)(root) - (size_t)(groups)) / sizeof(set<void*, cmp>) + 1; 00209 size_t num = 0; 00210 00211 // Add all task into dorresponding processor 00212 for(map<int, float>::const_iterator i = mapping.begin(); i != mapping.end(); i++) 00213 { 00214 // Get the task and the group 00215 size_t task = i->first; 00216 00217 // Add the task to schedule if the task is mapped to current group 00218 if(i->second == group) 00219 { 00220 // Add task to all processors member of current group 00221 for(map<int, float>::const_iterator j = members.find(group)->second.begin(); j != members.find(group)->second.end(); j++) 00222 { 00223 if((int)(j->second + 0.5) > 0) 00224 { 00225 map<int, map<int, float> >::iterator iter = schedule.find(j->first); 00226 map<int, float> sequence = iter->second; 00227 schedule.erase(iter); 00228 size_t size = sequence.size(); 00229 map<int, float>::iterator k; 00230 for(k = sequence.begin(); k != sequence.end(); k++) 00231 { 00232 if(k->second == task) 00233 { 00234 break; 00235 } 00236 } 00237 if(k == sequence.end()) 00238 { 00239 sequence.insert(pair<int, float>(size + 1, task)); 00240 } 00241 schedule.insert(pair<int, map<int, float> >(j->first, sequence)); 00242 } 00243 } 00244 00245 // Count number of tasks in this group 00246 num++; 00247 } 00248 } 00249 00250 // Explore subgroups 00251 size_t max = 0; 00252 for(set<void*, cmp>::const_iterator i = root->begin(); i != root->end(); i++) 00253 { 00254 const set<void*, cmp> *subgroup = (set<void*, cmp>*)*i; 00255 size_t size = build_schedule(groups, subgroup, members, mapping, schedule); 00256 00257 if(size > max) 00258 { 00259 max = size; 00260 } 00261 } 00262 00263 return max + num; 00264 } 00265 00266 const CrownConfig* 00267 CrownScheduler::getCrownConfig() const 00268 { 00269 return this->config; 00270 } 00271 00272 Algebra 00273 CrownScheduler::crownToSchedule(const Algebra &crown) 00274 { 00275 std::ios_base::sync_with_stdio(true); 00276 Algebra res = crown; 00277 //int n = crown.find<Scalar<float> >("n")->getValue(); 00278 int p = (int)crown.find<Scalar<float> >("p")->getValue(); 00279 const Vector<int, float> *group = crown.find<Vector<int, float> >("group"); 00280 const Vector<int, float> *size = crown.find<Vector<int, float> >("size"); 00281 const Matrix<int, int, float> *precedence = crown.find<Matrix<int, int, float> >(CrownConfig::crownConfigTree); 00282 const Matrix<int, int, float> *member = crown.find<Matrix<int, int, float> >(CrownConfig::crownConfigGroups); 00283 00284 //const Vector<int, float> *frequency = crown.find<Vector<int, float> >("frequency"); 00285 vector<vector<int> > groups; 00286 TaskWidthVector task_width; 00287 ProcScheduleMatrix proc_schedule; 00288 00289 // Create a collection of groups, each empty 00290 for(int group = 1; group <= 2 * p - 1; group++) 00291 { 00292 groups.push_back(vector<int>()); 00293 } 00294 00295 // Get the allocated width of each task 00296 for(map<int, float>::const_iterator i = group->getValues().begin(); i != group->getValues().end(); i++) 00297 { 00298 int task = i->first; 00299 int group = (int)i->second; 00300 00301 // Get the width of the task 00302 task_width.insert(pair<int, float>(task, group_size(group, p, b, size))); 00303 // Insert the task in the relevant group 00304 groups[group - 1].push_back(task); 00305 00306 } 00307 00308 // Get the task sequence for each processor 00309 int max = 0; // This will hold the maximum number of tasks a core handles 00310 { 00311 // Compute the precedence tree 00312 // Initialize one set for each group 00313 set<void*, cmp> groups[2 * p - 1]; 00314 set<void*, cmp> groupset; 00315 00316 // Pre-insert empty groups 00317 for(size_t i = 0; i < (size_t)(2 * p - 1); i++) 00318 { 00319 void* stuff = (void*)&(groups[i]); 00320 groupset.insert(stuff); 00321 } 00322 00323 const map<int, map<int, float> > pred = precedence->getValues(); 00324 00325 // Remove indirect inheritance links. For each group's direct of indirect ancestor group, 00326 // count the number or ancestor group this ancestor has. 00327 // The Ancestor group that has the most ancestor is the unique direct ancestor of 00328 // the group. If so, set the corresponding value to 1. 00329 map<int, map<int, float> > direct_pred = pred; 00330 map<int, size_t> ancestors; 00331 // For each group, count the number of ancestors 00332 for(map<int, map<int, float> >::const_iterator i = pred.begin(); i != pred.end(); i++) 00333 { 00334 size_t count = 0; 00335 for(map<int, float>::const_iterator j = i->second.begin(); j != i->second.end(); j++) 00336 { 00337 count += j->second; 00338 } 00339 ancestors.insert(pair<int, size_t>(i->first, count)); 00340 } 00341 00342 // For each group, browse the groups it depends on, and keep the highest number of dependencies 00343 for(map<int, map<int, float> >::const_iterator i = pred.begin(); i != pred.end(); i++) 00344 { 00345 size_t count = 0; 00346 for(map<int, float>::const_iterator j = i->second.begin(); j != i->second.end(); j++) 00347 { 00348 if(j->second > 0 && ancestors[j->first] > count) 00349 { 00350 count = ancestors[j->first]; 00351 } 00352 } 00353 00354 // having the highest number of dependencies, set 1 to the groups having the same number of dependencies 00355 // (Only the unique direct ancestor), and remove the dependency marker to other groups (write 0). 00356 for(map<int, float>::const_iterator j = i->second.begin(); j != i->second.end(); j++) 00357 { 00358 float newval = 0; 00359 if(ancestors[j->first] == count && j->second > 0) 00360 { 00361 newval = 1; 00362 } 00363 direct_pred.find(i->first)->second.find(j->first)->second = newval; 00364 } 00365 } 00366 00367 // Build the crown tree: a groups is a set of groups, and it receives all its direct subgroups 00368 // If a group has a dependency to an ancestor group, then add the group to the ancestor group's 00369 // list of direct subgroups 00370 for(map<int, map<int, float> >::const_iterator i = direct_pred.begin(); i != direct_pred.end(); i++) 00371 { 00372 size_t ii = i->first - 1; 00373 for(map<int, float>::const_iterator j = i->second.begin(); j != i->second.end(); j++) 00374 { 00375 size_t jj = j->first - 1; 00376 if(j->second > 0) 00377 { 00378 set<void*, cmp>::iterator k = groupset.find((void*)&groups[jj]); 00379 set<void*, cmp> *kk = (set<void*, cmp>*)*k; 00380 groupset.erase(k); 00381 kk->insert((void*)&groups[ii]); 00382 groupset.insert(kk); 00383 } 00384 } 00385 } 00386 00387 // From the list of groups, remove all that appear in the list of subgroups of any group 00388 // Only teh subgroup remains after this step. 00389 for(size_t i = 0; i < (size_t)(2 * p - 1); i++) 00390 { 00391 for(set<void*, cmp>::iterator j = groups[i].begin(); j != groups[i].end(); j++) 00392 { 00393 set<void*, cmp>* jj = (set<void*, cmp>*)*j; 00394 if(groupset.find(jj) != groupset.end()) 00395 { 00396 groupset.erase(groupset.find(jj)); 00397 } 00398 } 00399 } 00400 00401 // Initialize an empty schedule 00402 for(size_t i = 0; i < (size_t)p; i++) 00403 { 00404 proc_schedule.insert(pair<int, map<int, float> >(i + 1, map<int, float>())); 00405 } 00406 00407 // The root group is the only one left in the group collection 00408 set<void*, cmp> *root = (set<void*, cmp>*)*groupset.begin(); 00409 // Build a schedule starting from the root group 00410 max = build_schedule(groups, root, member->getValues(), group->getValues(), proc_schedule); 00411 } 00412 00413 // Fill smaller rows with task 0 so the matrix looks like a proper rectangle matrix 00414 for(int proc = 0; proc < p; proc++) 00415 { 00416 int size = proc_schedule[proc + 1].size(); 00417 00418 while(size < max) 00419 { 00420 size++; 00421 proc_schedule[proc + 1].insert(pair<int, float>(size, 0)); 00422 } 00423 } 00424 00425 Matrix<int, int, float> procSchedule = Matrix<int, int, float>("schedule", proc_schedule); 00426 res.insert(&procSchedule); 00427 00428 return res; 00429 } 00430 00431 CrownScheduler::~CrownScheduler() 00432 { 00433 delete this->config; 00434 } 00435 00436 float 00437 CrownScheduler::complexity(const Algebra &problem) const 00438 { 00439 return config->complexity(problem); 00440 } 00441 00442 float 00443 CrownScheduler::complexity(const Taskgraph &tg, const Platform &pt, const Algebra ¶m) const 00444 { 00445 return config->complexity(tg, pt, param); 00446 } 00447 00448 const Algebra* 00449 CrownScheduler::solve() const 00450 { 00451 map<const string, double> statistics; 00452 Algebra *sol = new Algebra(schedule(tg, pt, param, statistics).buildAlgebra()); 00453 return sol; 00454 } 00455 00456 const Algebra* 00457 CrownScheduler::solve(map<const string, double> &statistics) const 00458 { 00459 Algebra *sol = new Algebra(schedule(tg, pt, param, statistics).buildAlgebra()); 00460 return sol; 00461 } 00462