crown  1.0.0
src/mapping.cpp
Go to the documentation of this file.
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(&param_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 }