crown
1.0.0
|
00001 /* 00002 Copyright 2015 Nicolas Melot 00003 00004 This file is part of Crown. 00005 00006 Crown 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 Crown 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 Crown. If not, see <http://www.gnu.org/licenses/>. 00018 00019 */ 00020 00021 00022 #include <fstream> 00023 #include <cstdlib> 00024 #include <set> 00025 00026 #include <pelib/ParseException.hpp> 00027 #include <pelib/AmplInput.hpp> 00028 #include <pelib/AmplInputScalar.hpp> 00029 #include <pelib/AmplInputVector.hpp> 00030 #include <pelib/AmplInputSet.hpp> 00031 #include <pelib/AmplInputMatrix.hpp> 00032 #include <pelib/Scalar.hpp> 00033 #include <pelib/Vector.hpp> 00034 #include <pelib/Matrix.hpp> 00035 #include <pelib/Algebra.hpp> 00036 #include <pelib/AmplOutputScalar.hpp> 00037 #include <pelib/AmplOutputVector.hpp> 00038 #include <pelib/AmplOutputSet.hpp> 00039 #include <pelib/AmplOutputMatrix.hpp> 00040 #include <pelib/AmplOutput.hpp> 00041 00042 #ifdef debug 00043 #undef debug 00044 #endif 00045 00046 #define debug(var) cout << "[" << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << "] " << #var << " = \"" << (var) << "\"" << endl; 00047 00048 using namespace std; 00049 using namespace pelib; 00050 00051 struct task 00052 { 00053 int id, group; 00054 double time_unscaled, time_scaled; 00055 }; 00056 typedef struct task task_t; 00057 00058 // Compare two tasks based on their running time at some given frequency 00059 struct compare_task_per_scaled_time : binary_function <task_t, task_t, bool> 00060 { 00061 bool 00062 operator()(const task_t& t1, const task_t& t2) const 00063 { 00064 if(t1.time_scaled == t2.time_scaled) 00065 { 00066 // If two tasks have the same time, then order them by id 00067 return t1.id < t2.id; 00068 } 00069 else 00070 { 00071 // Use the opposite comparison signe in this line to make increasing or decreasing task rescaling 00072 return t1.time_scaled > t2.time_scaled; 00073 } 00074 } 00075 }; 00076 00077 typedef multiset<task_t, compare_task_per_scaled_time> by_time_t; 00078 00079 static by_time_t 00080 init_frequency_max(const Algebra &input) 00081 { 00082 by_time_t tasks; 00083 00084 set<float> F = input.find<Set<float> >("F")->getValues(); 00085 double maxF = *F.rbegin(); 00086 00087 map<int, float> tau = input.find<Vector<int, float> >("Tau")->getValues(); 00088 map<int, float> wi = input.find<Vector<int, float> >("wi")->getValues(); 00089 map<int, map<int, float> > e = input.find<Matrix<int, int, float> >("e")->getValues(); 00090 map<int, float> group = input.find<Vector<int, float> >("group")->getValues(); 00091 00092 for(map<int, float>::const_iterator i = tau.begin(); i != tau.end(); i++) 00093 { 00094 task_t t; 00095 00096 t.id = i->first; 00097 double tau_t = i->second; 00098 double wi_t = wi.find(t.id)->second; 00099 double e_t = e.find(t.id)->second.find((int)wi_t)->second; 00100 t.time_unscaled = tau_t / (wi_t * e_t); 00101 t.time_scaled = t.time_unscaled / maxF; 00102 t.group = (int)group.find(t.id)->second; 00103 00104 tasks.insert(t); 00105 } 00106 00107 return tasks; 00108 } 00109 00110 static by_time_t 00111 init_frequency_best(const Algebra &input) 00112 { 00113 // TODO: implement 00114 return init_frequency_max(input); 00115 } 00116 00117 static double 00118 update_group(map<int, double> &height, int g, double diff) 00119 { 00120 height[g] = height[g] + diff; 00121 00122 return height[g]; 00123 } 00124 00125 static double 00126 update_child_recursive(map<int, double> &height, int g, double diff, int b, int G) 00127 { 00128 // Update all kid groups, if any 00129 for(int i = 0; i < b && g * b + i <= G; i++) 00130 { 00131 update_child_recursive(height, g * b + i, diff, b, G); 00132 } 00133 00134 // Return the new height of this group 00135 return update_group(height, g, diff);; 00136 } 00137 00138 static void 00139 update_parent_recursive(map<int, double> &height, int g, double new_height, int b, int G) 00140 { 00141 if(g > 1 && new_height > height[g]) 00142 { 00143 update_parent_recursive(height, (int)floor((double)g / (double)b), new_height, b, G); 00144 } 00145 if(g >= 1 && new_height > height[g]) 00146 { 00147 update_group(height, g, new_height - height[g]); 00148 } 00149 } 00150 00151 static void 00152 update_height(map<int, double> &height, int g, double diff, int b, int G) 00153 { 00154 if(height.find(g) != height.end()) 00155 { 00156 update_parent_recursive(height, (int)floor((double)g / (double)b), height[g] + diff, b, G); 00157 update_child_recursive(height, g, diff, b, G); 00158 } 00159 else 00160 { 00161 // Catastrophic error 00162 } 00163 } 00164 00165 static void 00166 print_all_heights(map<int, double> &height) 00167 { 00168 #if DEBUG 00169 for(map<int, double>::const_iterator i = height.begin(); i != height.end(); i++) 00170 { 00171 //cerr << "[" << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << "] group " << i->first << ": " << i->second << endl; 00172 } 00173 #endif 00174 } 00175 00176 static void 00177 print_all_tasks(by_time_t &tasks) 00178 { 00179 #if DEBUG 00180 for(by_time_t::const_iterator i = tasks.begin(); i != tasks.end(); i++) 00181 { 00182 //cerr << "[" << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << "] task " << i->id << ": unscaled time = " << i->time_unscaled << "; scaled time = " << i->time_scaled << "; group = " << i->group << endl; 00183 } 00184 #endif 00185 } 00186 00187 static const long long int nsec_in_sec = 1000000000; 00188 00189 static int 00190 timespec_subtract(struct timespec *result, struct timespec *x, struct timespec *y) 00191 { 00192 00193 /* Perform the carry for the later subtraction by updating y. */ 00194 if (x->tv_nsec < y->tv_nsec) 00195 { 00196 int nsec = (y->tv_nsec - x->tv_nsec) / nsec_in_sec + 1; 00197 y->tv_nsec -= nsec_in_sec * nsec; 00198 y->tv_sec += nsec; 00199 } 00200 if (x->tv_nsec - y->tv_nsec > nsec_in_sec) 00201 { 00202 int nsec = (x->tv_nsec - y->tv_nsec) / nsec_in_sec; 00203 y->tv_nsec += nsec_in_sec * nsec; 00204 y->tv_sec -= nsec; 00205 } 00206 00207 /* Compute the time remaining to wait. tv_nsec is certainly positive. */ 00208 result->tv_sec = x->tv_sec - y->tv_sec; 00209 result->tv_nsec = x->tv_nsec - y->tv_nsec; 00210 00211 /* Return 1 if result is negative. */ 00212 return x->tv_sec < y->tv_sec; 00213 } 00214 00215 Algebra 00216 frequency_height(const Algebra &input) 00217 { 00218 struct timespec start, stop, time; 00219 Algebra schedule = input; 00220 int optimal = 0; 00221 00222 // Load the crown structure 00223 //int b = (int)input.find<Scalar<float> >("b")->getValue(); 00224 int b = 2; 00225 int p = (int)input.find<Scalar<float> >("p")->getValue(); 00226 map<int, double> height; 00227 00228 // Problem data 00229 double M = input.find<Scalar<float> >("M")->getValue(); 00230 set<float> F = input.find<Set<float> >("F")->getValues(); 00231 00232 // Initialize a collection of groups of height 0 00233 // TODO: Make it general with respect to b (assume b = 2 for now) 00234 int G = 2 * p - 1; 00235 //cerr << "[" << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << "] p = " << p << "; G = " << G << endl; 00236 for(int i = 0; i < G; i++) 00237 { 00238 height.insert(pair<int, float>(i + 1, 0)); 00239 } 00240 00241 // Set up the list of tasks at frequency max 00242 by_time_t tasks = init_frequency_best(input); 00243 00244 // Compute an initial height for all groups 00245 for(by_time_t::const_iterator i = tasks.begin(); i != tasks.end(); i++) 00246 { 00247 int g = i->group; 00248 update_height(height, g, i->time_scaled, b, G); 00249 } 00250 00251 // Just make sure everything is alright 00252 print_all_tasks(tasks); 00253 print_all_heights(height); 00254 00255 clock_gettime(CLOCK_MONOTONIC, &start); 00256 00257 for(set<float>::const_reverse_iterator i = F.rbegin(); i != F.rend(); i++) 00258 { 00259 double f = *i; 00260 by_time_t new_tasks; 00261 00262 //cerr << "[" << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << "] Trying frequency f = " << f << endl; 00263 if(f == *F.begin()) 00264 { 00265 optimal = 1; 00266 } 00267 else 00268 { 00269 optimal = 0; 00270 } 00271 00272 for(by_time_t::const_iterator j = tasks.begin(); j != tasks.end(); j++) 00273 { 00274 task_t t = *j; 00275 00276 if(t.time_unscaled / t.time_scaled > f) 00277 { 00278 //cerr << "[" << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << "] Scaling task " << t.id << " in group " << t.group << endl; 00279 //cerr << "[" << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << "] We have " << M - height[t.group] << " slack time" << endl; 00280 //cerr << "[" << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << "] We would compute for " << (t.time_unscaled / f - t.time_scaled) << " longer time" << endl; 00281 //cerr << "[" << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << "] There would be " << M - (height[t.group] + (t.time_unscaled / f - t.time_scaled)) << " time left" << endl; 00282 00283 if(M - (height[t.group] + (t.time_unscaled / f - t.time_scaled)) > 0) 00284 { 00285 double diff = t.time_unscaled / f - t.time_scaled; 00286 t.time_scaled = t.time_unscaled / f; 00287 update_height(height, t.group, diff, b, G); 00288 00289 print_all_heights(height); 00290 print_all_tasks(tasks); 00291 } 00292 else 00293 { 00294 optimal = 0; 00295 } 00296 } 00297 new_tasks.insert(t); 00298 } 00299 tasks = new_tasks; 00300 } 00301 00302 clock_gettime(CLOCK_MONOTONIC, &stop); 00303 00304 print_all_tasks(tasks); 00305 print_all_heights(height); 00306 00307 timespec_subtract(&time, &stop, &start); 00308 Scalar<float> param_time("_total_solve_elapsed_time", (time.tv_sec * nsec_in_sec + time.tv_nsec) / (double)nsec_in_sec); 00309 schedule.insert(¶m_time); 00310 00311 Scalar<float> param_optimal("frequency_optimal", (int)optimal); 00312 schedule.insert(¶m_optimal); 00313 00314 // Generate a frequency vector 00315 map<int, float> frequency; 00316 for(by_time_t::const_iterator i = tasks.begin(); i != tasks.end(); i++) 00317 { 00318 if(!isnan(i->time_unscaled / i->time_scaled)) 00319 { 00320 frequency.insert(pair<int, float>(i->id, i->time_unscaled / i->time_scaled)); 00321 } 00322 else 00323 { 00324 frequency.insert(pair<int, float>(i->id, *F.begin())); 00325 } 00326 } 00327 00328 // Insert values to collection 00329 Vector<int, float> ampl_frequency("frequency", frequency); 00330 schedule.insert(&l_frequency); 00331 00332 Scalar<float> ampl_m("m", M - height[1]); 00333 schedule.insert(&l_m); 00334 00335 return schedule; 00336 } 00337 00338 float 00339 frequency_height_complexity(const pelib::Algebra &input) 00340 { 00341 double n = input.find<Scalar<float> >("n")->getValue(); 00342 double p = input.find<Scalar<float> >("p")->getValue(); 00343 set<float> F = input.find<Set<float> >("F")->getValues(); 00344 00345 return n * p * (1 + F.size() * log(n)); 00346 }