crown
1.0.0
|
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 ¶m, 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 ¶m, 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(&l_frequency); 00300 00301 Scalar<float> ampl_m("m", M - height[1]->time); 00302 schedule.insert(&l_m); 00303 return schedule; 00304 } 00305 00306 Schedule 00307 CrownScalingHeight::scale(const Taskgraph &tg, const Platform &pt, const Algebra ¶m, 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 ¶m, 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