crown  1.0.0
src/CrownScalingHeight.cpp
Go to the documentation of this file.
00001 // The following definitions might be exchanged for others,
00002 // when integrating the following code into the framework.
00003 // The code implements a greedy heuristic to loadbalance the tasks
00004 // over cores such that the l2-norm of the load vector is minimized.
00005 // This should also minimize the l3-norm of the load vector.
00006 // J. Keller, July 14, 2014
00007 
00008 #include <stdio.h>
00009 #include <stdlib.h>
00010 #include <string.h>
00011 #include <math.h>
00012 #include <iostream>
00013 #include <sstream>
00014 #include <fstream>
00015 #include <cstdlib>
00016 #include <set>
00017 #include <map>
00018 
00019 #include <crown/allocation.h>
00020 #include <crown/mapping.h>
00021 #include <crown/scaling.h>
00022 #include <crown/crown.h>
00023 #include <crown/CrownScalingHeight.hpp>
00024 #include <crown/CrownConfigBinary.hpp>
00025 
00026 #include <pelib/XMLSchedule.hpp>
00027 #include <pelib/AmplInput.hpp>
00028 #include <pelib/AmplOutput.hpp>
00029 #include <pelib/Vector.hpp>
00030 #include <pelib/Matrix.hpp>
00031 #include <pelib/Set.hpp>
00032 #include <pelib/GraphML.hpp>
00033 #include <pelib/Schedule.hpp>
00034 #include <pelib/Task.hpp>
00035 #include <pelib/time.h>
00036 
00037 #include <pelib/ParseException.hpp>
00038 #include <pelib/AmplInputScalar.hpp>
00039 #include <pelib/AmplInputVector.hpp>
00040 #include <pelib/AmplInputSet.hpp>
00041 #include <pelib/AmplInputMatrix.hpp>
00042 #include <pelib/Scalar.hpp>
00043 #include <pelib/Algebra.hpp>
00044 #include <pelib/AmplOutputScalar.hpp>
00045 #include <pelib/AmplOutputVector.hpp>
00046 #include <pelib/AmplOutputSet.hpp>
00047 #include <pelib/AmplOutputMatrix.hpp>
00048 #include <pelib/AmplOutput.hpp>
00049 
00050 #ifdef debug
00051 #undef debug
00052 #endif
00053 
00054 #if 01
00055 #define debug(var) cout << "[" << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << "] " << #var << " = \"" << var << "\"" << endl;
00056 #else
00057 #define debug(var)
00058 #endif
00059 
00060 using namespace std;
00061 using namespace pelib;
00062 using namespace pelib::crown;
00063 
00064 static const long long int nsec_in_sec = 1000000000;
00065 
00066 typedef std::map<int, float> RowType;
00067 typedef std::map<int, RowType> MatrixType;
00068 
00069 // Group structure containing the number of the group, its height, width descendants and ancestors
00070 struct Group
00071 {
00072     int number;
00073     double time;
00074     vector<int> sons;
00075     vector<int> parents;
00076 
00077     Group(int gn, int gt)
00078         {
00079             number = gn;
00080             time = gt;
00081             sons = vector<int>();
00082             parents = vector<int>();
00083         }
00084 };
00085 
00086 struct task
00087 {
00088     int id, group;
00089     double time_unscaled, time_scaled;
00090 };
00091 typedef struct task task_t;
00092 
00093 // Compare two tasks based on their running time at some given frequency
00094 struct compare_task_per_scaled_time : binary_function <task_t, task_t, bool>
00095 {
00096     bool
00097     operator()(const task_t& t1, const task_t& t2) const
00098         {               
00099             if(t1.time_scaled == t2.time_scaled)
00100             {
00101                 // If two tasks have the same time, then order them by id
00102                 return t1.id < t2.id;
00103             }
00104             else
00105             {
00106                 // Use the opposite comparison signe in this line to make increasing or decreasing task rescaling
00107                 return t1.time_scaled > t2.time_scaled;
00108             }
00109         }
00110 };
00111 
00112 typedef multiset<task_t, compare_task_per_scaled_time> by_time_t;
00113 
00114 static by_time_t
00115 init_frequency_max(const Algebra &input)
00116 {
00117     by_time_t tasks;
00118 
00119     set<float> F = input.find<Set<float> >("F")->getValues();
00120     double maxF = *F.rbegin();
00121 
00122     map<int, float> tau = input.find<Vector<int, float> >("Tau")->getValues();
00123     map<int, float> wi = input.find<Vector<int, float> >("wi")->getValues();
00124     map<int, map<int, float> > e = input.find<Matrix<int, int, float> >("e")->getValues();
00125     map<int, float> group = input.find<Vector<int, float> >("group")->getValues();
00126 
00127     for(map<int, float>::const_iterator i = tau.begin(); i != tau.end(); i++)
00128     {
00129         task_t t;
00130                 
00131         t.id = i->first;
00132         double tau_t = i->second;
00133         double wi_t = wi.find(t.id)->second;
00134         double e_t = e.find(t.id)->second.find((int)wi_t)->second;
00135         t.time_unscaled = tau_t / (wi_t * e_t);
00136         t.time_scaled = t.time_unscaled / maxF;
00137         t.group = (int)group.find(t.id)->second;
00138                 
00139         tasks.insert(t);
00140     }
00141         
00142     return tasks;
00143 }
00144 
00145 static by_time_t
00146 init_frequency_best(const Algebra &input)
00147 {
00148     return init_frequency_max(input);
00149 }
00150 
00151 static void update_height(map<int, Group*> &height, int g, double diff)
00152 {
00153     double son, max;
00154         max = height[g]->time + diff;
00155     for(vector<int>::iterator it = height[g]->sons.begin() ; it != height[g]->sons.end() ; ++it)
00156     {
00157         height[*it]->time += diff;
00158         son = height[*it]->time;
00159         if(son > max) max = son;
00160     }
00161     
00162     height[g]->time = max;
00163     for(vector<int>::reverse_iterator it = height[g]->parents.rbegin() ; it != height[g]->parents.rend(); ++it)
00164     {
00165         if(height[*it]->time < height[g]->time)
00166         {
00167                 height[*it]->time = height[g]->time;
00168         }
00169     }
00170 }
00171 
00172 CrownScalingHeight::CrownScalingHeight(const CrownConfig *config, const CrownAllocation *alloc, const CrownMapping *mapping, bool showOutput, bool showError) : CrownScaling(config, alloc, mapping, showOutput, showError)
00173 {
00174     /* Do nothing else */
00175 }
00176 
00177 CrownScalingHeight::CrownScalingHeight(const Algebra &param, const CrownConfig *config, const CrownAllocation *alloc, const CrownMapping *mapping, bool showOutput, bool showError): CrownScaling(param, config, alloc, mapping, showOutput, showError)
00178 {
00179     /* Do nothing else */
00180 }
00181 
00182 CrownScalingHeight::CrownScalingHeight(const Taskgraph &tg, const Platform &pt, const Algebra &param, const CrownConfig *config, const CrownAllocation *alloc, const CrownMapping *mapping, bool showOutput, bool showError): CrownScaling(tg, pt, param, config, alloc, mapping, showOutput, showError)
00183 {
00184     /* Do nothing else */
00185 }
00186 
00187 CrownScalingHeight::CrownScalingHeight(const CrownScalingHeight &src) : CrownScaling(src)
00188 {
00189     /* Do nothing else */
00190 }
00191 
00192 Algebra
00193 CrownScalingHeight::scale(const Algebra &input, std::map<const string, double> &stats) const
00194 {
00195     struct timespec start, stop, time;
00196     Algebra schedule = input;
00197     int optimal = 0;
00198 
00199     // Load the crown structure
00200     map<int, Group*> height;
00201 
00202     // Problem data
00203     double M = input.find<Scalar<float> >("M")->getValue();
00204     set<float> F = input.find<Set<float> >("F")->getValues();
00205 
00206     MatrixType matrix_groups = input.find<Matrix<int, int, float> >(CrownConfig::crownConfigGroups)->getValues();
00207     MatrixType matrix_tree = input.find<Matrix<int, int, float> >(CrownConfig::crownConfigTree)->getValues();
00208 
00209     // Initialize the collection of groups of height 0
00210     for(unsigned int i = 1 ; i <= matrix_groups.size() ; ++i)
00211     {
00212         height.insert(std::make_pair(i, new Group(i, 0.0)));
00213     }
00214 
00215     // Setting the inheritance : (2p-1)² = 4p²-4p+3 = O(p²)
00216     for(unsigned int i = 1 ; i <= matrix_tree.size() ; ++i)
00217     {
00218         for(unsigned int j = 1 ; j <= matrix_tree.begin()->second.size() ; ++j)
00219         {
00220             if(matrix_tree.find(i)->second.find(j)->second)
00221             {
00222                 height[j]->sons.push_back(i);
00223                 height[i]->parents.push_back(j);
00224             }
00225         }
00226     }
00227         
00228     // Set up the list of tasks at frequency max
00229     by_time_t tasks = init_frequency_best(input);
00230 
00231     // Compute an initial height for all groups
00232     for(by_time_t::const_iterator i = tasks.begin(); i != tasks.end(); i++)
00233     {
00234         int g = i->group;
00235         update_height(height, g, i->time_scaled);
00236     }
00237 
00238     clock_gettime(CLOCK_MONOTONIC, &start);
00239 
00240     for(set<float>::const_reverse_iterator i = F.rbegin(); i != F.rend(); i++)
00241     {
00242         double f = *i;
00243         by_time_t new_tasks;
00244         double diff;
00245                 
00246         if(f == *F.begin())
00247         {
00248             optimal = 1;
00249         }
00250         else
00251         {
00252             optimal = 0;
00253         }
00254         
00255         for(by_time_t::const_iterator j = tasks.begin(); j != tasks.end(); j++)
00256         {
00257             task_t t = *j;
00258             
00259             if(t.time_unscaled / t.time_scaled > f)
00260             {
00261                 if(M - (height[t.group]->time + (t.time_unscaled / f - t.time_scaled)) > 0)
00262                 {
00263                     diff = t.time_unscaled / f - t.time_scaled;
00264                     t.time_scaled = t.time_unscaled / f;
00265                     update_height(height, t.group, diff);
00266                 }
00267                 else
00268                 {
00269                     optimal = 0;
00270                 }
00271             }
00272             new_tasks.insert(t);
00273         }
00274         tasks = new_tasks;
00275     }
00276     
00277     clock_gettime(CLOCK_MONOTONIC, &stop);
00278     
00279     pelib_timespec_subtract(&time, &stop, &start);
00280     stats.insert(pair<const string, double>("time_scaling", (time.tv_sec * nsec_in_sec + time.tv_nsec) / (float)nsec_in_sec));
00281     stats.insert(pair<const string, double>("frequency_optimal", optimal));
00282 
00283     // Generate a frequency vector
00284     map<int, float> frequency;
00285     for(by_time_t::const_iterator i = tasks.begin(); i != tasks.end(); i++)
00286     {
00287         if(!isnan(i->time_unscaled / i->time_scaled))
00288         {
00289             frequency.insert(pair<int, float>(i->id, i->time_unscaled / i->time_scaled));
00290         }
00291         else
00292         {
00293             frequency.insert(pair<int, float>(i->id, *F.begin()));
00294         }
00295     }
00296 
00297     // Insert values to collection
00298     Vector<int, float> ampl_frequency("frequency", frequency);
00299     schedule.insert(&ampl_frequency);
00300 
00301     Scalar<float> ampl_m("m", M - height[1]->time);
00302     schedule.insert(&ampl_m);
00303     return schedule;
00304 }
00305 
00306 Schedule
00307 CrownScalingHeight::scale(const Taskgraph &tg, const Platform &pt, const Algebra &param, const CrownConfig *config, std::map<const string, double> &stats) const
00308 {
00309     Algebra alg = tg.buildAlgebra(pt);
00310     alg = alg.merge(pt.buildAlgebra());
00311     alg = alg.merge(param);
00312     if(config == NULL)
00313     {
00314         CrownConfigBinary conf;
00315         config = &conf;
00316     }
00317     alg = alg.merge(config->configure(tg, pt, param, stats));
00318     alg = Schedule::addStartTime(alg, tg, pt);
00319 
00320     Schedule sched(getShortDescription(), tg.getName(), alg);
00321 
00322     return sched;
00323 }
00324 
00325 float
00326 CrownScalingHeight::complexity(const Taskgraph &tg, const Platform &pt, const Algebra &param, const CrownConfig* config) const
00327 {
00328     Algebra alg = tg.buildAlgebra(pt);
00329     alg = alg.merge(pt.buildAlgebra());
00330     alg = alg.merge(param);
00331     if(config == NULL)
00332     {
00333         CrownConfigBinary conf;
00334         config = &conf;
00335     }
00336     std::map<const string, double> stats;
00337     alg = alg.merge(config->configure(tg, pt, param, stats));
00338 
00339     return complexity(alg);
00340 }
00341 
00342 float
00343 CrownScalingHeight::complexity(const pelib::Algebra &input) const
00344 {
00345     double n = input.find<Scalar<float> >("n")->getValue();
00346     double p = input.find<Scalar<float> >("p")->getValue();
00347     set<float> F = input.find<Set<float> >("F")->getValues();
00348 
00349     return n * p * (1 + F.size() * log(n));
00350 }
00351 
00352 std::string
00353 CrownScalingHeight::getShortDescription() const
00354 {
00355     stringstream ss;
00356     std::streamsize p = ss.precision();
00357     ss.precision(4);
00358     ss << "newHeight";
00359     ss.precision(p);
00360 
00361     return ss.str();
00362 }
00363 
00364 CrownScaling*
00365 CrownScalingHeight::clone() const
00366 {
00367     return new CrownScalingHeight(*this);
00368 }
00369