schedulers  1.0.0
src/SandersSpeck.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/SandersSpeck.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/Link.hpp>
00025 #include <pelib/Taskgraph.hpp>
00026 #include <pelib/Platform.hpp>
00027 #include <pelib/CastException.hpp>
00028 #include <pelib/ParseException.hpp>
00029 #include <pelib/AmplOutput.hpp>
00030 #include <pelib/PelibException.hpp>
00031 
00032 #endif
00033 
00034 #define debug(var) cout << "[" << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << "] " << #var << " = \"" << (var) << "\"" << endl;
00035 
00036 #define LEN 100
00037 
00038 #define TAUTHRESHOLD 0.0001
00039 #define MINFACT 0.0001
00040 
00041 // define a constant to simulate infinity
00042 #define MAX_DOUBLE pow(2.0,50.0)
00043 
00044 // define a threshold when interval halving shall stop, instead of exact solution
00045 #define THRESHOLD 0.000001
00046 
00047 using namespace std;
00048 
00049 typedef struct task{
00050 int idnumber;
00051 double work;
00052 int maxwidth;
00053 int pbar;
00054 double *htab;
00055 char name[LEN];
00056 } Task;
00057 
00058 typedef struct taskset{
00059 int number;
00060 int maxnumber;
00061 int maxcores; // max. number of cores for which taskset can be scheduled
00062 char name[LEN];
00063 Task **list;
00064 } Taskset;
00065 
00066 typedef struct taskparams{
00067 Task *ptr;
00068 double frequency;
00069 double start;
00070 double end;
00071 } Taskparams;
00072 
00073 typedef struct schedule{
00074 double makespan; // makespan to be reached
00075 int corecount; // number of cores actually used for scheduling
00076 int fullcorecount; // full number of cores
00077 Taskset *ts; // taskset that schedule refers to
00078 char name[LEN];
00079 double *loadpercore; // sums up the loads of the tasks mapped to each core
00080 int *taskspercore; // array of how many tasks are mapped to each core
00081 Taskparams *list; // 2-dim array of size corecount*tasksetsize where element [i*tasksetsize+j] points to j-th task on core i
00082 } Schedule;
00083 
00084 typedef struct etable{
00085 Taskset *ts;
00086 int size;
00087 int cores;
00088 double *etab;
00089 } ETable;
00090     
00091 double alpha;
00092 
00093 // give the workload of a task
00094 // requires details of task implementation
00095 double taskload(Task *t) { return t->work; }
00096 
00097 // give an element of the h-table of a task
00098 // requires 0<=p<=pbar
00099 // requires details of task implementation
00100 double taskhtab(Task *t,int p) { return t->htab[p]; }
00101 
00102 // init a taskset (given the number of tasks)
00103 // note: does not set the number of tasks
00104 // requires detail of Taskset implementation
00105 void inittaskset(Taskset *ts,int n,char *name,int maxcores)
00106 { 
00107   ts->number = 0;
00108   ts->maxnumber = n;
00109   ts->maxcores = maxcores;
00110   strcpy(ts->name,name);
00111   ts->list = (Task**)malloc(sizeof(Task*)*n);
00112 }
00113 
00114 double g(int i) { return (double)i*(double)i; }
00115 
00116 // specific: the efficiency function is e(0)=1, e(i)=1-R*g(i)/g(maxwidth) for 1<=i<=maxwidth, with g(x)=g^2, and R=0.3
00117 // requires that 1<=i and 1<=maxwidth
00118 double efficiency(int i,int maxwidth)
00119 { double R=0.3;
00120 
00121   if(i==1) return 1.0;
00122   else if (i>maxwidth) return 0.000001;
00123   else return 1.0-R*g(i)/g(maxwidth);
00124 }
00125 
00126 // compute the table of h function, and pbar for task
00127 void computehtab(Task *t,int maxcores)
00128 { int i;
00129   double eff;
00130   
00131   t->pbar=maxcores;// patch for case that real pbar is larger than corecount available!
00132   t->htab=(double*)malloc(sizeof(double)*(1+maxcores)); // one more as htab starts with 0
00133   t->htab[0]=0.0;
00134   for(i=1;i<=maxcores;i++){
00135       eff=efficiency(i,t->maxwidth);
00136       // h(i)=sqrt[alpha-1](speedup(i)^alpha/i)
00137       // as speedup(i)=eff(i)*i, we get:
00138       t->htab[i]=pow(eff,alpha/(alpha-1.0))*(double)i;
00139       if((t->htab[i])<(t->htab[i-1])) { t->pbar=i-1; break; }
00140   }
00141 }  
00142 
00143 // add a task to a taskset
00144 // requires detail of Task and Taskset implementation
00145 void addtasktotaskset(Taskset *ts,int id,double work,int maxwidth,char *name)
00146 {
00147   ts->list[ts->number]=(Task*)malloc(sizeof(Task));
00148   ts->list[ts->number]->idnumber=id;
00149   ts->list[ts->number]->work=work;
00150   ts->list[ts->number]->maxwidth=maxwidth;
00151   strcpy(ts->list[ts->number]->name,name);
00152   computehtab(ts->list[ts->number],ts->maxcores);
00153   ts->number++;
00154 }
00155 
00157 // note: does not free the memory for tasks
00158 // requires detail of Taskset implementation
00159 void deinittaskset(Taskset *ts)
00160 {
00161   free(ts->list);
00162 }
00163 
00164 // copy a taskset: requires details of taskset implementation
00165 // does not copy the tasks themselves, only the pointers to the tasks
00166 // includes a taskset initialization, i.e. if taskset trg has been initialized before, it should be deinited first
00167 void copytaskset(Taskset *trg,Taskset *src,char *name)
00168 { int i;
00169 
00170   inittaskset(trg,src->number,name,src->maxcores);
00171   trg->number = src->number;
00172   for(i=0;i<trg->number;i++) *((trg->list)+i) = *((src->list)+i);
00173 }
00174 
00175 #if DUMMY != 0 
00176 // dummy, just for testing
00177 // requires detail of Taskset implementation
00178 void readinput(Taskset *ts,int maxcores)
00179 { int taskcount=10;
00180   inittaskset(ts, taskcount, (char*)string("Dummy task set").c_str(), maxcores);
00181 //  addtasktotaskset(ts,id,workload,maxwidth,name);
00182 /*  addtasktotaskset(ts,0,4.0,8, (char*)string("task 0").c_str());
00183   addtasktotaskset(ts,1,3.0,6, (char*)string("task 1").c_str());
00184   addtasktotaskset(ts,2,5.0,4, (char*)string("task 2").c_str());
00185   addtasktotaskset(ts,3,0.4,3, (char*)string("task 3").c_str());
00186   addtasktotaskset(ts,4,0.3,2, (char*)string("task 4").c_str());
00187   addtasktotaskset(ts,5,0.2,1, (char*)string("task 5").c_str());
00188 */
00189 addtasktotaskset(ts,0,27.0,4, (char*)string("task 1").c_str());
00190   addtasktotaskset(ts,1,13.0,4, (char*)string("task 2").c_str());
00191   addtasktotaskset(ts,2,16.0,4, (char*)string("task 3").c_str());
00192   addtasktotaskset(ts,3,11.0,1, (char*)string("task 4").c_str());
00193   addtasktotaskset(ts,4,27.0,4, (char*)string("task 5").c_str());
00194   addtasktotaskset(ts,5,16.0,4, (char*)string("task 6").c_str());
00195   addtasktotaskset(ts,6,34.0,4, (char*)string("task 7").c_str());
00196   addtasktotaskset(ts,7,25.0,4, (char*)string("task 8").c_str());
00197   addtasktotaskset(ts,8,27.0,4, (char*)string("task 9").c_str());
00198   addtasktotaskset(ts,9,17.0,4, (char*)string("task 10").c_str());
00199 }
00200 #else
00201 void readinput(Taskset *ts, const pelib::Taskgraph &tg, const pelib::Platform &arch)
00202 {
00203         using namespace std;
00204         using namespace pelib;
00205 
00206         int taskcount = tg.getTasks().size();
00207         inittaskset(ts, taskcount, (char*)string("taskset as read in").c_str(), arch.getCores().size());
00208 
00209         for(set<pelib::Task>::const_iterator i = tg.getTasks().begin(); i != tg.getTasks().end(); i++)
00210         {
00211                 size_t id = std::distance(tg.getTasks().begin(), i);
00212                 addtasktotaskset(ts, id, i->getWorkload(), i->getMaxWidth(), (char*) i->getName().c_str());
00213         }       
00214 }
00215 
00216 #endif
00217 
00218 // return the name string of a taskset
00219 // requires detail of Taskset implementation
00220 char *tasksetname(Taskset *ts) { return ts->name; }
00221 
00222 // give number of tasks in taskset
00223 // requires details of taskset implementation
00224 int tssize(Taskset *ts) { return ts->number; }
00225 
00227 // requires details of taskset implementation
00228 Task *gettask(Taskset *ts,int i) { return ts->list[i]; }
00229 
00230 // print a task
00231 // requires detail of task implementation
00232 void printtask(Task *t)
00233 { int i;
00234     
00235   printf("Task %d <%s> work %lf maxwidth %d pbar %d\nh-table:",t->idnumber,t->name,t->work,t->maxwidth,t->pbar);
00236   for(i=0;i<=t->pbar;i++) printf(" %lf",t->htab[i]);
00237   printf("\n");
00238 }
00239 
00240 // print a taskset
00241 // requires detail of taskset implementation
00242 void printtaskset(Taskset *ts)
00243 { int i;
00244 
00245   printf("Taskset <%s> for up to %d cores\n",ts->name,ts->maxcores);
00246   for(i=0;i<tssize(ts);i++) printtask(ts->list[i]);
00247 }
00248 
00249 //#define fprintf(...)
00250 #define printf_d(expr) fprintf(stderr, "[%s:%s:%d] %s = %d\n", __FILE__, __FUNCTION__, __LINE__, #expr, (int)expr);
00251 #define printf_lf(expr) fprintf(stderr, "[%s:%s:%d] %s = %lf\n", __FILE__, __FUNCTION__, __LINE__, #expr, (double)expr);
00252 double etau(Task *t,int p,double tau,double M)
00253 { double et;
00254 /*
00255   printf_lf(-pow(taskload(t),alpha))
00256   printf_lf(pow(tau*taskhtab(t,p+1)+(1.0-tau)*taskhtab(t,p),-alpha))
00257   printf_lf(taskhtab(t,p+1));
00258   printf_lf(taskhtab(t,p));
00259   printf_lf(taskhtab(t,p+1)-taskhtab(t,p));
00260   printf_lf(pow(M, alpha - 1.0));
00261 */
00262 
00263   et=-pow(taskload(t),alpha)*(alpha-1.0)*pow(tau*taskhtab(t,p+1)+(1.0-tau)*taskhtab(t,p),-alpha)*(taskhtab(t,p+1)-taskhtab(t,p)) / pow(M, alpha - 1.0);
00264   return et;
00265 }
00266 
00267 void initetable(ETable *et,Taskset *ts,int cores)
00268 {
00269    et->ts=ts;
00270    et->size=tssize(ts);
00271    et->cores=cores;
00272    et->etab=(double*)malloc(sizeof(double)*(et->size)*(2*cores+1));
00273 }
00274 
00275 void deinitetable(ETable *et)
00276 {
00277   free(et->etab);
00278 }
00279 
00280 // requires: cores <= ts->maxcores
00281 // note: all entries are scaled by makespan^{alpha-1}
00282 void computeetable(ETable *et,Taskset *ts,int cores, double M)
00283 { int i,j;
00284   
00285   // etable[i*(2*cores+1)+j] gives for task i, element j of its bend points:
00286   // if j is even: E<-(j/2), if j is odd: E->((j+1)/2), i.e. in order:
00287   // E<-(0), E->(1), E<-(1), E->(2),...
00288   // last element is E<-(pbar), i.e. j=2*pbar
00289   initetable(et,ts,cores);
00290   for(i=0;i<tssize(ts);i++){
00291     et->etab[i*(2*cores+1)]=-MAX_DOUBLE; // E<-(0)=-infinity
00292     for(j=1;j<=2*(gettask(ts,i)->pbar);j++){
00293       et->etab[i*(2*cores+1)+j]=etau(gettask(ts,i),(j-1)/2,1.0, M);  
00294       j++;
00295       et->etab[i*(2*cores+1)+j]=etau(gettask(ts,i),j/2,0.0, M);  
00296     }    
00297   }
00298 }
00299 
00300 void printetable(ETable *et)
00301 { int i,j;
00302 
00303   printf("e-table for task set %s\n",et->ts->name);
00304   for(i=0;i<et->size;i++){
00305     printf("Task %d:",i);
00306     for(j=0;j<1+2*gettask(et->ts,i)->pbar;j++){
00307       printf(" %lf",et->etab[i*(1+2*(et->cores))+j]);
00308     }
00309     printf("\n");    
00310   }      
00311 }    
00312 
00313 void computeinitialc(Taskset *ts,ETable *et,double *clp,double *cup, double M)
00314 { int i;
00315   int pm;
00316   double taum;
00317   double cl,cltmp,cu,cutmp;
00318   
00319   if(tssize(ts)>et->cores){ pm=0; taum=(double)(et->cores)/(double)(tssize(ts)); } else { pm=1; taum=0.0; }
00320   cl=0.0; cu=0.0;
00321   for(i=0;i<tssize(ts);i++){
00322     cltmp=etau(gettask(ts,i),pm,taum, M);
00323     //printf_lf(cltmp);
00324     if(cltmp<cl) cl=cltmp;
00325     cutmp=et->etab[i*(1+2*(et->cores))+2*(gettask(ts,i)->pbar)];
00326     if(cutmp<cu) cu=cutmp;
00327   }    
00328 
00329   *clp=cl;
00330   *cup=cu;
00331 }
00332 
00333 double invertefunction(Taskset *ts,ETable *et,int i,double c,double cl,double cu,int *bendpointsleftptr,double M)
00334 { int j;
00335   int pint;
00336   double proc,tau;
00337     
00338   // find adjacent bendpoints for c
00339   // in final version, use binary search. Here: linear
00340   for(j=0;j<2*gettask(ts,i)->pbar;j++)
00341     if(c<et->etab[i*(2*(ts->maxcores)+1)+j]) break;
00342   // now know that c is between j-1 and j
00343 //  printf("task %d position in etable %d\n",i,j-1);
00344   // check if cl and cu are between bendpoints or not
00345   if(!((cl>et->etab[i*(2*(ts->maxcores)+1)+j-1])&&(cu<et->etab[i*(2*(ts->maxcores)+1)+j]))) (*bendpointsleftptr)++;
00346 
00347   // check if case 1 or case 2
00348   if((j-1)&1){  // j-1 is odd
00349     // case 2
00350     proc=(double)(j>>1);
00351 //    printf("case 2 p+tau=%lf\n",proc);
00352   }else{ // case 1
00353     pint=(j-1)>>1;
00354     proc=(double)pint;
00355 // simple workaround: linear interpolation
00356       //tau = (c-(et->etab[i*(2*(ts->maxcores)+1)+j-1]))/((et->etab[i*(2*(ts->maxcores)+1)+j])-(et->etab[i*(2*(ts->maxcores)+1)+j-1]));
00357         tau = ((ts->list[i]->work)*pow((1.0-alpha)*((ts->list[i]->htab[1+pint])-(ts->list[i]->htab[pint]))/(c*pow(M,alpha-1.0)),1.0/alpha)-(ts->list[i]->htab[pint]))/((ts->list[i]->htab[1+pint])-(ts->list[i]->htab[pint]));
00358       proc += tau;
00359 //    proc += ((ts->list[i]->work)*pow((1.0-alpha)*((ts->list[i]->htab[1+pint])-(ts->list[i]->htab[pint]))/(c*pow(M,alpha-1.0)),1.0/alpha)-(ts->list[i]->htab[pint]))/((ts->list[i]->htab[1+pint])-(ts->list[i]->htab[pint]));
00360         //printf_d(j);
00361 //    printf("nominator prefactor %lf\n",(ts->list[i]->work));
00362 //    printf("nominator -(alpha-1)*(h(p+1)-h(p)) %lf\n",(1.0-alpha)*((ts->list[i]->htab[1+pint])-(ts->list[i]->htab[pint])));
00363 //printf_lf(c);
00364 //printf_lf(alpha);
00365 //printf_lf(M);
00366 //    printf("nominator c*M to alpha-1 %lf\n",(c*pow(M,alpha-1.0)));
00367 //    printf("nominator 2nd addend %lf\n",-(ts->list[i]->htab[pint]));
00368 //    printf("denominator %lf\n",((ts->list[i]->htab[1+pint])-(ts->list[i]->htab[pint])));
00369 //    printf("case 1 p=%d tau=%lf\n",pint,proc-(double)pint);
00370   }        
00371   // compute p+tau, and return
00372   
00373   return proc;
00374 }
00375     
00376 int checktoomany(Taskset *ts,ETable *et,double c,double cl,double cu,int *bendpointsleftptr,double M)
00377 { double m,m2;
00378   int i;
00379   int singletaskbendpointsleft = 0;
00380 
00381   *bendpointsleftptr = 0;
00382   m=0.0;
00383   for(i=0;i<tssize(ts);i++){
00384     m2 = invertefunction(ts,et,i,c,cl,cu,&singletaskbendpointsleft,M);
00385 //    printf("Task %d alloc %lf\n",i,m2);
00386     m += m2;
00387         //printf_lf(m);
00388     if(singletaskbendpointsleft) (*bendpointsleftptr)++;  
00389   }    
00390   if(m>(double)(et->cores)) return 1; else return 0;
00391 }
00392 
00393 // JKJK Nov 4, 2014: new function
00394 double computetaskenergy(Task *t,int pistar,double taui,double deadline,double lalpha)
00395 { double energy;
00396   double workload;
00397   double hp,hpplusone;
00398 
00399   workload=taskload(t);
00400   if(workload == 0)
00401   {
00402     return 0;
00403   }
00404   else
00405   {
00406     hp=taskhtab(t,pistar);
00407     hpplusone=taskhtab(t,pistar+1);
00408     energy=pow(workload,lalpha)/pow(deadline*(taui*hpplusone+(1.0-taui)*hp),lalpha-1.0);
00409 /*
00410         printf_lf(workload);
00411         printf_lf(t->idnumber);
00412         printf_lf(taui);
00413         printf_lf(pistar);
00414         printf_lf(deadline);
00415         printf_lf(lalpha);
00416         printf_lf(hp);
00417         printf_lf(hpplusone);
00418         printf_lf(energy);
00419     printf_lf(pow(workload,lalpha));
00420         printf_lf(pow(deadline*(taui*hpplusone+(1.0-taui)*hp),lalpha-1.0)); */
00421 /*  if((pistar ==0) && (taui < TAUTHRESHOLD))
00422   {
00423     energy = pow(workload, lalpha) / pow(deadline * MINFACT, lalpha - 1.0);
00424   }
00425   else
00426   {*/
00427 //  }
00428     return energy;
00429   }
00430 }    
00431 
00432 // JKJK Nov 4, 2014: changed function to return value double
00433 #if DUMMY != 0
00434 double computeoptc(Taskset *ts,ETable *et,int p,double M)
00435 #else
00436 double computeoptc(Taskset *ts,ETable *et,int p,double M, double minFreq)
00437 #endif
00438 { double cl,cu,c,prev_cl = 0,prev_cu = 0;
00439   int bendpointsflag;
00440   int i;
00441   int dummy;
00442   double pistar;
00443   double energy; // JKJK Nov 4, 2014: added variable
00444     
00445   computeinitialc(ts,et,&cl,&cu, M);
00446 //printf_lf(cl);
00447 //printf_lf(cu);
00448   do{
00449     c=(cl+cu)/2.0;
00450     //printf_lf(c);
00451     prev_cl = cl;
00452     prev_cu = cu;
00453     if(checktoomany(ts,et,c,cl,cu,&bendpointsflag,M)) cu=c; else cl=c;
00454 //  }while(bendpointsflag); // skip break when no bendpoints left in intervall,
00455 //  directsolve(); // and skip computing direct solution
00456 // instead: stop when interval cl,cu is sufficiently small, and compute processor allocations from c
00457 //    printf("cl %lf cu %lf c %lf fabs(cu - cl) %lf\n",cl,cu,c,fabs(cu-cl));
00458   }while(fabs(cu-cl)>THRESHOLD && (cl != prev_cl || cu != prev_cu));
00459   c=cu=cl; // ensure that sum of processor allocations is <= number of cores
00460   // output: number of tasks, number of cores, deadline
00461 //  printf("%d %d %lf\n",tssize(ts),p,M);
00462   energy=0.0; // JKJK Nov 4, 2014: added statement
00463   // for each task, compute
00464   for(i=0;i<tssize(ts);i++){
00465     pistar=invertefunction(ts,et,i,c,cl,cu,&dummy,M);
00466     // for each task: tasknumber, integral number of cores allocated p, fractional number of cores allocated tau,speedup of task with p cores, speedup of task with p+1 cores
00467     //printf("%d %d %lf %lf %lf %lf\n",ts->list[i]->idnumber,(int)pistar,pistar-(int)pistar,ts->list[i]->work,((int)pistar)*efficiency((int)pistar,ts->list[i]->maxwidth),(1+(int)pistar)*efficiency(1+(int)pistar,ts->list[i]->maxwidth));
00468 //    printf("%d %d %lf %lf %lf %lf\n",ts->list[i]->idnumber,(int)pistar,pistar,ts->list[i]->work,((int)pistar)*efficiency((int)pistar,ts->list[i]->maxwidth),(1+(int)pistar)*efficiency(1+(int)pistar,ts->list[i]->maxwidth));
00469 // JKlatest: add x lines
00470     if(pistar<1.0){
00471 //      double taui=pistar-(int)pistar=pistar (because (int)pistar==0);
00472 //      double time=taui*M;
00473 //      double frequency=taskload(ts->list[i])/time;
00474 
00475 #if DUMMY != 0 && FORCE_MIN_FREQUENCY != 0
00476         int minFreq = 1;
00477 #endif
00478 
00479         // If the task's necessary frequency is lower than the minimal frequency given by the platform, then raise it to the minimum
00480 #if FORCE_MIN_FREQUENCY != 0    
00481       double frequency=taskload(ts->list[i])/(pistar*M);
00482       if(frequency<minFreq){
00483         pistar=taskload(ts->list[i])/(minFreq * M); // set frequency to 1.0, makes taui smaller!
00484       }
00485 #endif
00486     }
00487     energy+=computetaskenergy(ts->list[i],(int)pistar,pistar-(int)pistar,M,alpha); // JKJK Nov 4, 2014: added statement
00488 /*      printf_lf(i);
00489         printf_lf(pistar);
00490         printf_lf(M);
00491         printf_lf(alpha);
00492         printf_lf(energy);*/
00493   }
00494   return energy; // JKJK Nov 4, 2014: added statement
00495 }
00496     
00497 // Quality assessment parameters
00498 const long long int nsec_in_sec = 1000000000;
00499 
00500 static int
00501 timespec_subtract(struct timespec *result, struct timespec *x, struct timespec *y)
00502 {
00503         /* Perform the carry for the later subtraction by updating y. */
00504         if (x->tv_nsec < y->tv_nsec)
00505         {
00506                 int nsec = (y->tv_nsec - x->tv_nsec) / nsec_in_sec + 1;
00507                 y->tv_nsec -= nsec_in_sec * nsec;
00508                 y->tv_sec += nsec;
00509         }
00510         if (x->tv_nsec - y->tv_nsec > nsec_in_sec)
00511         {
00512                 int nsec = (x->tv_nsec - y->tv_nsec) / nsec_in_sec;
00513                 y->tv_nsec += nsec_in_sec * nsec;
00514                 y->tv_sec -= nsec;
00515         }
00516      
00517         /* Compute the time remaining to wait. tv_nsec is certainly positive. */
00518         result->tv_sec = x->tv_sec - y->tv_sec;
00519         result->tv_nsec = x->tv_nsec - y->tv_nsec;
00520      
00521         /* Return 1 if result is negative. */
00522         return x->tv_sec < y->tv_sec;
00523 }
00524 
00525 #if DUMMY == 0
00526 static
00527 pelib::Schedule makeSchedule(const pelib::Taskgraph &tg, const pelib::Platform &arch, std::map<const string, double>& stats)
00528 #else
00529 int main(int argc,char *argv[])
00530 #endif
00531 {
00532         double M;
00533         int p;
00534         struct timespec start, stop, total_time;
00535         Taskset ts;
00536         ETable et;
00537 
00538         // set alpha, important for energy and computation of h-function
00539         alpha = 3.0;
00540 
00541 #if DUMMY != 0
00542         // set number of cores and makespan
00543         p = 4;
00544         M = 33.6758;
00545 
00546         // read in taskset ts
00547         readinput(&ts, p);
00548 #else
00549         p = arch.getCores().size();
00550         M = tg.getDeadline(arch);
00551         double minFreq = *(*arch.getCores().begin())->getFrequencies().begin();
00552 
00553         readinput(&ts, tg, arch);
00554 #endif
00555         // printtaskset(&ts);
00556         clock_gettime(CLOCK_MONOTONIC, &start);
00557         computeetable(&et,&ts,p, M);
00558         clock_gettime(CLOCK_MONOTONIC, &stop);
00559 #if DUMMY != 0
00560         double energy = computeoptc(&ts,&et,p,M);
00561 #else
00562         double energy = computeoptc(&ts,&et,p,M,minFreq);
00563 #endif
00564 
00565         deinittaskset(&ts);
00566         deinitetable(&et);
00567 
00568 #if DUMMY != 0
00569         cerr << "energy = " << energy << endl;
00570 #else
00571         /*
00572         printf_lf(energy);
00573         printf_lf(M);
00574         printf_lf((double)p);
00575         printf_lf(alpha);
00576         */
00577         double freq = pow(energy / (M * p), 1.0/alpha);
00578 
00579         pelib::Task t(string("energy"));
00580         t.setWorkload(energy / pow(freq, alpha));
00581         t.setEfficiencyString("1");
00582         t.setMaxWidth(p);
00583         t.setFrequency(freq);
00584 
00585         std::map<int, std::map<float, pair<const pelib::Task*, double> > > schedule;
00586         for(int i = 0; i < p; i++)
00587         {
00588                 std::map<float, pair<const pelib::Task*, double> > core;
00589                 core.insert(std::pair<float, pair<const pelib::Task*, double> >(0, pair<const pelib::Task*, double>(&t, t.getWorkload())));
00590 
00591                 schedule.insert(pair<int, std::map<float, pair<const pelib::Task*, double> > >(i + 1, core));
00592         }
00593 
00594         pelib::Schedule pelib_schedule(string("Sanders and Speck"), tg.getName(), schedule);
00595 #endif
00596 
00597 #if DUMMY != 0
00598         pelib::Taskgraph newtg;
00599         set<pelib::Task> tasks;
00600         tasks.insert(t);
00601         newtg = pelib::Taskgraph(tasks, set<pelib::Link>());
00602         newtg.setName("Dummy taskgraph");
00603         std::ostringstream strs;
00604         strs << M;
00605         std::string str = strs.str();
00606         newtg.setDeadlineCalculator(strs.str());
00607         std::ofstream newtg_file(std::string(argv[3]), std::ios::out);
00608         pelib::GraphML().dump(newtg_file, newtg);
00609         newtg_file.close();
00610 
00611         pelib::XMLSchedule().dump(cout, pelib_schedule);
00612 #endif
00613 
00614         timespec_subtract(&total_time, &stop, &start);
00615 #if DUMMY != 0
00616         cerr << "energy = " << energy << std::endl;
00617 #else
00618         stats.insert(pair<const string, double>("optimal", 1));
00619         stats.insert(pair<const string, double>("feasible", isfinite(energy)));
00620         stats.insert(pair<const string, double>("time_global", (float)(total_time.tv_sec * nsec_in_sec + total_time.tv_nsec) / (float)nsec_in_sec));
00621 #endif
00622 
00623 #if DUMMY == 0
00624         if(isfinite(energy))
00625         {
00626                 return pelib_schedule;
00627         }
00628         else
00629         {
00630                 return pelib::Schedule(string("Sanders and Speck"), tg.getName(), pelib::Schedule::table());
00631         }
00632 #else
00633         return isfinite(energy) ? EXIT_SUCCESS : EXIT_FAILURE;
00634 #endif
00635 }
00636 
00637 pelib::SandersSpeck::SandersSpeck()
00638 {
00639         // Do nothing
00640 }
00641 
00642 pelib::SandersSpeck::SandersSpeck(const Taskgraph &tg, const Platform &pt)
00643 {
00644         this->taskgraph = tg;
00645         this->platform = pt;
00646 }
00647 
00648 pelib::Schedule
00649 pelib::SandersSpeck::schedule(const Taskgraph &tg, const Platform &pt, std::map<const string, double>& stats) const
00650 {
00651         return makeSchedule(tg, pt, stats);
00652 }
00653 
00654 pelib::Schedule
00655 pelib::SandersSpeck::schedule(const Taskgraph &tg, const Platform &pt, const Algebra &param, std::map<const string, double>& stats) const
00656 {
00657         return schedule(tg, pt, stats);
00658 }
00659 
00660 const pelib::Algebra*
00661 pelib::SandersSpeck::solve() const
00662 {
00663         std::map<const string, double> stats;
00664         return new pelib::Algebra(schedule(this->taskgraph, this->platform, stats).buildAlgebra());
00665 }
00666 
00667 const pelib::Algebra*
00668 pelib::SandersSpeck::solve(std::map<const string, double> &stats) const
00669 {
00670         return new pelib::Algebra(schedule(this->taskgraph, this->platform, stats).buildAlgebra());
00671 }
00672 
00673 std::string
00674 pelib::SandersSpeck::getShortDescription() const
00675 {
00676         return string("SandersSpeck.");
00677 }
00678 
00679 #ifdef __cplusplus
00680 extern "C" {
00681 #endif
00682 
00683 const pelib::Schedule*
00684 pelib_schedule(const pelib::Taskgraph &tg, const pelib::Platform &pt, size_t argc, char **argv, std::map<const string, double>& statistics)
00685 {
00686         // Convert solver output to general schedule
00687         pelib::Schedule *sched;
00688         sched = new pelib::Schedule(pelib::SandersSpeck().schedule(tg, pt, statistics));
00689 
00690         return sched;
00691 }
00692 
00693 string
00694 pelib_description(size_t argc, char **argv)
00695 {
00696         // Convert solver output to general schedule
00697         string desc;
00698         desc = pelib::SandersSpeck().getShortDescription();
00699 
00700         return desc;
00701 }
00702 
00703 void
00704 pelib_delete(pelib::Schedule *sched)
00705 {
00706         delete sched;
00707 }
00708 
00709 #ifdef __cplusplus
00710 }
00711 #endif
00712 
00713