schedulers  1.0.0
src/PruhsHeuristic.cpp
Go to the documentation of this file.
00001 // The following definitions might be exchanged for others,
00002 // when integrating the following code into the framework.
00003 // The code implements a greedy heuristic to loadbalance the tasks
00004 // over cores such that the l2-norm of the load vector is minimized.
00005 // This should also minimize the l3-norm of the load vector.
00006 // J. Keller, July 14, 2014
00007 
00008 #include <stdio.h>
00009 #include <stdlib.h>
00010 #include <string.h>
00011 #include <math.h>
00012 
00013 #include <string>
00014 #include <iostream>
00015 #if DUMMY == 0
00016 #include <pelib/PruhsHeuristic.hpp>
00017 #include <pelib/AmplSolver.hpp>
00018 #include <pelib/Schedule.hpp>
00019 #include <pelib/Scalar.hpp>
00020 #include <pelib/Vector.hpp>
00021 #include <pelib/Matrix.hpp>
00022 #include <pelib/Set.hpp>
00023 #include <pelib/Task.hpp>
00024 #include <pelib/Taskgraph.hpp>
00025 #include <pelib/Platform.hpp>
00026 #include <pelib/CastException.hpp>
00027 #include <pelib/ParseException.hpp>
00028 #include <pelib/AmplOutput.hpp>
00029 #include <pelib/PelibException.hpp>
00030 
00031 #endif
00032 
00033 #define debug(var) cout << "[" << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << "] " << #var << " = \"" << (var) << "\"" << endl;
00034 #define LEN 50
00035 
00036 using namespace std;
00037 
00038 typedef struct task{
00039 int idnumber;
00040 double work;
00041 char name[LEN];
00042 } Task;
00043 
00044 typedef struct taskset{
00045 int number;
00046 int maxnumber;
00047 char name[LEN];
00048 Task **list;
00049 } Taskset;
00050 
00051 typedef struct taskparams{
00052 Task *ptr;
00053 double frequency;
00054 double start;
00055 } Taskparams;
00056 
00057 typedef struct schedule{
00058 double makespan; // makespan to be reached
00059 int corecount; // number of cores
00060 Taskset *ts; // taskset that schedule refers to
00061 char name[LEN];
00062 double *loadpercore; // sums up the loads of the tasks mapped to each core
00063 int *taskspercore; // array of how many tasks are mapped to each core
00064 Taskparams *list; // 2-dim array of size corecount*tasksetsize where element [i*tasksetsize+j] points to j-th task on core i
00065 } Schedule;
00066 
00067 // alpha used in greedy mapping, not used for energy computation!
00068 // ALPHA 0.0 is used for mapping to core with minimum current load
00069 #define ALPHA 0
00070 
00071 // Max frequency
00072 double max_frequency;
00073 double *discrete_frequencies_relative;
00074 size_t number_of_frequencies;
00075 
00076 /*
00077 // JK: added following declarations
00078 #define NUMBEROFFREQUENCIES 5
00079 
00080 // frequencies as fractions of max_frequency, in ascending order
00081 // i.e. last frequency is 1.0
00082 double discrete_frequencies_relative[NUMBEROFFREQUENCIES]={0.2,0.4,0.6,0.8,1.0};
00083 
00084 #define max_frequency 100.0
00085 */
00086 
00087 
00088 //void readtaskset(Taskset *ts,double *Mptr,int *pptr, char*, char*);
00089 
00090 // give the workload of a task
00091 // requires details of task implementation
00092 static
00093 double taskload(Task *t) { return t->work; }
00094 
00095 // init a taskset (given the number of tasks)
00096 // note: does not set the number of tasks
00097 // requires detail of Taskset implementation
00098 static
00099 void inittaskset(Taskset *ts,int n,char *name)
00100 { 
00101   ts->number = 0;
00102   ts->maxnumber = n;
00103   strcpy(ts->name,name);
00104   ts->list = (Task**)malloc(sizeof(Task*)*n);
00105 }
00106 
00107 // add a task to a taskset
00108 // requires detail of Task and Taskset implementation
00109 static
00110 void addtasktotaskset(Taskset *ts,int id,double work,char *name)
00111 {
00112   ts->list[ts->number]=(Task*)malloc(sizeof(Task));
00113   ts->list[ts->number]->idnumber=id;
00114   ts->list[ts->number]->work=work;
00115   strcpy(ts->list[ts->number]->name,name);
00116   ts->number++;
00117 }
00118 
00119 // deinit a taskset
00120 // note: does not free the memory for tasks
00121 // requires detail of Taskset implementation
00122 static
00123 void deinittaskset(Taskset *ts)
00124 {
00125   free(ts->list);
00126 }
00127 
00128 // copy a taskset: requires details of taskset implementation
00129 // does not copy the tasks themselves, only the pointers to the tasks
00130 // includes a taskset initialization, i.e. if taskset trg has been initialized before, it should be deinited first
00131 static
00132 void copytaskset(Taskset *trg,Taskset *src,char *name)
00133 { int i;
00134 
00135   inittaskset(trg,src->number,name);
00136   trg->number = src->number;
00137   for(i=0;i<trg->number;i++) *((trg->list)+i) = *((src->list)+i);
00138 }
00139 
00140 static
00141 #if DUMMY == 0
00142 void readtaskset(Taskset *ts, double *Mptr, int *pptr, const pelib::Taskgraph &tg, const pelib::Platform &arch)
00143 {
00144   using namespace std;
00145   using namespace pelib;
00146 
00147   int taskcount = tg.getTasks().size();
00148   inittaskset(ts,taskcount, (char*) tg.getName().c_str());
00149 
00150   for(set<pelib::Task>::const_iterator i = tg.getTasks().begin(); i != tg.getTasks().end(); i++)
00151   {
00152         int id = std::distance(tg.getTasks().begin(), i) + 1;
00153     addtasktotaskset(ts, id, i->getWorkload(), (char*) i->getName().c_str());
00154   }
00155 
00156   *Mptr = tg.getDeadline(arch); // makespan
00157   *pptr = arch.getCores().size(); // no. of cores
00158 
00159   set<float> frequencies = (*arch.getCores().begin())->getFrequencies();
00160   number_of_frequencies = frequencies.size();
00161   max_frequency = *frequencies.rbegin();
00162   
00163   discrete_frequencies_relative = (double*)malloc(sizeof(double) * number_of_frequencies);
00164   int i = 0;
00165   for(set<float>::iterator iter = frequencies.begin(); iter != frequencies.end(); iter++)
00166   {
00167     discrete_frequencies_relative[i] = *iter / max_frequency;
00168     i++;
00169   }
00170 }
00171 #else
00172 void readtaskset(Taskset *ts, double *Mptr, int *pptr)
00173 {
00174   *Mptr = 10; // makespan
00175   int taskcount = 10;
00176   inittaskset(ts,taskcount, (char*) std::string("taskset as read in").c_str());
00177   addtasktotaskset(ts,0,10.0, (char*) std::string("task 0").c_str());
00178   addtasktotaskset(ts,1,11.0, (char*) std::string("task 1").c_str());
00179   addtasktotaskset(ts,2,12.0, (char*) std::string("task 3").c_str());
00180   addtasktotaskset(ts,3,13.0, (char*) std::string("task 3").c_str());
00181   addtasktotaskset(ts,4,14.0, (char*) std::string("task 4").c_str());
00182   addtasktotaskset(ts,5,15.0, (char*) std::string("task 5").c_str());
00183   addtasktotaskset(ts,6,16.0, (char*) std::string("task 6").c_str());
00184   addtasktotaskset(ts,7,17.0, (char*) std::string("task 7").c_str());
00185   addtasktotaskset(ts,8,18.0, (char*) std::string("task 8").c_str());
00186   addtasktotaskset(ts,9,19.0, (char*) std::string("task 9").c_str());
00187 
00188   number_of_frequencies = 5;
00189   discrete_frequencies_relative = (double*)malloc(sizeof(double) * number_of_frequencies);
00190   discrete_frequencies_relative[0] = 0.2;
00191   discrete_frequencies_relative[1] = 0.4;
00192   discrete_frequencies_relative[2] = 0.6;
00193   discrete_frequencies_relative[3] = 0.8;
00194   discrete_frequencies_relative[4] = 1.0;
00195   max_frequency = 100;
00196 
00197   *Mptr = 50.0; // makespan
00198   *pptr = 4; // no. of cores
00199 }
00200 #endif
00201 
00202 // return the name string of a taskset
00203 // requires detail of Taskset implementation
00204 static
00205 char *tasksetname(Taskset *ts) { return ts->name; }
00206 
00207 // give number of tasks in taskset
00208 // requires details of taskset implementation
00209 static
00210 int tssize(Taskset *ts) { return ts->number; }
00211 
00212 // return pointer to i-th task of a taskset
00213 // requires details of taskset implementation
00214 static
00215 Task *gettask(Taskset *ts,int i) { return ts->list[i]; }
00216 
00217 #if DUMMY != 0
00218 // print a task
00219 // requires detail of task implementation
00220 static
00221 void printtask(std::ostream &out, Task *t)
00222 {
00223         out << "## Task " << t->idnumber << " <" << t->name << "> work " << t->work << std::endl;
00224 }
00225 
00226 // print a taskset
00227 // requires detail of taskset implementation
00228 static
00229 void printtaskset(std::ostream &out, Taskset *ts)
00230 { int i;
00231 
00232   out << "## Taskset <" << ts->name << std::endl;
00233   for(i=0;i<tssize(ts);i++) printtask(out, ts->list[i]);
00234 }
00235 
00236 // print a taskparams
00237 // requires detail of taskparams implementation
00238 static
00239 void printtaskparams(std::ostream &out, Taskparams *tp)
00240 {
00241    out << "## Starttime: " << tp->start << " Frequency " << tp->frequency << " of" << std::endl;
00242    printtask(out, tp->ptr);
00243 }
00244 #endif
00245 
00246 // Finds the makespan of a schedule
00247 static
00248 double schedule_makespan(Schedule *sched, float frequency = 0)
00249 {
00250   int i, j;
00251   float makespan = 0;
00252 
00253   for(i = 0; i < sched->corecount; i++)
00254   {
00255     float start_time = 0;
00256     for(j = 0; j < sched->taskspercore[i]; j++)
00257     {
00258       Taskparams *tp = &(sched->list[i*tssize(sched->ts)+j]);
00259       float workload = (float)tp->ptr->work;
00260       float freq = frequency == 0 ? (float)tp->frequency : frequency;
00261       float end_time = start_time + workload / freq;
00262       start_time = end_time;
00263 
00264       //std::cerr << "[" << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << "] " << "start_time = " << start_time << ", workload = " << workload << ", freq = " << freq << ", end_time = " << end_time << std::endl;
00265 
00266       if(end_time > makespan)
00267       {
00268         makespan = end_time;
00269       }
00270     }
00271   }
00272 
00273   return makespan;
00274 }
00275 
00276 // print a schedule
00277 // requires detail of schedule implementation
00278 static
00279 #if DUMMY == 0
00280 pelib::Schedule buildSchedule(Schedule *sched)
00281 #else
00282 void printschedule(std::ostream &out, Schedule *sched)
00283 #endif
00284 {
00285 #if DUMMY == 0
00286   using namespace std;
00287 
00288   int i, j;
00289   vector<pelib::Task> tasks;
00290   
00291   // Count the number of tasks and reserve the necessary amount
00292   // to prevent C++ from copying task instances inside, making
00293   // pointers inserted in schedules to become invalid
00294   size_t num = 0;
00295   for(i = 0; i < sched->corecount; i++)
00296   {
00297     for(j = 0; j < sched->taskspercore[i]; j++)
00298     {
00299        num++;
00300     }
00301   }
00302   tasks.reserve(num);
00303 
00304   std::map<int, std::map<float, pair<const pelib::Task*, double> > > schedule;
00305   for(i = 0; i < sched->corecount; i++)
00306   {
00307     map<float, pair<const pelib::Task*, double> > core_schedule;
00308 
00309     for(j = 0; j < sched->taskspercore[i]; j++)
00310     {
00311       Taskparams *tp = &(sched->list[i*tssize(sched->ts)+j]);
00312       pelib::Task task(string(tp->ptr->name));
00313       tasks.push_back(task);
00314       pelib::Task &t = tasks[tasks.size() - 1];
00315       t.setFrequency(tp->frequency);
00316       t.setWidth(1);
00317       t.setWorkload(tp->ptr->work);
00318       t.setStartTime((float)tp->start);
00319 
00320       core_schedule.insert(pair<float, pair<const pelib::Task*, double> >((float)tp->start, pair<const pelib::Task*, double>(&t, t.getWorkload())));
00321     }
00322 
00323     schedule.insert(pair<int, map<float, pair<const pelib::Task*, double> > >(i + 1, core_schedule));
00324   }
00325 
00326   //psched.setSchedule(schedule);
00327   pelib::Schedule psched(string("Pruhs Heuristic"), tasksetname(sched->ts), schedule);
00328   
00329   //psched.setRoundTime(sched->makespan);
00330 
00331   return psched;
00332 #else
00333   int i,j;
00334 
00335   out << "## Schedule <" << sched->name << "> of taskset <" << tasksetname(sched->ts) << "> on " << sched->corecount << "cores with makespan " << sched->makespan << std::endl;
00336 
00337   for(i=0;i<sched->corecount;i++)
00338   {
00339     out << "## Schedule for core " << i << std::endl;
00340     for(j=0;j<sched->taskspercore[i];j++)
00341     {
00342       printtaskparams(out, &(sched->list[i*tssize(sched->ts)+j]));
00343     }
00344   }
00345 #endif
00346 }
00347 
00348 // compare Tasks according to work, so that they are in descending order
00349 // requires details of task implementation
00350 static
00351 int comparetasks(const void *t1,const void *t2)
00352 { Task *tp1, *tp2;
00353 
00354   tp1 = *((Task**)t1);
00355   tp2 = *((Task**)t2);
00356   if(tp1->work>tp2->work) return -1;
00357   if(tp1->work<tp2->work) return 1;
00358   return 0;
00359 }
00360 
00361 // sort the tasks of a taskset in descending order.
00362 // requires details of Taskset implementation
00363 static
00364 void sorttaskset(Taskset *ts)
00365 {
00366   qsort(ts->list,ts->number,sizeof(Task*),comparetasks);
00367 }
00368 
00369 // init the schedule
00370 // requires detail of Schedule implementation
00371 static
00372 void initschedule(Schedule *sched,Taskset *ts,double makespan,int corecount,char *name)
00373 { int i;
00374 
00375   sched->makespan = makespan;
00376   sched->corecount = corecount;
00377   sched->ts = ts;
00378   strcpy(sched->name,name);
00379   sched->loadpercore = (double*)malloc(sizeof(double)*corecount);
00380   for(i=0;i<corecount;i++) sched->loadpercore[i]=0.0;
00381   sched->taskspercore = (int*)malloc(sizeof(int)*corecount);
00382   for(i=0;i<corecount;i++) sched->taskspercore[i]=0;
00383   sched->list = (Taskparams*)malloc(sizeof(Taskparams)*corecount*tssize(ts));
00384 }
00385 
00386 // deinit a schedule
00387 // requires detail of schedule implementation
00388 static
00389 void deinitschedule(Schedule *sched)
00390 {
00391   free(sched->loadpercore);
00392   free(sched->taskspercore);
00393   free(sched->list);
00394 }
00395 
00396 // add a task to a Taskparam entry of a schedule
00397 // requires detail of taskparams implementation
00398 static
00399 void addtasktoparams(Taskparams *tp,Task *t) { tp->ptr=t; }
00400 
00401 // set the frequency in a Taskparam entry of a schedule
00402 // requires detail of taskparams implementation
00403 static
00404 void setfreqparams(Taskparams *tp,double freq) { tp->frequency=freq; }
00405 
00406 // set the starttime in a Taskparam entry of a schedule
00407 // return the endtime, implicitly assuming continuous frequencies
00408 // requires that the frequency in the Taskparam entry is already set
00409 // requires detail of taskparams implementation
00410 static
00411 double setstarttimeparams(Taskparams *tp,double time)
00412 { 
00413   tp->start=time;
00414   return time+taskload(tp->ptr)/(tp->frequency);
00415 }
00416 
00417 // JK: new routine
00418 // get pointer to task in taskparams
00419 // requires detail of taskparams implementation
00420 static
00421 Task *gettaskfromtaskparams(Taskparams *tp) { return tp->ptr; }
00422 
00423 // JK: new routine
00424 // copy a taskparams struct
00425 // requires detail of taskparams implementation
00426 static
00427 void copytaskparams(Taskparams *trg,Taskparams *src)
00428 {
00429     trg->ptr=src->ptr;
00430     trg->frequency=src->frequency;
00431     trg->start=src->start;
00432 }
00433 
00434 // JK: new routine
00435 // copy a schedule, with provision of a new name
00436 // requires detail of schedule implementation
00437 static
00438 void copyschedule(Schedule *trg,Schedule *src,char *newname)
00439 { int i;
00440     
00441   initschedule(trg,src->ts,src->makespan,src->corecount,newname);
00442 
00443   for(i=0;i<src->corecount;i++){
00444     trg->loadpercore[i]=src->loadpercore[i];
00445     trg->taskspercore[i]=src->taskspercore[i];
00446   }
00447 
00448   for(i=0;i<(src->corecount)*tssize(src->ts);i++){
00449     copytaskparams(&(trg->list[i]),&(src->list[i]));
00450   }    
00451 }
00452 
00453 // huge double number, larger than any load...
00454 #define MAX_DOUBLE pow(2.0,1000)
00455 
00456 // map a task into a schedule: greedy, i.e. search core with minimum
00457 // increase when considering ALPHA-power
00458 // requires detail of schedule implementation
00459 static
00460 void map(Task *t,Schedule *sched)
00461 { int i;
00462   int minarg=-1;
00463   double minincrease=MAX_DOUBLE;
00464   double increase;
00465   Taskparams *tp;
00466   int index;
00467 
00468   // find core with minimum increase
00469   for(i=0;i<sched->corecount;i++){
00470     if(ALPHA == 0.0)
00471       increase = sched->loadpercore[i];
00472     else
00473       increase = pow(sched->loadpercore[i] + taskload(t), ALPHA) - pow(sched->loadpercore[i], ALPHA);
00474     if(increase<minincrease) { minincrease=increase; minarg=i; }
00475   }
00476   // increase the load of that core
00477   sched->loadpercore[minarg] += taskload(t);
00478   // link the task
00479   index = minarg * (tssize(sched->ts))+(sched->taskspercore[minarg]);
00480   tp = &(sched->list[index]);
00481   addtasktoparams(tp,t);
00482   // increase number of tasks for that core
00483   sched->taskspercore[minarg]++;
00484 }
00485 
00486 // JK: adapted routine
00487 // scale the frequencies of the task(params) of a schedule such that the deadline is met.
00488 // all the tasks on one core have same frequency: sum-of-workloads/deadline
00489 // set the starttimes of the tasks accordingly
00490 // return 0 if all frequencies <= max_frequency, else return 1 as schedule is not feasible
00491 // requires detail of schedule implementation
00492 static
00493 int scalefrequencies(Schedule *sched)
00494 { int i,j;
00495   double freq;
00496   double time;
00497   int flag=0;
00498 
00499   for(i=0;i<sched->corecount;i++){
00500     time=0.0;
00501     freq=sched->loadpercore[i]/sched->makespan;
00502     if(freq>max_frequency) flag=1;
00503     for(j=0;j<sched->taskspercore[i];j++){
00504       setfreqparams(&(sched->list[i*tssize(sched->ts)+j]),freq);
00505       time=setstarttimeparams(&(sched->list[i*tssize(sched->ts)+j]),time);
00506     }
00507   }
00508   return flag;
00509 }
00510 
00511 // map the tasks to cores to balance load vector
00512 // greedy approach: map tasks one by one, map next task such that the maximum load of any core
00513 // is increased as little as possible, i.e. map the task to the core with the current minimum load
00514 // return 0 if schedule feasible (ie. all frequencies <= 1.0), else return 1 as schedule is not feasible
00515 static
00516 int scheduletaskset(Taskset *tssorted,Schedule *sched,double makespan,int corecount)
00517 { int i;
00518 
00519   initschedule(sched,tssorted,makespan,corecount, (char*) std::string("Pruhs schedule").c_str());
00520   
00521   for(i=0;i<tssize(tssorted);i++){
00522     ::map(gettask(tssorted,i),sched);
00523   }
00524   return scalefrequencies(sched);  
00525 }
00526 
00527 // JK: removed the CONT and DISC defines
00528 
00529 // JK: adapted routine
00530 // adapt the frequency for discrete freq levels
00531 // currently statically defined, see above
00532 static
00533 double adaptfrequency(double freq)
00534 { size_t i;
00535 
00536   if(freq>max_frequency) freq=max_frequency; // should not happen as in
00537     // this case the schedule is infeasible, and the computeenergy is never invoked
00538   for(i=0;i<number_of_frequencies;i++){
00539     if(freq<=discrete_frequencies_relative[i]*max_frequency){
00540       freq=discrete_frequencies_relative[i]*max_frequency;
00541       break;
00542     }
00543   }
00544   return freq;
00545 }
00546 
00547 // JK: new routine
00548 // compute index of discrete frequency level
00549 static
00550 int finddiscfrequencylevel(double freq)
00551 { size_t i;
00552 
00553   if(freq>max_frequency) freq=max_frequency; // should not happen as in
00554     // this case the schedule is infeasible, and the computeenergy is never invoked
00555   for(i=0;i<number_of_frequencies;i++){
00556     if(freq<=discrete_frequencies_relative[i]*max_frequency){
00557       break;
00558     }
00559   }
00560   return i;
00561 }
00562 
00563 
00564 // JK: new routine
00565 // scale task frequencies on each core to next higher and lower frequencies such that makespan is met, and frequency is switched only once
00566 // requires that all frequencies are <= max_frequency
00567 // returns 0 if all frequencies are <= max_frequency, 1 else
00568 // requires detail of schedule implementation
00569 static
00570 int scaletodiscretefrequencies(Schedule *sched)
00571 { int i,j;
00572   double freq;
00573   double discfreq;
00574   int discfreqlevel;
00575   double time;
00576   double sparetime;
00577   double addtime;
00578   int flag=0;
00579 
00580   for(i=0;i<sched->corecount;i++){
00581     time=0.0;
00582     freq=sched->loadpercore[i]/sched->makespan;
00583     if(freq>max_frequency){ flag=1; freq=max_frequency; }
00584     discfreq=adaptfrequency(freq);
00585     sparetime = (sched->makespan) - (sched->loadpercore[i])/discfreq; // compute how much time saved by higher discr. freq
00586     discfreqlevel=finddiscfrequencylevel(freq);
00587     if(discfreqlevel==0) sparetime=-1.0; // if freq <= lowest discrete frequency level, then no task can be scaled down
00588     for(j=0;j<sched->taskspercore[i];j++){
00589       // compute difference between task runtimes at lower discrete frequency and at higher discrete frequency
00590       addtime=taskload(gettaskfromtaskparams(&(sched->list[i*tssize(sched->ts)+j])))/max_frequency*(1.0/discrete_frequencies_relative[discfreqlevel-1] - 1.0/discrete_frequencies_relative[discfreqlevel]);
00591       if(addtime<=sparetime){
00592         setfreqparams(&(sched->list[i*tssize(sched->ts)+j]),discrete_frequencies_relative[discfreqlevel-1]*max_frequency);
00593         sparetime -= addtime;
00594       }else  
00595         setfreqparams(&(sched->list[i*tssize(sched->ts)+j]),discfreq);
00596       time=setstarttimeparams(&(sched->list[i*tssize(sched->ts)+j]),time);
00597     }
00598   }
00599   return flag;
00600 }
00601 
00602 #if DUMMY != 0
00603 // compute the power consumption of a task running at a certain frequency
00604 // requires frequency <= 1.0
00605 // if discrete frequency levels used, increase frequency to next available level
00606 // power model currently hardcoded as freq^3
00607 // return power consumption
00608 // requires detail of Taskparams implementation
00609 static
00610 double powercons(Taskparams *tp)
00611 { double freq;
00612 
00613   freq=tp->frequency; // JK: removed the frequency adaptation
00614   return freq*freq*freq;  
00615 }
00616 
00617 // compute runtime of a task as division of workload and frequency
00618 // requires frequency <= 1.0
00619 // if discrete frequency levels used, increase frequency to next available level
00620 // return runtime
00621 // requires detail of Taskparams implementation
00622 static
00623 double taskruntime(Taskparams *tp)
00624 { double freq;
00625 
00626   freq=tp->frequency;
00627   return taskload(tp->ptr)/freq;  
00628 }
00629 
00630 // compute the energy of a task as product of power consumption (depending on freq) and runtime
00631 // return the energy
00632 static
00633 double taskenergy(Taskparams *tp)
00634 { 
00635   return powercons(tp)*taskruntime(tp);
00636 }
00637 
00638 // compute the energy of a schedule.
00639 // return the computed energy
00640 // requires detail of schedule implementation
00641 static
00642 double computeenergy(Schedule *sched)
00643 { int i,j; 
00644   double energy=0.0;
00645   
00646   for(i=0;i<sched->corecount;i++)
00647     for(j=0;j<sched->taskspercore[i];j++){
00648       energy += taskenergy(&(sched->list[i*tssize(sched->ts)+j]));
00649     }
00650   return energy;  
00651 }
00652 #endif
00653 
00654 // Quality assessment parameters
00655 const long long int nsec_in_sec = 1000000000;
00656 
00657 static int
00658 timespec_subtract(struct timespec *result, struct timespec *x, struct timespec *y)
00659 {
00660         /* Perform the carry for the later subtraction by updating y. */
00661         if (x->tv_nsec < y->tv_nsec)
00662         {
00663                 int nsec = (y->tv_nsec - x->tv_nsec) / nsec_in_sec + 1;
00664                 y->tv_nsec -= nsec_in_sec * nsec;
00665                 y->tv_sec += nsec;
00666         }
00667         if (x->tv_nsec - y->tv_nsec > nsec_in_sec)
00668         {
00669                 int nsec = (x->tv_nsec - y->tv_nsec) / nsec_in_sec;
00670                 y->tv_nsec += nsec_in_sec * nsec;
00671                 y->tv_sec -= nsec;
00672         }
00673      
00674         /* Compute the time remaining to wait. tv_nsec is certainly positive. */
00675         result->tv_sec = x->tv_sec - y->tv_sec;
00676         result->tv_nsec = x->tv_nsec - y->tv_nsec;
00677      
00678         /* Return 1 if result is negative. */
00679         return x->tv_sec < y->tv_sec;
00680 }
00681 
00682 #if DUMMY == 0
00683 static
00684 pelib::Schedule makeSchedule(const pelib::Taskgraph &tg, const pelib::Platform &arch, std::map<const string, double>& stats)
00685 #else
00686 int main(int argc,char *argv[])
00687 #endif
00688 { Taskset ts1,tssorted;
00689   Schedule sched;
00690   double M;
00691   int p;
00692   int infeasible;
00693 #if DUMMY != 0
00694   double en_cont,en_disc;
00695 #endif
00696   struct timespec start, stop, total_time;
00697   Schedule sched_disc;
00698 
00699 #if DUMMY == 0
00700   int n;
00701 
00702 /* 
00703   std::ifstream tg_file(std::string(argv[1]), std::ios::in);
00704   std::ifstream arch_file(std::string(argv[2]), std::ios::in);
00705 
00706   pelib::Taskgraph tg = pelib::GraphML().parse(tg_file);
00707   pelib::Platform arch = pelib::AmplPlatform().parse(arch_file);
00708 
00709   tg_file.close();
00710   arch_file.close();
00711 */
00712 
00713   // read in taskset ts1 (including possible allocations in internal representation of taskset and tasks), deadline M, number of cores p
00714   readtaskset(&ts1, &M, &p, tg, arch);
00715 #else
00716   // read in taskset ts1 (including possible allocations in internal representation of taskset and tasks), deadline M, number of cores p
00717   readtaskset(&ts1,&M,&p);
00718 #endif
00719 
00720   /* TODO @Jörg: check if this region is indeed where the "useful" computation runs */
00721   clock_gettime(CLOCK_MONOTONIC, &start);
00722 
00723   /* Useful region */
00724   copytaskset(&tssorted,&ts1, (char*) std::string("taskset sorted").c_str());
00725   sorttaskset(&tssorted);
00726   /* End of useful region */
00727 
00728   clock_gettime(CLOCK_MONOTONIC, &stop);
00729   timespec_subtract(&total_time, &stop, &start);
00730 
00731 #if DUMMY == 0
00732   stats.insert(pair<const string, double>("time_global", (float)(total_time.tv_sec * nsec_in_sec + total_time.tv_nsec) / (float)nsec_in_sec));
00733 
00734   n = tg.getTasks().size();
00735   stats.insert(pair<const string, double>("complexity", n * log2(n) + n * p)); 
00736 #endif
00737 
00738   infeasible=scheduletaskset(&tssorted,&sched,M,p);
00739   stats.insert(pair<const string, double>("feasible", !infeasible));
00740 
00741   if(!infeasible){
00742     // write out the schedule...
00743 #if DUMMY != 0
00744     en_cont=computeenergy(&sched);
00745     printschedule(std::cerr, &sched); // NM: We can only print one schedule or the framework cannot parse correctly the output
00746     std::cerr << "quality = " << schedule_makespan(&sched, 1) << std::endl; 
00747 #else
00748   stats.insert(pair<const string, double>("quality", schedule_makespan(&sched, 1)));
00749 #endif
00750     copyschedule(&sched_disc,&sched,(char*) std::string("Pruhs schedule discrete frequencies").c_str());
00751     infeasible = scaletodiscretefrequencies(&sched_disc);
00752 #if DUMMY == 0
00753     return buildSchedule(&sched_disc);
00754 #else
00755     en_disc=computeenergy(&sched_disc);
00756     printschedule(std::cout, &sched_disc);
00757     std::cerr << "## Energy with cont. freq " << en_cont << std::endl;
00758     std::cerr << "## Energy with disc freq " << en_disc << std::endl;
00759 #endif
00760     //printf("## Energy with cont. freq %lf\n## Energy with disc freq %lf\n",en_cont,en_disc);
00761   }
00762 #if DUMMy != 0
00763   else{
00764     printschedule(std::cout, &sched);
00765   }
00766 #endif
00767 #if DUMMY != 0
00768   std::cerr << "feasible = " << !infeasible << std::endl;
00769 #endif
00770 
00771   deinittaskset(&ts1);
00772   deinittaskset(&tssorted);
00773   deinitschedule(&sched);
00774   //deinitschedule(&sched_disc);
00775   free(discrete_frequencies_relative);
00776 #if DUMMY == 0
00777   return pelib::Schedule("Pruhs Heuristic", tg.getName(), std::map<int, std::map<float, pair<const pelib::Task*, double> > >());
00778 #else
00779   return EXIT_SUCCESS;
00780 #endif
00781 }
00782 
00783 pelib::PruhsHeuristic::PruhsHeuristic()
00784 {
00785         // Do nothing
00786 }
00787 
00788 pelib::PruhsHeuristic::PruhsHeuristic(const Taskgraph &tg, const Platform &pt)
00789 {
00790         this->taskgraph = tg;
00791         this->platform = pt;
00792 }
00793 
00794 pelib::Schedule
00795 pelib::PruhsHeuristic::schedule(const Taskgraph &tg, const Platform &pt, std::map<const string, double>& stats) const
00796 {
00797         return makeSchedule(tg, pt, stats);
00798 }
00799 
00800 pelib::Schedule
00801 pelib::PruhsHeuristic::schedule(const Taskgraph &tg, const Platform &pt, const Algebra &param, std::map<const string, double>& stats) const
00802 {
00803         return schedule(tg, pt, stats);
00804 }
00805 
00806 const pelib::Algebra*
00807 pelib::PruhsHeuristic::solve() const
00808 {
00809         std::map<const string, double> stats;
00810         return new pelib::Algebra(schedule(this->taskgraph, this->platform, stats).buildAlgebra());
00811 }
00812 
00813 const pelib::Algebra*
00814 pelib::PruhsHeuristic::solve(std::map<const string, double> &stats) const
00815 {
00816         return new pelib::Algebra(schedule(this->taskgraph, this->platform, stats).buildAlgebra());
00817 }
00818 
00819 std::string
00820 pelib::PruhsHeuristic::getShortDescription() const
00821 {
00822         return string("Pruhs-Heur.");
00823 }
00824 
00825 #ifdef __cplusplus
00826 extern "C" {
00827 #endif
00828 
00829 const pelib::Schedule*
00830 pelib_schedule(const pelib::Taskgraph &tg, const pelib::Platform &pt, size_t argc, char **argv, std::map<const string, double>& statistics)
00831 {
00832         // Convert solver output to general schedule
00833         pelib::Schedule *sched;
00834         sched = new pelib::Schedule(pelib::PruhsHeuristic().schedule(tg, pt, statistics));
00835 
00836         return sched;
00837 }
00838 
00839 string
00840 pelib_description(size_t argc, char **argv)
00841 {
00842         // Convert solver output to general schedule
00843         string desc;
00844         desc = pelib::PruhsHeuristic().getShortDescription();
00845 
00846         return desc;
00847 }
00848 
00849 void
00850 pelib_delete(pelib::Schedule *sched)
00851 {
00852         delete sched;
00853 }
00854 
00855 #ifdef __cplusplus
00856 }
00857 #endif
00858 
00859