crown  1.0.0
src/CrownConfigTaskgraph.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 <crown/CrownConfigTaskgraph.hpp>
00021 #include <pelib/Matrix.hpp>
00022 #include <pelib/AmplInput.hpp>
00023 #include <pelib/time.h>
00024 
00025 #ifdef debug
00026 #undef debug
00027 #endif
00028 
00029 #define debug(var) cout << "[" << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << "] " << #var << " = \"" << (var) << "\"" << endl;
00030 
00031 using namespace pelib;
00032 using namespace crown;
00033 using namespace std;
00034 
00035 size_t
00036 pick_size(set<size_t> &sizes, size_t avail, size_t alt)
00037 {
00038         size_t out;
00039         if(sizes.size() > 0 && *sizes.rbegin() >= floor(avail / 2))
00040         {
00041                 out = *sizes.rbegin();
00042                 sizes.erase(sizes.find(out));
00043         }
00044         else
00045         {
00046                 out = alt;
00047         }
00048 
00049         return out;
00050 }
00051 
00052 static
00053 map<int, map<int, float> >
00054 build_crown(size_t p, size_t wi, size_t skip, set<size_t> &sizes, const map<int, map<int, float> > matrix, map<int, map<int, float> > &tree)
00055 {
00056         map<int, map<int, float> > config = matrix;
00057         map<int, float> group;
00058         for(size_t i = 0; i < p; i++)
00059         {
00060                 if(i < skip || i >= skip + wi)
00061                 {
00062                         group.insert(pair<int, float>(i + 1, 0));
00063                 }
00064                 else
00065                 {
00066                         group.insert(pair<int, float>(i + 1, 1));
00067                 }
00068         }
00069 
00070         // Dependencies for this group
00071         map<int, float> deps;
00072         for(size_t i = 0; i < 2 * p - 1; i++)
00073         {
00074                 deps.insert(pair<int, float>(i + 1, 0));
00075         }
00076 
00077         // Browse all other groups already formed
00078         for(map<int, map<int, float> >::iterator i = config.begin(); i != config.end(); i++)
00079         {
00080                 // Browse all cores
00081                 int ii = std::distance(config.begin(), i) + 1;
00082                 for(map<int, float>::iterator j = i->second.begin(); j != i->second.end(); j++)
00083                 {
00084                         int jj = std::distance(i->second.begin(), j) + 1;
00085                         // If both groups have the core, then there is a dependency link
00086                         if(group[jj] == j->second && j->second > 0)
00087                         {
00088                                 deps[ii] = 1;
00089                                 break;
00090                         }
00091                 }
00092         }
00093 
00094         // Add groups membership and dependencies to temporary outcome
00095         config.insert(pair<int, map<int, float> >(config.size() + 1, group));
00096         tree.insert(pair<int, map<int, float> >(tree.size() + 1, deps));
00097 
00098         // Recurse, if necessary
00099         if(wi > 1)
00100         {
00101                 size_t size_left = pick_size(sizes, wi, floor((float)wi / 2));
00102                 if(sizes.find(wi - size_left) != sizes.end())
00103                 {
00104                         sizes.erase(sizes.find(wi - size_left));
00105                 }
00106                 size_t size_right = wi - size_left;
00107                 config = build_crown(p, size_left, skip, sizes, config, tree);
00108                 config = build_crown(p, size_right, skip + size_left, sizes, config, tree);
00109         }
00110 
00111         return config;
00112 }
00113 
00114 string
00115 CrownConfigTaskgraph::getShortDescription() const
00116 {
00117         return string("tg");
00118 }
00119 
00120 Algebra
00121 CrownConfigTaskgraph::configure(const Taskgraph &tg, const Platform &pt, const Algebra &param, map<const string, double> &stats) const
00122 {
00123         // Compute a binary crown and place it in class' Algebra container
00124         size_t p = pt.getCores().size();
00125         struct timespec start, stop, total_time;
00126 
00127         // Cellects the width that yields the best ratio efficiency / parallel time for each task
00128         set<size_t> best_group_sizes;
00129         clock_gettime(CLOCK_MONOTONIC, &start); 
00130         for(set<Task>::const_iterator i = tg.getTasks().begin(); i != tg.getTasks().end(); i++)
00131         {
00132                 debug(i->getName());
00133                 size_t best_width = 1;
00134                 float best_ratio = 0;
00135                 for(size_t j = 0; j < p && j < i->getMaxWidth(); j++)
00136                 {
00137                         debug(j + 1);
00138                         debug(i->runtime(j + 1));
00139                         debug(i->getEfficiency(j + 1));
00140                         float task_time = i->runtime(j + 1, 1);
00141                         float quality = i->getEfficiency(j + 1) / task_time;
00142                         debug(quality);
00143                         if(quality > best_ratio)
00144                         {
00145                                 best_ratio = quality;
00146                                 best_width = j + 1;
00147                                 debug(best_width);
00148                         }
00149                 }
00150                 if(best_width < p)
00151                 {
00152                         debug(best_width);
00153                         best_group_sizes.insert(best_width);
00154                 }
00155         }
00156 
00157         map<int, map<int, float> > tree;
00158         map<int, map<int, float> > config = build_crown(p, p, 0, best_group_sizes, map<int, map<int, float> >(), tree);
00159         clock_gettime(CLOCK_MONOTONIC, &stop);
00160         pelib_timespec_subtract(&total_time, &stop, &start);
00161 
00162         stats.insert(pair<const string, double>("time_config", (float)(total_time.tv_sec * pelib_nsec_in_sec + total_time.tv_nsec) / (float)pelib_nsec_in_sec));
00163         Algebra conf;
00164         conf.insert(new Matrix<int, int, float>(CrownConfig::crownConfigGroups, config));
00165         conf.insert(new Matrix<int, int, float>(CrownConfig::crownConfigTree, tree));
00166 
00167         return conf;
00168 }
00169 
00170 CrownConfigTaskgraph::~CrownConfigTaskgraph()
00171 {
00172         // Do nothing
00173 }
00174 
00175 CrownConfig*
00176 CrownConfigTaskgraph::clone() const
00177 {
00178         return new CrownConfigTaskgraph(*this);
00179 }
00180 
00181 float
00182 CrownConfigTaskgraph::complexity(const Algebra &problem) const
00183 {
00184         return 0;
00185 }
00186 
00187 float
00188 CrownConfigTaskgraph::complexity(const Taskgraph&, const Platform&, const Algebra&) const
00189 {
00190         return 0;
00191 }
00192