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 00015 #include <crown/allocation.h> 00016 #include <crown/mapping.h> 00017 #include <crown/scaling.h> 00018 #include <crown/crown.h> 00019 #include <crown/annealing.h> 00020 #include <crown/CrownCompositeConsolidation.hpp> 00021 #include <crown/CrownException.hpp> 00022 00023 #include <pelib/AmplInput.hpp> 00024 #include <pelib/Schedule.hpp> 00025 #include <pelib/Scalar.hpp> 00026 #include <pelib/Vector.hpp> 00027 #include <pelib/Matrix.hpp> 00028 #include <pelib/Set.hpp> 00029 #include <pelib/time.h> 00030 00031 #ifdef debug 00032 #undef debug 00033 #endif 00034 00035 #define debug(var) cout << "[" << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << "] " << #var << " = \"" << (var) << "\"" << endl; 00036 00037 using namespace std; 00038 using namespace pelib; 00039 using namespace pelib::crown; 00040 00041 // Quality assessment parameters 00042 static const long long int nsec_in_sec = 1000000000; 00043 00044 const string CrownCompositeConsolidation::dummyTaskPrefix(DUMMY_TASK); 00045 const string CrownCompositeConsolidation::realTaskPrefix("Real task"); 00046 00047 Algebra 00048 CrownCompositeConsolidation::solve(const Algebra &tg, const Algebra &pt, const pelib::Algebra ¶m, std::map<const std::basic_string<char>, double> &stats) const 00049 { 00050 float p = pt.find<Scalar<float> >("p")->getValue(); 00051 float logp = pow(2, floor(log(p) / log(2))); 00052 00053 if(p == logp || 1) 00054 { 00055 Algebra taskgraph = tg; 00056 00057 // Get useful problem data 00058 float n = taskgraph.find<Scalar<float> >("n")->getValue(); 00059 float M = taskgraph.find<Scalar<float> >("M")->getValue(); 00060 map<int, float> work = taskgraph.find<Vector<int, float> >("Tau")->getValues(); 00061 map<int, float> max_width = taskgraph.find<Vector<int, float> >("Wi")->getValues(); 00062 map<int, map<int, float> > efficiency = taskgraph.find<Matrix<int, int, float> >("e")->getValues(); 00063 00064 // Make mock-up efficiency function for dummy tasks 00065 map<int, float> dummy_e; 00066 dummy_e.insert(pair<int, float>(1, 1)); 00067 for(size_t i = 1; i < p; i++) 00068 { 00069 dummy_e.insert(pair<int, float>(i + 1, 1e-6)); 00070 } 00071 00072 // Make up task names for existing tasks 00073 map<int, string> name; 00074 for(size_t i = 0; i < n; i++) 00075 { 00076 stringstream ssname; 00077 ssname << realTaskPrefix << " " << i + 1; 00078 name.insert(pair<int, string>(i + 1, ssname.str())); 00079 } 00080 00081 // Fill up task with mock-up names, workloads and efficiency 00082 for(size_t i = 0; i < p - 1; i++) 00083 { 00084 stringstream ssname; 00085 ssname << dummyTaskPrefix << " " << n + i + 1; 00086 name.insert(pair<int, string>(n + i + 1, ssname.str())); 00087 work.insert(pair<int, float>(n + i + 1, 0)); 00088 max_width.insert(pair<int, float>(n + i + 1, 1)); 00089 efficiency.insert(pair<int, map<int, float> >(n + i + 1, dummy_e)); 00090 } 00091 00092 taskgraph.remove("n"); 00093 taskgraph.remove("Tau"); 00094 taskgraph.remove("Wi"); 00095 taskgraph.remove("e"); 00096 Scalar<float> N("n", n + p - 1); 00097 Vector<int, float> Tau("Tau", work); 00098 Vector<int, float> Wi("Wi", max_width); 00099 Vector<int, string> Name("name", name); 00100 Matrix<int, int, float> e("e", efficiency); 00101 taskgraph.insert(&N); 00102 taskgraph.insert(&Tau); 00103 taskgraph.insert(&Wi); 00104 taskgraph.insert(&Name); 00105 taskgraph.insert(&e); 00106 00107 float max_freq = *pt.find<Set<float> >("F")->getValues().rbegin(); 00108 00109 // Compute all indices of dummy tasks 00110 vector<size_t> dummy_index; 00111 for(size_t i = 0; i < p - 1; i++) 00112 { 00113 //stringstream ss; 00114 //ss << dummyTaskPrefix << " " << i + 1; 00115 //size_t index = std::distance(tg.getTasks().begin(), tg.getTasks().find(ss.str())) + 1; 00116 dummy_index.push_back(n + i + 1); 00117 } 00118 00119 // Get direct access to task workloads 00120 map<int, float> &dummy_task_workload = (map<int, float>&)taskgraph.find<Vector<int, float> >("Tau")->getValues(); 00121 00122 // Run Crown binary 00123 struct timespec start, stop, total_time; 00124 clock_gettime(CLOCK_MONOTONIC, &start); 00125 //Algebra best_schedule = crown_binary(schedule, 3); 00126 Algebra best_schedule = scheduler->solve(taskgraph, pt, param, stats); 00127 float best_quality = energy_static_dynamic_busy_idle_active(best_schedule); 00128 //float best_quality = best_schedule.find<Scalar<float> >("quality")->getValue(); 00129 float best_m = best_schedule.find<Scalar<float> >("m")->getValue(); 00130 float m = best_m; 00131 size_t index = 0; 00132 00133 // Increase the number of cores switched off until we reach p cores or 00134 // until it is not possible to generate any valid schedule anymore 00135 while(index <= p - 1 && m >= 0) 00136 { 00137 // Then we set the dummy tasks' only admissible width to the current number 00138 // of cores to switch off 00139 // Set the dummy task workload so that it must run from time 0 to M at max freqeuncy to make the deadline 00140 dummy_task_workload[n + index + 1] = M * max_freq; 00141 00142 // Try to compute a new schedule 00143 //Algebra current = crown_binary(schedule, 3); 00144 Algebra current = scheduler->solve(taskgraph, pt, param, stats); 00145 00146 // Get the new schedule's quality and correctness 00147 float quality = energy_static_dynamic_busy_idle_active(current); 00148 //float quality = current.find<Scalar<float> >("quality")->getValue(); 00149 m = current.find<Scalar<float> >("m")->getValue(); 00150 00151 // If the new schedule is correct and more energy-efficient that the best schedule 00152 // the replace the best schedule 00153 if((m >= 0 || M <= 0) && quality < best_quality) 00154 { 00155 best_schedule = current; 00156 best_quality = quality; 00157 best_m = m; 00158 } 00159 00160 // Prepare for next task to activate 00161 index++; 00162 } 00163 00164 clock_gettime(CLOCK_MONOTONIC, &stop); 00165 00166 // Remove dummy tasks 00167 best_schedule.remove("n"); 00168 best_schedule.remove("Tau"); 00169 best_schedule.remove("Wi"); 00170 best_schedule.remove("e"); 00171 best_schedule.remove("name"); 00172 N = Scalar<float>("n", n); 00173 Tau = Vector<int, float>("Tau", work); 00174 Wi = Vector<int, float>("Wi", max_width); 00175 Name = Vector<int, string>("name", name); 00176 e = Matrix<int, int, float>("e", efficiency); 00177 best_schedule.insert(tg.find<Scalar<float> >("n")); 00178 best_schedule.insert(tg.find<Vector<int, float> >("Tau")); 00179 best_schedule.insert(tg.find<Vector<int, float> >("Wi")); 00180 best_schedule.insert(tg.find<Matrix<int, int, float> >("e")); 00181 00182 // Remove dummy tasks from best_schedule 00183 map<int, float> grp = best_schedule.find<Vector<int, float> >("group")->getValues(); 00184 map<int, float> freq = best_schedule.find<Vector<int, float> >("frequency")->getValues(); 00185 map<int, float> size = best_schedule.find<Vector<int, float> >("wi")->getValues(); 00186 best_schedule.remove("group"); 00187 best_schedule.remove("frequency"); 00188 best_schedule.remove("wi"); 00189 for(size_t i = 0; i < p - 1; i++) 00190 { 00191 grp.erase(grp.find(n + i + 1)); 00192 freq.erase(freq.find(n + i + 1)); 00193 size.erase(size.find(n + i + 1)); 00194 } 00195 Vector<int, float> group("group", grp); 00196 Vector<int, float> frequency("frequency", freq); 00197 Vector<int, float> wi("wi", size); 00198 best_schedule.insert(&group); 00199 best_schedule.insert(&frequency); 00200 best_schedule.insert(&wi); 00201 00202 // Report mapping quality 00203 stats.insert(pair<string, double>("quality", best_quality)); 00204 00205 // Report optimization time 00206 float time = (float)(total_time.tv_sec * nsec_in_sec + total_time.tv_nsec) / (float)nsec_in_sec; 00207 stats.insert(pair<string, double>("time_global", time)); 00208 00209 return best_schedule; 00210 } 00211 else 00212 { 00213 throw CrownException("Binary scheduler cannot handle non-power of two number of cores"); 00214 } 00215 } 00216 00217 CrownCompositeConsolidation::CrownCompositeConsolidation(const CrownScheduler *scheduler, bool showOutput, bool showError) : CrownComposite(scheduler, showOutput, showError) 00218 { 00219 /* Do nothing else */ 00220 } 00221 00222 CrownCompositeConsolidation::CrownCompositeConsolidation(const Algebra ¶m, const CrownScheduler *scheduler, bool showOutput, bool showError) : CrownComposite(param, scheduler, showOutput, showError) 00223 { 00224 /* Do nothing else */ 00225 } 00226 00227 CrownCompositeConsolidation::CrownCompositeConsolidation(const Taskgraph &tg, const Platform &pt, const Algebra ¶m, const CrownScheduler *scheduler, bool showOutput, bool showError) : CrownComposite(tg, pt, param, scheduler, showOutput, showError) 00228 { 00229 /* Do nothing else */ 00230 } 00231 00232 CrownCompositeConsolidation::CrownCompositeConsolidation(const CrownCompositeConsolidation &src) : CrownComposite(src) 00233 { 00234 /* nothing else to do */ 00235 } 00236 00237 float 00238 CrownCompositeConsolidation::complexity(const Algebra &problem) const 00239 { 00240 return 0; 00241 } 00242 00243 float 00244 CrownCompositeConsolidation::complexity(const Taskgraph&, const Platform&, const Algebra&) const 00245 { 00246 return 0; 00247 } 00248 00249 CrownCompositeConsolidation* 00250 CrownCompositeConsolidation::clone() const 00251 { 00252 return new CrownCompositeConsolidation(*this); 00253 } 00254 00255 Schedule 00256 CrownCompositeConsolidation::schedule(const Taskgraph &tg, const Platform &pt, std::map<const string, double>& stats) const 00257 { 00258 Algebra param = this->param; 00259 00260 // TODO: Make scheduler work without scalar b 00261 //param.insert(new Scalar<float>("b", 2)); 00262 param = param.merge(scheduler->addCrownConfig(tg, pt, param, stats)); 00263 00264 // Take task name out 00265 Algebra taskgraph = tg.buildAlgebra(pt); 00266 Vector<int, string> name = *taskgraph.find<Vector<int, string> >("name"); 00267 taskgraph.remove("name"); 00268 00269 //Perform actual work 00270 Algebra schedule = solve(taskgraph, pt.buildAlgebra(), param, stats); 00271 00272 // Put back task names 00273 schedule.insert(new Vector<int, string>(name)); 00274 00275 // Convert crown schedule to regular algebra schedule 00276 schedule = CrownScheduler::crownToSchedule(schedule); 00277 00278 // Add task starting time 00279 schedule = Schedule::addStartTime(schedule, tg, pt); 00280 00281 // report scheduling complexity 00282 float complexity = pt.getCores().size() * crown_binary_complexity(schedule) * (allocation_fastest_complexity(schedule) + mapping_ltlg_complexity(schedule) + frequency_height_complexity(schedule)); 00283 stats.insert(pair<string, double>("complexity", complexity)); 00284 00285 float M = tg.getDeadline(pt); 00286 float m = schedule.find<Scalar<float> >("m")->getValue(); 00287 Schedule *sched; 00288 if(m < 0 && M > 0) 00289 { 00290 stats.insert(pair<string, double>("feasible", 0)); 00291 sched = new Schedule(getShortDescription(), tg.getName(), Schedule::table()); 00292 } 00293 else 00294 { 00295 stats.insert(pair<string, double>("feasible", 1)); 00296 string desc = getShortDescription(); 00297 sched = new Schedule(desc, tg.getName(), schedule); 00298 } 00299 00300 Schedule final = *sched; 00301 delete sched; 00302 return final; 00303 } 00304 00305 Schedule 00306 CrownCompositeConsolidation::schedule(const Taskgraph &tg, const Platform &pt, const Algebra ¶m, std::map<const string, double>& stats) const 00307 { 00308 return schedule(tg, pt, stats); 00309 } 00310 00311 std::string 00312 CrownCompositeConsolidation::getShortDescription() const 00313 { 00314 return string("Cons.") + scheduler->getShortDescription(); 00315 } 00316