crown  1.0.0
src/CrownScheduler.cpp
Go to the documentation of this file.
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 &param, 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 &param) 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