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 #include <crown/mapping.h> 00043 00044 #if LONGEST_WIDEST_LOWEST_TASK_FIRST 00045 #undef LONGEST_WIDEST_TASK_FIRST 00046 #define LONGEST_WIDEST_TASK_FIRST 1 00047 #endif 00048 00049 #if LONGEST_WIDEST_TASK_FIRST 00050 #undef LONGEST_TASK_FIRST 00051 #define LONGEST_TASK_FIRST 1 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 00063 typedef map<int, float> by_group_t; 00064 typedef pair<int, float> group_time_t; 00065 00066 typedef std::map<int, float> RowType; 00067 typedef std::map<int, RowType> MatrixType; 00068 00069 // Needed tp compare two group_time_t elements in the set whose definition comes right after 00070 struct cmp_time : binary_function <group_time_t, group_time_t, bool> 00071 { 00072 bool 00073 operator()(const group_time_t& x, const group_time_t& y) const 00074 { 00075 // Operand groups' ids 00076 int xfirst = x.first; 00077 int yfirst = y.first; 00078 00079 // Operand groups' time 00080 float xsecond = x.second; 00081 float ysecond = y.second; 00082 00083 //cerr << "[" << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << "] x.first: " << x.first << "; y.first: " << y.first << "; x.second: " << x.second << "; y.second: " << y.second << endl; 00084 //cerr << "[" << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << "] xfirst: " << xfirst << "; yfirst: " << yfirst << "; xsecond: " << xsecond << "; ysecond: " << ysecond << endl; 00085 00086 if(xsecond == ysecond) 00087 { 00088 // If two groups have the same time, then order them by id 00089 //cerr << "[" << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << "] " << (xfirst < yfirst) << endl; 00090 return xfirst < yfirst; 00091 } 00092 else 00093 { 00094 //cerr << "[" << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << "] " << (xsecond < ysecond) << endl; 00095 return xsecond < ysecond; 00096 } 00097 } 00098 }; 00099 00100 typedef multiset<group_time_t, cmp_time> by_time_t; 00101 typedef pair<by_group_t, by_time_t> level_time_t; 00102 typedef map<int, level_time_t> mapping_time_t; 00103 typedef vector<pair<int, int> > mapping_t; 00104 00105 static int n, b, L, p, G; 00106 //static AmplInput data(AmplInput::floatHandlers()); 00107 00108 static Algebra *rec; 00109 static mapping_t schedule; 00110 static mapping_time_t load; // Map organized by group size 00111 static map<int, float> vector_Wi; 00112 static map<int, float> vector_Tau; 00113 static map<int, float> vector_wi; 00114 static MatrixType matrix_e; 00115 00116 /* 00117 static int 00118 size(int g) 00119 { 00120 return (int)pow((double)b, (double)(L - floor(log2(g)))); 00121 } 00122 00123 static size_t 00124 begin(int g) 00125 { 00126 return (size_t)(size(g) * (g - pow(b, floor(log2(g))))); 00127 } 00128 00129 static size_t 00130 end(int g) 00131 { 00132 return begin(g) + size(g); 00133 } 00134 */ 00135 00136 /* 00137 static void 00138 show_group_time() 00139 { 00140 for(mapping_time_t::iterator lvl = load.begin(); lvl != load.end(); lvl++) 00141 { 00142 for(by_time_t::iterator time = lvl->second.second.begin(); time != lvl->second.second.end(); time++) 00143 { 00144 cout << "In level " << lvl->first << ": group " << time->first << " has time " << time->second << endl; 00145 } 00146 } 00147 } 00148 */ 00149 00150 static float 00151 update_group_time(int g, float time_offset) // O(log(p)) 00152 { 00153 //cerr << "Updating group " << g << " by " << time_offset << endl; 00154 // Update the group itself 00155 00156 // Find out what level is this group in 00157 //int lvl = (int)(floor(log(g) / log(b))); // O(1) 00158 int lvl = (int)(floor(log2(g) / (b - 1))); // TODO: floor(log(g) / log(b)) is broken (g++ 3.4.5) and returns 2 for g = 8 and b = 2, but we have to use b so the compiler shuts up. To be restored with a compiler fix // O(1) 00159 //show_group_time(); 00160 00161 // Get the group collection of level of the group we modify 00162 mapping_time_t::iterator level_time = load.find(lvl); // O(log(log(p))) 00163 00164 // Get the run time of the group we want to modify, thanks to the group key 00165 float time = level_time->second.first.find(g)->second; // O(log(p)) 00166 00167 // Get an iterator to the group we want to modify, 00168 // in the collection sorted by time 00169 group_time_t group_key = group_time_t(g, time); 00170 by_time_t::iterator iter = level_time->second.second.find(group_key); 00171 00172 /* 00173 if(iter == level_time->second.second.end()) 00174 { 00175 cerr << "g = " << g << "; time = " << time << endl; 00176 cerr << "Error" << endl; 00177 } 00178 */ 00179 00180 // Get a copy of the group record 00181 group_time_t group_time = *iter; 00182 00183 // Update its time in the 00184 group_time.second = time + time_offset; 00185 00186 /* 00187 cerr << time << " + " << time_offset << endl; 00188 cerr << (*iter).first << " " << (*iter).second << endl; 00189 cerr << group_time.first << " " << group_time.second << endl 00190 */ 00191 00192 // Update the group record in the time-sorted collection 00193 level_time->second.second.erase(iter); // O(log(p)) 00194 level_time->second.second.insert(group_time); // O(log(p)) 00195 00196 // Update the time in the group-sorted collection 00197 level_time->second.first.find(g)->second = time + time_offset; // O(log(p)) 00198 00199 return time + time_offset; 00200 } 00201 00202 static float 00203 recursive_update_time(int g, float time_offset) // O(b log(p)) 00204 { 00205 float max; 00206 float descendant; 00207 00208 // Update this group time 00209 //cerr << "[" << __FILE__ << ";" << __FUNCTION__ << ";" << __LINE__ << "] g = " << g << "; time_offset = " << time_offset << endl; 00210 max = update_group_time(g, time_offset); // O(log(p)) 00211 00212 // Also update all groups recursively in the group being updated 00213 for(int i = b * g; i < G + 1 && i < (g + 1) * b; i++) // O(b * log(p)) 00214 { 00215 descendant = recursive_update_time(i, time_offset); // O(log(p)) 00216 if(descendant > max) max = descendant; 00217 } 00218 00219 return max; 00220 } 00221 00222 static float 00223 update_time(int g, float time_offset) // O(log^2(p)) 00224 { 00225 #if LONGEST_TASK_FIRST 00226 // Update group time and its descendants' 00227 //cerr << "[" << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << "] " << time_offset << endl; 00228 float target_time = recursive_update_time(g, time_offset); // O(b log(p)) 00229 00230 // Also update all anscestors, but no recursive call 00231 while(g > b + 1) // O(log^2(p)) 00232 { 00233 g = (int)floor(g / b); 00234 00235 // Update ancestor's group to what is missing to make it reach the level of group g. 00236 //int lvl = (int)floor(log(g) / log(b)); 00237 int lvl = (int)floor(log2(g)); 00238 mapping_time_t::iterator level_time = load.find(lvl); // O(log(log(p))) 00239 float time = level_time->second.first.find(g)->second; 00240 time = target_time - time; 00241 00242 if(time > 0) 00243 { 00244 //cerr << "[" << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << "] " << time << endl; 00245 update_group_time(g, time); // O(log(p)) 00246 } 00247 } 00248 00249 return target_time; 00250 #else 00251 return recursive_update_time(g, time_offset); 00252 #endif 00253 } 00254 00255 /* 00256 static float 00257 Wi(int task) 00258 { 00259 int return_Wi = (int)vector_Wi.find(task)->second; 00260 //cerr << "[" << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << "] Task: " << task << ", Wi = " << return_Wi << endl; 00261 return return_Wi; 00262 } 00263 */ 00264 00265 static float 00266 Tau(int task) 00267 { 00268 return vector_Tau.find(task)->second; 00269 } 00270 00271 static float 00272 wi(int task) 00273 { 00274 int return_wi = (int)vector_wi.find(task)->second; 00275 //cerr << "[" << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << "] Task: " << task << ", wi = " << return_wi << endl; 00276 return return_wi; 00277 } 00278 00279 static float 00280 e(int task, int p) 00281 { 00282 return matrix_e.find(task)->second.find(p)->second; 00283 } 00284 00285 static float 00286 work(int task, int p) 00287 { 00288 float return_work = Tau(task) / e(task, p); 00289 //cerr << "[" << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << "] Task: " << task << ", p = " << p << ", work = " << return_work << endl; 00290 return return_work; 00291 } 00292 00293 static float 00294 time(int task, int p) 00295 { 00296 float return_time = work(task, p) / (float)p; 00297 //cerr << "[" << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << "] Task: " << task << ", p = " << p << ", time = " << return_time << endl; 00298 return return_time; 00299 } 00300 00301 static int 00302 level(int p) 00303 { 00304 //return (int)(L - floor(log(p) / log(b))); 00305 return (int)(L - floor(log2(p))); 00306 } 00307 00308 #if LONGEST_TASK_FIRST 00309 // Needed tp compare two group_time_t elements in the set whose definition comes right after 00310 struct cmp_task : binary_function <int, int, bool> 00311 { 00312 bool 00313 operator()(const int& x, const int& y) const 00314 { 00315 #if LONGEST_WIDEST_TASK_FIRST 00316 if(time(x, wi(x)) == time(y, wi(y))) 00317 { 00318 #if LONGEST_WIDEST_LOWEST_TASK_FIRST 00319 if(wi(x) == wi(y)) 00320 { 00321 return x < y; 00322 } 00323 else 00324 { 00325 #endif 00326 return wi(x) > wi(y); 00327 #if LONGEST_WIDEST_LOWEST_TASK_FIRST 00328 } 00329 #endif 00330 } 00331 else 00332 { 00333 #endif 00334 return time(x, (int)wi(x)) > time(y, (int)wi(y)); 00335 #if LONGEST_WIDEST_TASK_FIRST 00336 } 00337 #endif 00338 } 00339 }; 00340 static multiset<int, cmp_task> ordered_tasks; 00341 #endif 00342 00343 static void 00344 parse() 00345 { 00346 schedule = mapping_t(); 00347 load = mapping_time_t(); 00348 vector_Wi = map<int, float>(); 00349 vector_Tau = map<int, float>(); 00350 vector_wi = map<int, float>(); 00351 matrix_e = MatrixType(); 00352 AmplInput data(AmplInput::floatHandlers()); 00353 00354 // Read all values 00355 n = (int)rec->find<Scalar<float> >("n")->getValue(); 00356 b = (int)rec->find<Scalar<float> >("b")->getValue(); 00357 p = (int)rec->find<Scalar<float> >("p")->getValue(); 00358 00359 vector_Wi = rec->find<Vector<int, float> >("Wi")->getValues(); 00360 vector_Tau = rec->find<Vector<int, float> >("Tau")->getValues(); 00361 vector_wi = rec->find<Vector<int, float> >("wi")->getValues(); 00362 00363 matrix_e = rec->find<Matrix<int, int, float> >("e")->getValues(); 00364 00365 // Compute other values from parameters 00366 L = (int)(log2(p)); 00367 00368 // Number of groups 00369 G = 2 * p - 1; 00370 00371 // Load of each p processors, initialized to 0 00372 for(int i = 0; i < L + 1; i++) 00373 { 00374 // typedef pair<map<group_t, run_t>, set<group_t, run_t> > level_time_t; 00375 // Inserting already sorted values, takes constant time each 00376 by_group_t by_group; 00377 by_time_t by_time; 00378 for(int j = (int)pow((double)b, (double)i); j < (int)pow((double)b, (double)i + 1); j++) 00379 { 00380 by_group.insert(group_time_t(j, 0)); 00381 by_time.insert(group_time_t(j, 0)); 00382 } 00383 load.insert(pair<int, level_time_t>(i, level_time_t(by_group, by_time))); 00384 } 00385 } 00386 00387 static const long long int nsec_in_sec = 1000000000; 00388 00389 static int 00390 timespec_subtract(struct timespec *result, struct timespec *x, struct timespec *y) 00391 { 00392 /* Perform the carry for the later subtraction by updating y. */ 00393 if (x->tv_nsec < y->tv_nsec) 00394 { 00395 int nsec = (y->tv_nsec - x->tv_nsec) / nsec_in_sec + 1; 00396 y->tv_nsec -= nsec_in_sec * nsec; 00397 y->tv_sec += nsec; 00398 } 00399 if (x->tv_nsec - y->tv_nsec > nsec_in_sec) 00400 { 00401 int nsec = (x->tv_nsec - y->tv_nsec) / nsec_in_sec; 00402 y->tv_nsec += nsec_in_sec * nsec; 00403 y->tv_sec -= nsec; 00404 } 00405 00406 /* Compute the time remaining to wait. tv_nsec is certainly positive. */ 00407 result->tv_sec = x->tv_sec - y->tv_sec; 00408 result->tv_nsec = x->tv_nsec - y->tv_nsec; 00409 00410 /* Return 1 if result is negative. */ 00411 return x->tv_sec < y->tv_sec; 00412 } 00413 00414 static float 00415 group_recursive_load(int g, int b, int p, float *group) 00416 { 00417 int i; 00418 float load, max_load = 0; 00419 00420 for(i = g * b; i < (g + 1) * b && i < 2 * p; i++) 00421 { 00422 load = group_recursive_load(i, b, p, group); 00423 if(load > max_load) max_load = load; 00424 } 00425 00426 return max_load + group[g - 1]; 00427 } 00428 00429 float 00430 mapping_quality(const pelib::Algebra &input) 00431 { 00432 float p = input.find<Scalar<float> >("p")->getValue(); 00433 float b = input.find<Scalar<float> >("b")->getValue(); 00434 map<int, float> tau = input.find<Vector<int, float> >("Tau")->getValues(); 00435 map<int, float> wi = input.find<Vector<int, float> >("wi")->getValues(); 00436 map<int, float> group = input.find<Vector<int, float> >("group")->getValues(); 00437 map<int, map<int, float> > e = input.find<Matrix<int, int, float> >("e")->getValues(); 00438 00439 float g = 2 * p - 1; 00440 float *group_load = (float*)calloc((size_t)g, sizeof(float)); 00441 00442 // Get all the tasks's parallel time, add them to group load 00443 for(map<int, float>::const_iterator i = tau.begin(); i != tau.end(); i++) 00444 { 00445 float load = (float)i->second / (float)wi[i->first] / e[i->first][(int)wi[i->first]]; 00446 group_load[(int)group[i->first] - 1] += load; 00447 } 00448 00449 float final_load = group_recursive_load(1, (int)b, (int)p, group_load); 00450 free(group_load); 00451 00452 return final_load; 00453 } 00454 00455 Algebra 00456 mapping_ltlg(const Algebra &record) 00457 { 00458 Algebra input = record; 00459 struct timespec start, stop, total_time; 00460 00461 rec = &input; 00462 parse(); 00463 00464 clock_gettime(CLOCK_MONOTONIC, &start); 00465 00466 // Start timer here 00467 #if LONGEST_TASK_FIRST 00468 ordered_tasks = multiset<int, cmp_task>(); 00469 for(int i = 0; i < n; i++) // O(n) 00470 { 00471 int task = i + 1; 00472 ordered_tasks.insert(task); // O(log n) 00473 } 00474 #endif 00475 00476 // Use a temporary vector to reduce asymptotic time with n 00477 vector<pair<int, float> > schedule_vector; 00478 //O(n log^2(p)) 00479 #if LONGEST_TASK_FIRST 00480 for(set<int>::iterator iter = ordered_tasks.begin(); iter != ordered_tasks.end(); iter++) 00481 #else 00482 for(int i = 0; i < n; i++) 00483 #endif 00484 { 00485 #if LONGEST_TASK_FIRST 00486 int task = *iter; 00487 #else 00488 int task = i + 1;; 00489 #endif 00490 float task_wi = wi(task); 00491 float task_time = time(task, (int)wi(task)); 00492 //cerr << "(" << task_time << ", " << task_wi << ")" << endl; 00493 00494 int task_level = level((int)task_wi); 00495 mapping_time_t::iterator level_queue = load.find(task_level); 00496 level_time_t level_time = level_queue->second; 00497 by_time_t group_queue = level_time.second; 00498 by_time_t::iterator group_queue_iter = group_queue.begin(); 00499 int group = group_queue_iter->first; 00500 // All the above in one line 00501 //int group = load.find(level(task_wi))->second.second.begin()->first; 00502 00503 schedule_vector.push_back(pair<int, int>(task, group)); // O(1) 00504 //cerr << "[" << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << "] " << task_time << endl; 00505 update_time(group, task_time); // O(log^2(p)) 00506 00507 for(by_time_t::iterator j = group_queue.begin(); j != group_queue.end(); j++) 00508 { 00509 //level_time_t level_time = level_queue->second; 00510 //cerr << "[" << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << "] group: " << j->first << "; time: " << level_queue->second.first.find(j->first)->second << endl; 00511 } 00512 } 00513 clock_gettime(CLOCK_MONOTONIC, &stop); 00514 00515 // Build the final schedule cppelib structure from schedule_vector 00516 // Outside time measurement 00517 for(vector<pair<int, float> >::iterator iter = schedule_vector.begin(); iter != schedule_vector.end(); iter++) 00518 { 00519 schedule.push_back(pair<int, int>(iter->first, (int)iter->second)); 00520 } 00521 00522 timespec_subtract(&total_time, &stop, &start); 00523 Scalar<float> param_time("_total_solve_elapsed_time", (total_time.tv_sec * nsec_in_sec + total_time.tv_nsec) / (float)nsec_in_sec); 00524 rec->insert(¶m_time); 00525 00526 // Make 00527 map<int, float> vector_group; 00528 bool all_sequential = true; 00529 for(mapping_t::iterator iter = schedule.begin(); iter != schedule.end(); iter++) 00530 { 00531 all_sequential = all_sequential && wi(iter->first) == 1; 00532 vector_group.insert(pair<int, int>(iter->first, iter->second)); 00533 } 00534 Vector<int, float> group("group", vector_group); 00535 rec->insert(&group); 00536 00537 Scalar<float> all_seq("all_sequential", (int)all_sequential); 00538 rec->insert(&all_seq); 00539 00540 return input; 00541 } 00542 00543 float 00544 mapping_ltlg_complexity(const pelib::Algebra &input) 00545 { 00546 float n = input.find<Scalar<float> >("n")->getValue(); 00547 float p = input.find<Scalar<float> >("p")->getValue(); 00548 00549 return n * (p * log(p) + log(p) * log(p)); 00550 }