crown  1.0.0
src/frequency.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 #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(&param_time);
00310 
00311         Scalar<float> param_optimal("frequency_optimal", (int)optimal);
00312         schedule.insert(&param_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(&ampl_frequency);
00331         
00332         Scalar<float> ampl_m("m", M - height[1]);
00333         schedule.insert(&ampl_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 }