crown  1.0.0
src/crown.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 <set>
00024 
00025 #include <cstdlib>
00026 
00027 #include <crown/allocation.h>
00028 #include <crown/mapping.h>
00029 #include <crown/scaling.h>
00030 #include <crown/annealing.h>
00031 #include <crown/crown.h>
00032 
00033 #include <pelib/AmplInput.hpp>
00034 #include <pelib/AmplOutput.hpp>
00035 #include <pelib/Vector.hpp>
00036 #include <pelib/Matrix.hpp>
00037 #include <pelib/Set.hpp>
00038 
00039 #ifdef debug
00040 #undef debug
00041 #endif
00042 
00043 #if 01
00044 #define debug(var) cout << "[" << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << "] " << #var << " = \"" << var << "\"" << endl;
00045 #else
00046 #define debug(var)
00047 #endif
00048 
00049 using namespace std;
00050 
00051 namespace pelib
00052 {
00053 namespace crown
00054 {
00055 
00056 // Quality assessment parameters
00057 const long long int nsec_in_sec = 1000000000;
00058 
00059 static int
00060 timespec_subtract(struct timespec *result, struct timespec *x, struct timespec *y)
00061 {
00062         /* Perform the carry for the later subtraction by updating y. */
00063         if (x->tv_nsec < y->tv_nsec)
00064         {
00065                 int nsec = (y->tv_nsec - x->tv_nsec) / nsec_in_sec + 1;
00066                 y->tv_nsec -= nsec_in_sec * nsec;
00067                 y->tv_sec += nsec;
00068         }
00069         if (x->tv_nsec - y->tv_nsec > nsec_in_sec)
00070         {
00071                 int nsec = (x->tv_nsec - y->tv_nsec) / nsec_in_sec;
00072                 y->tv_nsec += nsec_in_sec * nsec;
00073                 y->tv_sec -= nsec;
00074         }
00075      
00076         /* Compute the time remaining to wait. tv_nsec is certainly positive. */
00077         result->tv_sec = x->tv_sec - y->tv_sec;
00078         result->tv_nsec = x->tv_nsec - y->tv_nsec;
00079      
00080         /* Return 1 if result is negative. */
00081         return x->tv_sec < y->tv_sec;
00082 }
00083 
00084 // This is not valid if we consider swithing off unused cores
00085 #if RETURN_EARLY && 0
00086 #define return_now_if_best(solution) if(solution.find<Scalar<float> >("all_sequential")->getValue() == 1 && solution.find<Scalar<float> >("frequency_optimal")->getValue() == 1) return solution
00087 #else
00088 #define return_now_if_best(solution)
00089 #endif
00090 
00091 static Algebra
00092 crown_binary_quality(const Algebra &taskgraph, float (*quality)(const Algebra &solution), unsigned int precision)
00093 {
00094         Algebra schedule = taskgraph;
00095         float threshold = 0.5;
00096         float delta = 0.25;
00097         float derivative, min_derivative = 1;
00098         unsigned int round = 0;
00099         //int need_schedule = 1;
00100         float m = 0;
00101         Algebra current, best;
00102         float power = 0, best_power;
00103 
00104         // Compute allocation for maximal parallelization
00105         // This is is to get an allocation if nothing else works
00106         // Yet it is not guaranteed to produce a valid schedule
00107         // because of a still too high makespan presure
00108         best = schedule;
00109         
00110         best = allocation_fastest(best);
00111         best = mapping_ltlg(best);
00112         best = frequency_height(best);
00113         best_power = quality(best);
00114 
00115         //return_now_if_best(best);
00116 
00117         float emax = 0, emin = 1;
00118         float previous = 1;
00119         map<int, map<int, float> > map_e = schedule.find<Matrix<int, int, float> >("e")->getValues();
00120         map<int, float> map_Wi = schedule.find<Vector<int, float> >("Wi")->getValues();
00121         for(map<int, map<int, float> >::iterator row_iter = map_e.begin(); row_iter != map_e.end(); row_iter++)
00122         {
00123                 int task = row_iter->first;
00124                 int Wi = (int)map_Wi[task];
00125                 map<int, float> map_row = row_iter->second;
00126                                 
00127                 for(map<int, float>::iterator col_iter = map_row.begin(); col_iter != map_row.end() && col_iter->first <= Wi; col_iter++)
00128                 {
00129                         if(col_iter->second < 1)
00130                         {
00131                                 if(col_iter->second > emax)
00132                                 {
00133                                         emax = col_iter->second;
00134                                 }
00135 
00136                                 if(col_iter->second < emin)
00137                                 {
00138                                         emin = col_iter->second;
00139                                 }
00140 
00141                                 derivative = previous - col_iter->second;
00142                                 if(derivative < min_derivative)
00143                                 {
00144                                         min_derivative = derivative;
00145                                 }
00146                         }
00147                 }
00148         }
00149 
00150         // Binary search for maximal minimum efficiency for all tasks
00151         //bool threshold_ok = true;
00152         bool retry = true;
00153 
00154         // Try a whole sequential schedule
00155         current = schedule;
00156         current = allocation_gemin(current, 1);
00157         current = mapping_ltlg(current);
00158         current = frequency_height(current);
00159 
00160         //AmplOutput(AmplOutput::floatHandlers()).dump(cerr, current);
00161         //return_now_if_best(current);
00162                 
00163         // Check if this allocation could produce a valid mapping
00164         // m is the minimal slack time
00165         m = current.find<Scalar<float> >("m")->getValue();
00166         if(m > 0)
00167         {
00168                 power = quality(current);
00169                 if(power <= best_power)
00170                 {
00171                         best_power = power;
00172                         best = current;
00173                 }
00174         }
00175 
00176         // Loop while the current threshold is lower than the maximum non-sequential efficiency
00177         // and delta is higher than the minimal efficiency gap between two allocations for any task
00178         // And, if any maximum round was given, this threshold was not reached
00179         while(retry && delta * 2 > min_derivative && ((precision != 0 && round < precision) || precision == 0))
00180         {
00181                 // Reset the current solution to input
00182                 current = schedule;
00183 
00184                 // Allocate with current threshold then run mapping and frequency scaling
00185                 //cerr << "######################################" << endl;
00186                 //AmplInput().dump(cerr, current);
00187                 //cerr << endl;
00188                 
00189                 current = allocation_gemin(current, threshold);
00190                 
00191                 //AmplInput().dump(cerr, current);
00192                 
00193                 current = mapping_ltlg(current);
00194                 current = frequency_height(current);
00195 
00196                 //return_now_if_best(current);
00197                 
00198                 // Check if this allocation could produce a valid mapping
00199                 // m is the minimal slack time
00200                 m = current.find<Scalar<float> >("m")->getValue();
00201 
00202                 // Update the threshold after the feasibility
00203                 if(m > 0)
00204                 {
00205                         power = quality(current);
00206 #if SHOWPOWER
00207                         // Output the energy of current schedule
00208                         cout << "# Statistics: " << threshold << " " << power << endl;
00209 #endif
00210                         // This is a valid schedule
00211                         // Retry if current threshold is lower than maximal efficiency
00212                         retry = threshold < emax;
00213                         
00214                         // Increase threshold by delta
00215                         threshold = threshold + delta;
00216                 
00217                         // Keep this schedule as the best found so far
00218                         if(power < best_power)
00219                         {
00220                                 best = current;
00221                         }
00222                 }
00223                 else
00224                 {
00225                         // This was an invalid schedule
00226                         retry = true;
00227                         
00228                         // Allow lower efficiency
00229                         threshold = threshold - delta;                  
00230                 }
00231 
00232                 // Reduce the delta
00233                 delta = delta / 2;
00234 
00235                 // Count the number of rounds
00236                 round++;
00237         }
00238 
00239         Scalar<float> best_quality_scalar("quality", best_power);
00240         best.remove("best_quality");
00241         best.insert(&best_quality_scalar);
00242 
00243 /*
00244         Scalar<float> scalar_threshold = Scalar<float>("gemin", threshold);
00245         best.insert(&scalar_threshold);
00246         Scalar<float> scalar_gemax = Scalar<float>("gemax", emax);
00247         best.insert(&scalar_gemax);
00248 */
00249 
00250         // Compute and insert scheduling time
00251 /*
00252         Scalar<float> scalar_round = Scalar<float>("round", round);
00253         best.insert(&scalar_round);
00254 */
00255 
00256         return best;
00257 }
00258 
00259 Algebra
00260 crown_binary_simple(const Algebra &taskgraph, unsigned int precision)
00261 {
00262         return crown_binary_quality(taskgraph, quality_simple, precision);
00263 }
00264 
00265 Algebra
00266 crown_binary_idle(const Algebra &taskgraph, unsigned int precision)
00267 {
00268         return crown_binary_quality(taskgraph, quality_idle, precision);
00269 }
00270 
00271 Algebra
00272 crown_binary_off(const Algebra &taskgraph, unsigned int precision)
00273 {
00274         return crown_binary_quality(taskgraph, quality_off, precision);
00275 }
00276 
00277 Algebra
00278 crown_binary(const Algebra &taskgraph, unsigned int precision)
00279 {
00280         return crown_binary_quality(taskgraph, energy_static_dynamic_busy_idle_active, precision);
00281 }
00282 
00283 Algebra
00284 crown_binary_annealing_allocation(const Algebra &initial, float temperature, float cooling, float final, int max_transform, int max_new_state, float distance)
00285 {
00286         Algebra schedule = initial;
00287         Algebra best = schedule;
00288         // Compute an initial best solution     
00289         best = crown_binary(best, 0);
00290 
00291         return annealing(best, best, energy_static_dynamic_busy_idle_active, neighbor_allocation_tasks, temperature, cooling, final, max_transform, max_new_state, distance);
00292 }
00293 
00294 Algebra
00295 crown_annealing_allocation_idle(const Algebra &initial, float temperature, float cooling, float final, int max_transform, int max_new_state, float distance)
00296 {
00297         struct timespec start, stop, total_time;
00298         Algebra schedule = initial;
00299 
00300         Algebra best = schedule;
00301         clock_gettime(CLOCK_MONOTONIC, &start); 
00302         // Compute an initial best solution     
00303         best = allocation_fastest(best);
00304         best = mapping_ltlg(best);
00305         best = frequency_height(best);
00306 
00307         // Generate a random initial solution
00308         schedule = allocation_random(schedule);
00309         schedule = mapping_ltlg(schedule);
00310         schedule = frequency_height(schedule);
00311 
00312         schedule = annealing(schedule, best, quality_idle, neighbor_allocation_full, temperature, cooling, final, max_transform, max_new_state, distance);
00313         clock_gettime(CLOCK_MONOTONIC, &stop);
00314         
00315         timespec_subtract(&total_time, &stop, &start);
00316         Scalar<float> param_time("_total_solve_elapsed_time", (float)(total_time.tv_sec * nsec_in_sec + total_time.tv_nsec) / (float)nsec_in_sec);
00317         schedule.insert(&param_time);
00318 
00319         return schedule;
00320 }
00321 
00322 Algebra
00323 crown_annealing_allocation_off(const Algebra &initial, float temperature, float cooling, float final, int max_transform, int max_new_state, float distance)
00324 {
00325         struct timespec start, stop, total_time;
00326         Algebra schedule = initial;
00327 
00328         Algebra best = schedule;
00329         clock_gettime(CLOCK_MONOTONIC, &start); 
00330         // Compute an initial best solution     
00331         best = allocation_fastest(best);
00332         best = mapping_ltlg(best);
00333         best = frequency_height(best);
00334 
00335         // Generate a random initial solution
00336         schedule = allocation_random(schedule);
00337         schedule = mapping_ltlg(schedule);
00338         schedule = frequency_height(schedule);
00339 
00340         schedule = annealing(schedule, best, quality_off, neighbor_allocation_full, temperature, cooling, final, max_transform, max_new_state, distance);
00341         clock_gettime(CLOCK_MONOTONIC, &stop);
00342         
00343         timespec_subtract(&total_time, &stop, &start);
00344         Scalar<float> param_time("_total_solve_elapsed_time", (float)(total_time.tv_sec * nsec_in_sec + total_time.tv_nsec) / (float)nsec_in_sec);
00345         schedule.insert(&param_time);
00346 
00347         return schedule;
00348 }
00349 
00350 Algebra
00351 crown_annealing_allocation_simple(const Algebra &initial, float temperature, float cooling, float final, int max_transform, int max_new_state, float distance)
00352 {
00353         struct timespec start, stop, total_time;
00354         Algebra schedule = initial;
00355         Algebra best = schedule;
00356 
00357         clock_gettime(CLOCK_MONOTONIC, &start); 
00358 
00359         // Compute an initial best solution     
00360         best = allocation_fastest(best);
00361         best = mapping_ltlg(best);
00362         best = frequency_height(best);
00363 
00364         // Generate a random initial solution
00365         schedule = allocation_random(schedule);
00366         schedule = mapping_ltlg(schedule);
00367         schedule = frequency_height(schedule);
00368 
00369         schedule = annealing(schedule, best, quality_simple, neighbor_allocation_full, temperature, cooling, final, max_transform, max_new_state, distance);
00370         clock_gettime(CLOCK_MONOTONIC, &stop);
00371         
00372         timespec_subtract(&total_time, &stop, &start);
00373         Scalar<float> param_time("_total_solve_elapsed_time", (float)(total_time.tv_sec * nsec_in_sec + total_time.tv_nsec) / (float)nsec_in_sec);
00374         schedule.insert(&param_time);
00375 
00376         return schedule;
00377 }
00378 
00379 Algebra
00380 crown_binary_annealing_allocation_idle(const Algebra &initial, float temperature, float cooling, float final, int max_transform, int max_new_state, float distance)
00381 {
00382         struct timespec start, stop, total_time;
00383         Algebra schedule = initial;
00384 
00385         Algebra best = schedule;
00386         clock_gettime(CLOCK_MONOTONIC, &start); 
00387         // Compute an initial best solution     
00388         best = crown_binary_idle(best, 0);
00389 
00390         schedule = annealing(best, best, quality_idle, neighbor_allocation_tasks, temperature, cooling, final, max_transform, max_new_state, distance);
00391         clock_gettime(CLOCK_MONOTONIC, &stop);
00392         
00393         timespec_subtract(&total_time, &stop, &start);
00394         Scalar<float> param_time("_total_solve_elapsed_time", (float)(total_time.tv_sec * nsec_in_sec + total_time.tv_nsec) / (float)nsec_in_sec);
00395         schedule.insert(&param_time);
00396 
00397         return schedule;
00398 }
00399 
00400 Algebra
00401 crown_binary_annealing_allocation_off(const Algebra &initial, float temperature, float cooling, float final, int max_transform, int max_new_state, float distance)
00402 {
00403         struct timespec start, stop, total_time;
00404         Algebra schedule = initial;
00405 
00406         Algebra best = schedule;
00407         clock_gettime(CLOCK_MONOTONIC, &start); 
00408         // Compute an initial best solution     
00409         best = crown_binary_off(best, 0);
00410 
00411         schedule = annealing(best, best, quality_off, neighbor_allocation_tasks, temperature, cooling, final, max_transform, max_new_state, distance);
00412         clock_gettime(CLOCK_MONOTONIC, &stop);
00413         
00414         timespec_subtract(&total_time, &stop, &start);
00415         Scalar<float> param_time("_total_solve_elapsed_time", (float)(total_time.tv_sec * nsec_in_sec + total_time.tv_nsec) / (float)nsec_in_sec);
00416         schedule.insert(&param_time);
00417 
00418         return schedule;
00419 }
00420 
00421 Algebra
00422 crown_binary_annealing_allocation_simple(const Algebra &initial, float temperature, float cooling, float final, int max_transform, int max_new_state, float distance)
00423 {
00424         struct timespec start, stop, total_time;
00425         Algebra schedule = initial;
00426 
00427         Algebra best = schedule;
00428         clock_gettime(CLOCK_MONOTONIC, &start); 
00429         // Compute an initial best solution     
00430         best = crown_binary_simple(best, 0);
00431 
00432         schedule = annealing(best, best, quality_simple, neighbor_allocation_full, temperature, cooling, final, max_transform, max_new_state, distance);
00433         clock_gettime(CLOCK_MONOTONIC, &stop);
00434         
00435         timespec_subtract(&total_time, &stop, &start);
00436         Scalar<float> param_time("_total_solve_elapsed_time", (float)(total_time.tv_sec * nsec_in_sec + total_time.tv_nsec) / (float)nsec_in_sec);
00437         schedule.insert(&param_time);
00438 
00439         return schedule;
00440 }
00441 
00442 static Algebra
00443 add_extreme_e(const Algebra &schedule)
00444 {
00445         float emax = 0, emin = 1;
00446         //float previous = 1;
00447         map<int, map<int, float> > map_e = schedule.find<Matrix<int, int, float> >("e")->getValues();
00448         map<int, float> map_Wi = schedule.find<Vector<int, float> >("Wi")->getValues();
00449         for(map<int, map<int, float> >::iterator row_iter = map_e.begin(); row_iter != map_e.end(); row_iter++)
00450         {
00451                 int task = row_iter->first;
00452                 int Wi = (int)map_Wi[task];
00453                 map<int, float> map_row = row_iter->second;
00454                                 
00455                 for(map<int, float>::iterator col_iter = map_row.begin(); col_iter != map_row.end() && col_iter->first <= Wi; col_iter++)
00456                 {
00457                         if(col_iter->second < 1)
00458                         {
00459                                 if(col_iter->second > emax)
00460                                 {
00461                                         emax = col_iter->second;
00462                                 }
00463 
00464                                 if(col_iter->second < emin)
00465                                 {
00466                                         emin = col_iter->second;
00467                                 }
00468                         }
00469                 }
00470         }
00471 
00472         Algebra input = schedule;
00473         Scalar<float> scalar_threshold = Scalar<float>("gemin", emin);
00474         input.insert(&scalar_threshold);
00475         Scalar<float> scalar_gemax = Scalar<float>("gemax", emax);
00476         input.insert(&scalar_gemax);
00477 
00478         return input;
00479 }
00480 
00481 Algebra
00482 crown_binary_annealing_efficiency_simple(const Algebra &schedule, float temperature, float cooling, float final, int max_transform, int max_new_state, float distance)
00483 {
00484         struct timespec start, stop, total_time;
00485 
00486         Algebra initial, best;
00487         clock_gettime(CLOCK_MONOTONIC, &start);
00488         
00489         // Compute an initial solution  
00490         initial = add_extreme_e(schedule);
00491         float gemin = initial.find<Scalar<float> >("gemin")->getValue();
00492         float gemax = initial.find<Scalar<float> >("gemax")->getValue();
00493         float random = (float)rand() / RAND_MAX;
00494         initial = allocation_gemin(initial, gemin + random * (gemax - gemin));
00495         initial = mapping_ltlg(initial);
00496         initial = frequency_height(initial);
00497 
00498         // Compute an initial best solution
00499         best = allocation_fastest(schedule);
00500         best = mapping_ltlg(best);
00501         best = frequency_height(best);
00502 
00503         best = annealing(initial, best, quality_simple, neighbor_efficiency, temperature, cooling, final, max_transform, max_new_state, distance);
00504         clock_gettime(CLOCK_MONOTONIC, &stop);
00505         
00506         timespec_subtract(&total_time, &stop, &start);
00507         Scalar<float> param_time("_total_solve_elapsed_time", (float)(total_time.tv_sec * nsec_in_sec + total_time.tv_nsec) / (float)nsec_in_sec);
00508         best.insert(&param_time);
00509 
00510         return best;
00511 }
00512 
00513 Algebra
00514 crown_binary_annealing_efficiency_idle(const Algebra &schedule, float temperature, float cooling, float final, int max_transform, int max_new_state, float distance)
00515 {
00516         struct timespec start, stop, total_time;
00517 
00518         Algebra initial, best;
00519         clock_gettime(CLOCK_MONOTONIC, &start);
00520         
00521         // Compute an initial solution  
00522         initial = add_extreme_e(schedule);
00523         float gemin = initial.find<Scalar<float> >("gemin")->getValue();
00524         float gemax = initial.find<Scalar<float> >("gemax")->getValue();
00525         float random = (float)rand() / RAND_MAX;
00526         initial = allocation_gemin(initial, gemin + random * (gemax - gemin));
00527         initial = mapping_ltlg(initial);
00528         initial = frequency_height(initial);
00529 
00530         // Compute an initial best solution
00531         best = allocation_fastest(schedule);
00532         best = mapping_ltlg(best);
00533         best = frequency_height(best);
00534 
00535         best = annealing(initial, best, quality_idle, neighbor_efficiency, temperature, cooling, final, max_transform, max_new_state, distance);
00536         clock_gettime(CLOCK_MONOTONIC, &stop);
00537         
00538         timespec_subtract(&total_time, &stop, &start);
00539         Scalar<float> param_time("_total_solve_elapsed_time", (float)(total_time.tv_sec * nsec_in_sec + total_time.tv_nsec) / (float)nsec_in_sec);
00540         best.insert(&param_time);
00541 
00542         return best;
00543 }
00544 
00545 Algebra
00546 crown_binary_annealing_efficiency_off(const Algebra &schedule, float temperature, float cooling, float final, int max_transform, int max_new_state, float distance)
00547 {
00548         struct timespec start, stop, total_time;
00549 
00550         Algebra initial, best;
00551         clock_gettime(CLOCK_MONOTONIC, &start);
00552         
00553         // Compute an initial solution  
00554         initial = add_extreme_e(schedule);
00555         float gemin = initial.find<Scalar<float> >("gemin")->getValue();
00556         float gemax = initial.find<Scalar<float> >("gemax")->getValue();
00557         float random = (float)rand() / RAND_MAX;
00558         initial = allocation_gemin(initial, gemin + random * (gemax - gemin));
00559         initial = mapping_ltlg(initial);
00560         initial = frequency_height(initial);
00561 
00562         // Compute an initial best solution
00563         best = allocation_fastest(schedule);
00564         best = mapping_ltlg(best);
00565         best = frequency_height(best);
00566 
00567         best = annealing(initial, best, quality_off, neighbor_efficiency, temperature, cooling, final, max_transform, max_new_state, distance);
00568         clock_gettime(CLOCK_MONOTONIC, &stop);
00569         
00570         timespec_subtract(&total_time, &stop, &start);
00571         Scalar<float> param_time("_total_solve_elapsed_time", (float)(total_time.tv_sec * nsec_in_sec + total_time.tv_nsec) / (float)nsec_in_sec);
00572         best.insert(&param_time);
00573 
00574         return best;
00575 }
00576 
00577 float
00578 crown_binary_complexity(const Algebra &schedule, unsigned int precision)
00579 {
00580         if(precision > 0)
00581         {
00582                 return precision;
00583         }
00584         else
00585         {
00586                 float emax = 0, emin = 1;
00587                 float previous = 1;
00588                 float derivative, min_derivative = 0.25;
00589                 map<int, map<int, float> > map_e = schedule.find<Matrix<int, int, float> >("e")->getValues();
00590                 map<int, float> map_Wi = schedule.find<Vector<int, float> >("Wi")->getValues();
00591                 
00592                 for(map<int, map<int, float> >::iterator row_iter = map_e.begin(); row_iter != map_e.end(); row_iter++)
00593                 {
00594                         int task = row_iter->first;
00595                         int Wi = (int)map_Wi[task];
00596                         map<int, float> map_row = row_iter->second;
00597                         
00598                         for(map<int, float>::iterator col_iter = map_row.begin(); col_iter != map_row.end() && col_iter->first <= Wi; col_iter++)
00599                         {
00600                                 if(col_iter->first > 1)
00601                                 {
00602                                         if(col_iter->second > emax)
00603                                         {
00604                                                 emax = col_iter->second;
00605                                         }
00606 
00607                                         if(col_iter->second < emin)
00608                                         {
00609                                                 emin = col_iter->second;
00610                                         }
00611 
00612                                         derivative = previous - col_iter->second;
00613                                         //cerr << "derivative = " << derivative << endl;
00614                                         previous = col_iter->second;
00615                                         if(derivative < min_derivative)
00616                                         {
00617                                                 min_derivative = derivative;
00618                                                 //cerr << "min_derivative = " << min_derivative << endl;
00619                                         }
00620                                         //cerr << "previous = " << previous << endl;
00621                                 }
00622                                 else
00623                                 {
00624                                         previous = col_iter->second; // ... which should be always 1.
00625                                         //min_derivative = 0.25; // If a task is sequential, then the complexity will be 1.
00626                                         //cerr << "min_derivative = " << min_derivative << endl;
00627                                 }
00628                         }
00629                 }
00630 
00631                 //cerr << "min_derivative = " << min_derivative << endl;
00632                 //cerr << ceil(log2 (0.5 / min_derivative)) << endl;
00633                 return ceil(log2 (0.5 / min_derivative));
00634         }
00635 }
00636 
00637 }
00638 }