crown  1.0.0
src/CrownBinary.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/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 &param, 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 &param, 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 &param) 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 &param, 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 &param, 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