schedulers
1.0.0
|
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 ¶m, 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