pelib
2.0.0
|
00001 /* 00002 Copyright 2015 Nicolas Melot 00003 00004 This file is part of Pelib. 00005 00006 Pelib 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 Pelib 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 Pelib. If not, see <http://www.gnu.org/licenses/>. 00018 */ 00019 00020 #include <libxml++/libxml++.h> 00021 #include <exception> 00022 #include <vector> 00023 #include <sstream> 00024 #include <cstdlib> 00025 #include <string> 00026 00027 extern "C"{ 00028 #include <igraph.h> 00029 } 00030 #include <cairomm/context.h> 00031 #include <cairomm/surface.h> 00032 #include <sigc++/signal.h> 00033 #include <cmath> 00034 00035 #include <pelib/Schedule.hpp> 00036 #include <pelib/TetrisSchedule.hpp> 00037 00038 #include <pelib/Scalar.hpp> 00039 #include <pelib/Vector.hpp> 00040 #include <pelib/Matrix.hpp> 00041 #include <pelib/Set.hpp> 00042 #include <pelib/Task.hpp> 00043 #include <pelib/Taskgraph.hpp> 00044 00045 #include <pelib/CastException.hpp> 00046 #include <pelib/ParseException.hpp> 00047 00048 #ifdef debug 00049 #undef debug 00050 #endif 00051 00052 #ifndef debug 00053 #define debug(expr) cerr << "[" << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << "] " << #expr << " = \"" << (expr) << "\"." << endl; 00054 #endif 00055 00056 using namespace pelib; 00057 using namespace std; 00058 using namespace Cairo; 00059 00060 static uint32_t 00061 shiftLeft(uint32_t value, uint32_t shift) 00062 { 00063 return value << shift; 00064 } 00065 00066 static uint32_t 00067 shiftRight(uint32_t value, uint32_t shift) 00068 { 00069 return value >> shift; 00070 } 00071 00072 static unsigned char 00073 decode(uint32_t value, uint32_t position) 00074 { 00075 return shiftRight(value & shiftLeft(255, position * 8), position * 8); 00076 } 00077 00078 static uint32_t 00079 encode(uint32_t base, unsigned char value, uint32_t position) 00080 { 00081 return base - shiftLeft(decode(base, position), position * 8) + shiftLeft(value, position * 8); 00082 } 00083 00084 static 00085 uint32_t 00086 HSLtoRGB(uint32_t hsl, double *CC) 00087 { 00088 double H = decode(hsl, 3); 00089 double S = decode(hsl, 2); 00090 double L = decode(hsl, 1); 00091 double A = decode(hsl, 0); 00092 00093 H = H / 255 * 6; 00094 H = fmod(H, 2); 00095 S = S / 255; 00096 L = L / 255; 00097 00098 double R, G, B, C; 00099 if(CC != NULL) 00100 { 00101 C = *CC; 00102 } 00103 else 00104 { 00105 C = (1 - abs(2 * L - 1)) * S; 00106 } 00107 double X = C * (1 - abs(H - 1)); 00108 00109 if(0 <= H && H < 1) 00110 { 00111 R = C; 00112 G = X; 00113 B = 0; 00114 } 00115 else if(1 <= H && H < 2) 00116 { 00117 R = X; 00118 G = C; 00119 B = 0; 00120 } 00121 else if(2 <= H && H < 3) 00122 { 00123 R = 0; 00124 G = C; 00125 B = X; 00126 } 00127 else if(3 <= H && H < 4) 00128 { 00129 R = 0; 00130 G = X; 00131 B = C; 00132 } 00133 else if(4 <= H && H < 5) 00134 { 00135 R = X; 00136 G = 0; 00137 B = C; 00138 } 00139 else if(5 <= H && H < 6) 00140 { 00141 R = C; 00142 G = 0; 00143 B = X; 00144 } 00145 else 00146 { 00147 R = G = B = 0; 00148 } 00149 00150 //double m = L - C / 2; 00151 double m = L - (0.3 * R + 0.59 * G + 0.11 * B); 00152 00153 R = (R + m) * 255; 00154 G = (G + m) * 255; 00155 B = (B + m) * 255; 00156 00157 // Round RGB values to closest integer by truncating value + 0.5 00158 uint32_t rgb = A + encode(0, R + 0.5, 3) + encode(0, G + 0.5, 2) + encode(0, B + 0.5, 1); 00159 00160 return rgb; 00161 } 00162 00163 // Give HSLtoRGB the output value C if you want to convert back the color to RGB 00164 static 00165 uint32_t 00166 RGBtoHSL(uint32_t rgb, double &C) 00167 { 00168 double R = decode(rgb, 3); 00169 double G = decode(rgb, 2); 00170 double B = decode(rgb, 1); 00171 double A = decode(rgb, 0); 00172 00173 R = R / 255; 00174 G = G / 255; 00175 B = B / 255; 00176 00177 double M = R > G ? R > B ? R : B : G > B ? G : B; 00178 double m = R < G ? R < B ? R : B : G < B ? G : B; 00179 C = M - m; 00180 00181 double H = 0; 00182 if(M == R) 00183 { 00184 H = fmod((G - B) / C, 6); 00185 } 00186 else if(M == G) 00187 { 00188 H = ((B - R) / C) + 2; 00189 } 00190 else if(M == B) 00191 { 00192 H = ((R - G) / C) + 4; 00193 } 00194 else 00195 { 00196 // Cannot happen 00197 } 00198 H = 60 * H; 00199 00200 // HSL 00201 //double L = (M + m) / 2; 00202 //double S = C == 0 ? 0 : C / (1 - abs(2 * L - 1)); 00203 00204 // Rec 601 NTSC 00205 double L = 0.3 * R + 0.59 * G + 0.11 * B; 00206 double S = 1 - m / ((R + G + B) / 3); 00207 00208 uint32_t hsl = A + encode(0, H / 360 * 255 + 0.5, 3) + encode(0, S * 255 + 0.5, 2) + encode(0, L * 255 + 0.5, 1); 00209 00210 return hsl; 00211 } 00212 00213 static 00214 map<float, uint32_t> 00215 makeGradient(vector<uint32_t> colors, set<float> values) 00216 { 00217 map<float, uint32_t> gradient; 00218 float minValue = *values.begin(); 00219 float maxValue = *values.rbegin(); 00220 00221 for(set<float>::iterator i = values.begin(); i != values.end(); i++) 00222 { 00223 double C; 00224 float value = *i; 00225 float position = (value - minValue) / (maxValue - minValue) * (colors.size() - 1); 00226 size_t minIndex = (size_t)floor(position); 00227 size_t maxIndex = (size_t)ceil(position); 00228 position = (position - minIndex); 00229 vector<uint32_t>::iterator minIter = colors.begin(); 00230 std::advance(minIter, minIndex); 00231 uint32_t minColor = *minIter; 00232 unsigned char minRed = decode(minColor, 3); 00233 unsigned char minGreen = decode(minColor, 2); 00234 unsigned char minBlue = decode(minColor, 1); 00235 unsigned char minAlpha = decode(minColor, 0); 00236 unsigned char minLuminosity = decode(RGBtoHSL(minColor, C), 2); 00237 00238 vector<uint32_t>::iterator maxIter = colors.begin(); 00239 std::advance(maxIter, maxIndex); 00240 uint32_t maxColor = *maxIter; 00241 unsigned char maxRed = decode(maxColor, 3); 00242 unsigned char maxGreen = decode(maxColor, 2); 00243 unsigned char maxBlue = decode(maxColor, 1); 00244 unsigned char maxAlpha = decode(maxColor, 0); 00245 unsigned char maxLuminosity = decode(RGBtoHSL(maxColor, C), 2); 00246 00247 unsigned char valueRed = minRed * (1 - position) + maxRed * position; 00248 unsigned char valueGreen = minGreen * (1 - position) + maxGreen * position; 00249 unsigned char valueBlue = minBlue * (1 - position) + maxBlue * position; 00250 unsigned char valueAlpha = minAlpha * (1 - position) + maxAlpha * position; 00251 unsigned char valueLuminosity = minLuminosity * (1 - position) + maxLuminosity * position; 00252 uint32_t valueColor = encode(0, valueRed, 3) + encode(0, valueGreen, 2) + encode(0, valueBlue, 1) + encode(0, valueAlpha, 0); 00253 valueColor = RGBtoHSL(valueColor, C); 00254 valueColor = HSLtoRGB(encode(valueColor, valueLuminosity, 2), &C); 00255 00256 gradient.insert(pair<float, int>(value, valueColor)); 00257 } 00258 00259 return gradient; 00260 } 00261 00262 float 00263 TetrisSchedule::defaultRatio() 00264 { 00265 return 4.0 / 3; 00266 } 00267 00268 float 00269 TetrisSchedule::defaultStrokeSize() 00270 { 00271 return 1; 00272 } 00273 00274 bool 00275 TetrisSchedule::defaultFrequencyLegend() 00276 { 00277 return true; 00278 } 00279 00280 vector<uint32_t> 00281 TetrisSchedule::defaultFrequencyColors() 00282 { 00283 double C; 00284 vector<uint32_t> colors; 00285 uint32_t darkRed = encode(0, 84, 3) + encode(0, 0, 2) + encode(0, 0, 1) + 255; 00286 RGBtoHSL(darkRed, C); 00287 uint32_t lightYellow = encode(0, 255, 3) + encode(0, 250, 2) + encode(0, 165, 1) + 255; 00288 RGBtoHSL(lightYellow, C); 00289 colors.push_back(lightYellow); 00290 colors.push_back(darkRed); 00291 00292 return colors; 00293 } 00294 00295 bool 00296 TetrisSchedule::defaultTaskLabel() 00297 { 00298 return false; 00299 } 00300 00301 bool 00302 TetrisSchedule::defaultTaskId() 00303 { 00304 return true; 00305 } 00306 00307 TetrisSchedule::TetrisSchedule() 00308 { 00309 this->ratio = defaultRatio(); 00310 this->showFrequencies = defaultFrequencyLegend(); 00311 this->showTaskId = defaultTaskId(); 00312 this->useTaskName = defaultTaskLabel(); 00313 this->colors = defaultFrequencyColors(); 00314 this->strokeSize = defaultStrokeSize(); 00315 } 00316 00317 TetrisSchedule::TetrisSchedule(float ratio, bool showFrequencies, bool showTaskId, bool useTaskName, vector<uint32_t> frequency_colors, float strokeSize) 00318 { 00319 this->ratio = ratio; 00320 this->showFrequencies = showFrequencies; 00321 this->colors = frequency_colors; 00322 this->showTaskId = showTaskId; 00323 this->useTaskName = useTaskName; 00324 this->strokeSize = strokeSize; 00325 } 00326 00327 TetrisSchedule::~TetrisSchedule() 00328 { 00329 // Do nothing 00330 } 00331 00332 void 00333 TetrisSchedule::dump(ostream& os, const Schedule &data, const Taskgraph &tg, const Platform &pt) const 00334 { 00335 dump(os, &data, &tg, &pt); 00336 } 00337 00338 // sigc callback class initialized with an output stream 00339 class Slot: public sigc::mem_functor2<ErrorStatus, Slot, const unsigned char*, uint32_t> 00340 { 00341 public: 00342 Slot(ostream &out): sigc::mem_functor2<ErrorStatus, Slot, const unsigned char* , uint32_t>(sigc::mem_functor2<ErrorStatus, Slot, const unsigned char*, uint32_t>(&Slot::write)) 00343 { 00344 this->out = &out; 00345 } 00346 00347 ErrorStatus 00348 write(const unsigned char* data, uint32_t length) 00349 { 00350 bool success = true; 00351 for(size_t i = 0; i < length && success; i++) 00352 { 00353 success = success && (*this->out << data[i]).good(); 00354 } 00355 00356 return success ? CAIRO_STATUS_SUCCESS: CAIRO_STATUS_WRITE_ERROR; 00357 }; 00358 00359 ErrorStatus 00360 operator()(const unsigned char* data, uint32_t length) 00361 { 00362 return write(data, length); 00363 } 00364 00365 private: 00366 ostream *out; 00367 }; 00368 00369 class Canvas 00370 { 00371 public: 00372 Canvas(double height, double width, double thickness, double magnify, map<float, uint32_t> colors, bool drawDeadline, bool showFrequencies) 00373 { 00374 this->height = height; 00375 this->width = width; 00376 this->thickness = thickness; 00377 this->magnify = magnify; 00378 this->colors = colors; 00379 this->drawDeadline = drawDeadline; 00380 this->showFrequencies = showFrequencies; 00381 } 00382 00383 void 00384 dump(ostream& os, const Schedule *sched, const Taskgraph *tg, const Platform *pt, bool show_task_id, bool useTaskName, float strokeSize) 00385 { 00386 #ifdef CAIRO_HAS_SVG_SURFACE 00387 // Compute canvas size, taking thickness and magnification into account 00388 this->magnify = height >= magnify ? magnify : magnify / height; 00389 height = height * this->magnify; 00390 this->absthick = thickness * height * strokeSize; 00391 this->height = height + absthick; 00392 this->width = width * this->magnify + absthick; 00393 00394 // Create cairo surface into svg output stream 00395 Slot slot(os); 00396 this->surface = SvgSurface::create_for_stream(slot, this->width, this->height); 00397 this->cr = Cairo::Context::create(surface); 00398 00399 // Partition drawing surface 00400 // Space for frequency legend 00401 if(this->showFrequencies) 00402 { 00403 size_t f = this->colors.size(); 00404 this->legend_size = (((this->height - this->absthick) / (f + 2))); // Space for legend 00405 } 00406 else 00407 { 00408 this->legend_size = 0; 00409 } 00410 // Space for y axis legend 00411 this->setFontSize(4 * this->absthick); 00412 cairo_text_extents_t te; 00413 cairo_font_extents_t fe; 00414 cr->select_font_face("Sans", FONT_SLANT_NORMAL, FONT_WEIGHT_BOLD); 00415 cr->get_text_extents("Time", te); 00416 cr->get_font_extents(fe); 00417 this->yaxis_size = 4 * absthick - te.y_bearing; 00418 00419 // Space between extreme-left and extreme-right tasks and extremities of barriers 00420 this->margin = 3 * absthick; 00421 size_t p = pt->getCores().size(); 00422 this->core_size = (this->width - absthick - this->margin * 2 - this->legend_size - this->yaxis_size) / p; 00423 00424 // Browse all tasks to determine the biggest font size that fits all tasks to draw 00425 double startSize = this->getHeight() > this->getWidth() ? this->getHeight() : this->getWidth(); 00426 double fontSize = startSize; 00427 for(set<Task>::iterator i = sched->getTasks().begin(); i != sched->getTasks().end(); i++) 00428 { 00429 Task task = *i; 00430 task.setWorkload(tg->getTasks().find(task)->getWorkload()); 00431 double runtime = task.runtime(i->getWidth(), i->getFrequency()); 00432 double width = i->getWidth(); 00433 string name; 00434 if(useTaskName) 00435 { 00436 name = i->getName(); 00437 } 00438 else 00439 { 00440 stringstream ss; 00441 ss << std::distance(sched->getTasks().begin(), i) + 1; 00442 name = ss.str(); 00443 } 00444 double idealSize = this->idealFontSize(runtime, width, name, startSize); 00445 if(idealSize <= fontSize) 00446 { 00447 fontSize = idealSize; 00448 } 00449 } 00450 00451 // Check out font size of frequency legend 00452 float legend_height = 0; 00453 float legend_font_size = 0; 00454 map<float, string> freq_labels; 00455 if(this->showFrequencies) 00456 { 00457 legend_height = this->legend_size; 00458 float legend_width = legend_height / this->core_size; 00459 legend_font_size = legend_height; 00460 for(map<float, uint32_t>::const_iterator i = this->colors.begin(); i != this->colors.end(); i++) 00461 { 00462 float freq = i->first * (*pt->getCores().begin())->getFrequencyUnit(); 00463 uint32_t letter_number = ((uint32_t)log10(freq)) / 3; 00464 float short_freq = freq; 00465 unsigned char letter; 00466 switch(letter_number) 00467 { 00468 case 0: 00469 letter = '\0'; 00470 break; 00471 case 1: 00472 letter = 'K'; 00473 short_freq /= 1000; 00474 break; 00475 case 2: 00476 letter = 'M'; 00477 short_freq /= 1000; 00478 short_freq /= 1000; 00479 break; 00480 case 3: 00481 letter = 'G'; 00482 short_freq /= 1000; 00483 short_freq /= 1000; 00484 short_freq /= 1000; 00485 break; 00486 break; 00487 case 4: 00488 letter = 'T'; 00489 short_freq /= 1000; 00490 short_freq /= 1000; 00491 short_freq /= 1000; 00492 short_freq /= 1000; 00493 break; 00494 default: 00495 letter = 'X'; 00496 break; 00497 } 00498 stringstream freq_label; 00499 if(letter != '\0') 00500 { 00501 freq_label << short_freq << letter; 00502 } 00503 else 00504 { 00505 freq_label << short_freq; 00506 } 00507 freq_labels.insert(pair<float, string>(freq, freq_label.str())); 00508 double ideal_legend_size = this->idealFontSize(legend_height, legend_width, freq_label.str(), (double)legend_height); 00509 if(ideal_legend_size < legend_font_size) 00510 { 00511 legend_font_size = ideal_legend_size; 00512 } 00513 } 00514 } 00515 00516 // Set the pen thickness and style 00517 cr->set_line_width(this->absthick); 00518 cr->set_line_cap(LINE_CAP_ROUND); 00519 cr->set_line_join(LINE_JOIN_ROUND); 00520 setColor(255); // solid black 00521 00522 // Draw y axis legend 00523 // Vertical line 00524 cr->move_to((te.height + this->yaxis_size + absthick) / 2, height - this->absthick * 2.5); 00525 cr->line_to((te.height + this->yaxis_size + absthick) / 2, this->absthick * 2.5); 00526 cr->stroke(); 00527 // Left arrow stroke 00528 cr->move_to((te.height + this->yaxis_size + absthick) / 2, this->absthick * 2.5); 00529 cr->line_to((te.height + this->yaxis_size + absthick) / 2 - this->absthick * 2, this->absthick * 6.5); 00530 cr->stroke(); 00531 // Right arrow stroke 00532 cr->move_to((te.height + this->yaxis_size + absthick) / 2, this->absthick * 2.5); 00533 cr->line_to((te.height + this->yaxis_size + absthick) / 2 + this->absthick * 2, this->absthick * 6.5); 00534 cr->stroke(); 00535 // Text 00536 cr->save(); 00537 this->setFontSize(4 * this->absthick); 00538 cr->move_to(-te.y_bearing, height / 2 + te.width / 2 - te.x_bearing); 00539 cr->translate(-te.y_bearing, height / 2 + te.width / 2 - te.x_bearing); 00540 cr->rotate_degrees(-90); 00541 cr->show_text("Time"); 00542 cr->restore(); 00543 00544 // Draw frequency legend 00545 if(this->showFrequencies) 00546 { 00547 for(map<float, uint32_t>::iterator i = this->colors.begin(); i != this->colors.end(); i++) 00548 { 00549 uint32_t color = i->second; 00550 size_t index = std::distance(this->colors.begin(), i); 00551 00552 cr->rectangle(this->width - legend_height - absthick / 2, legend_height * (index + 1) + absthick / 2, legend_height, legend_height); 00553 setColor(color); 00554 cr->fill_preserve(); 00555 setColor(255); 00556 cr->stroke(); 00557 00558 // Write Frequency 00559 float freq = i->first * (*pt->getCores().begin())->getFrequencyUnit(); 00560 cr->set_font_size(legend_font_size); 00561 cairo_text_extents_t te; 00562 cairo_font_extents_t fe; 00563 cr->select_font_face("Sans", FONT_SLANT_NORMAL, FONT_WEIGHT_BOLD); 00564 cr->get_font_extents(fe); 00565 cr->get_text_extents(freq_labels.find(freq)->second, te); 00566 cr->move_to(this->width - 0.5 * legend_height - te.width / 2 - absthick / 2 - te.x_bearing, legend_height * (index + 2) - legend_height / 2 - fe.descent + fe.height / 2 + absthick / 2); 00567 setColor(255); 00568 cr->show_text(freq_labels.find(freq)->second); 00569 } 00570 } 00571 00572 // Restore font size computed above 00573 this->setFontSize(fontSize); 00574 00575 // Browse all tasks in schedule to draw them 00576 map<Task, pair<size_t, size_t> > drawn; 00577 for(Schedule::table::const_iterator i = sched->getSchedule().begin(); i != sched->getSchedule().end(); i++) 00578 { 00579 for(Schedule::sequence::const_iterator j = i->second.begin(); j != i->second.end(); j++) 00580 { 00581 // Checks the number of core already covered when drawing this task 00582 Task task = *j->second.first; 00583 // done is the number of cores already drawn for the task 00584 // next is the first core after what has been already drawn for the task 00585 size_t done = 0, next = 1; 00586 size_t core = i->first; 00587 00588 // Find the task in the list of task already partially drawn 00589 if(drawn.find(task) != drawn.end()) 00590 { 00591 done = drawn.find(task)->second.first; 00592 next = drawn.find(task)->second.second; 00593 00594 // Remove task from list only if it will run again 00595 if(done < task.getWidth() && core >= next) 00596 { 00597 drawn.erase(drawn.find(task)); 00598 } 00599 } 00600 00601 // Draw the task only if all its core has not been drawn yet, 00602 // and if the current core is at least as high as the next allowed 00603 // core computed last time the task was partially drawn 00604 if(done < task.getWidth() && core >= next) 00605 { 00606 task.setWorkload(tg->getTasks().find(task)->getWorkload()); 00607 task.setMaxWidth(tg->getTasks().find(task)->getMaxWidth()); 00608 task.setEfficiencyString(tg->getTasks().find(task)->getEfficiencyString()); 00609 double runtime = task.runtime(task.getWidth(), task.getFrequency()); 00610 00611 // Looks for the number of cores through the task can be drawn in a continuous manner 00612 // Instead of the task's width, because mapping may not be to contiguous cores 00613 size_t width = 0; 00614 int counter = core - 1; 00615 for(Schedule::table::const_iterator k = i; k != sched->getSchedule().end(); k++, counter++) 00616 { 00617 bool task_found = false; 00618 for(Schedule::sequence::const_iterator l = k->second.begin(); l != k->second.end(); l++) 00619 { 00620 if(*l->second.first == task && k->first == counter + 1) 00621 { 00622 width++; 00623 task_found = true;; 00624 } 00625 } 00626 00627 if(!task_found) 00628 { 00629 break; 00630 } 00631 } 00632 double start = task.getStartTime(); 00633 string name; 00634 if(useTaskName) 00635 { 00636 name = task.getName(); 00637 } 00638 else 00639 { 00640 stringstream ss; 00641 ss << (std::distance(sched->getTasks().begin(), sched->getTasks().find(task)) + 1); 00642 name = ss.str(); 00643 } 00644 this->drawTask(runtime, width, task.getFrequency(), start, core, name, show_task_id); 00645 drawn.insert(pair<Task, pair<size_t, size_t> >(task, pair<size_t, size_t>(done + width, core + width))); 00646 } 00647 } 00648 } 00649 00650 // Draw final deadline, if necessary 00651 this->drawBarrier(0); 00652 if(drawDeadline) 00653 { 00654 this->drawBarrier(this->height - this->absthick); 00655 } 00656 #else 00657 #warning You must compile cairo with SVG support for this schedule output to work. 00658 #endif 00659 } 00660 00661 void 00662 drawTask(double time, double width, double frequency, double start, double firstCore, string label, bool show_task_id) 00663 { 00664 #ifdef CAIRO_HAS_SVG_SURFACE 00665 // Task rectangle 00666 cr->rectangle((firstCore - 1) * this->core_size + absthick / 2 + margin + yaxis_size, height - absthick / 2 - (start + time) * magnify, width * this->core_size, time * magnify); 00667 // Fill rectangle in solid red 00668 uint32_t color = this->colors.find(frequency)->second; 00669 setColor(color); 00670 cr->fill_preserve(); 00671 // Trace stroke in solid back 00672 setColor(255); 00673 cr->stroke(); 00674 00675 // Add task name 00676 if(this->fontSize > 0 && show_task_id) 00677 { 00678 cr->set_font_size(this->fontSize); 00679 cairo_text_extents_t te; 00680 cairo_font_extents_t fe; 00681 cr->select_font_face("Sans", FONT_SLANT_NORMAL, FONT_WEIGHT_BOLD); 00682 cr->get_font_extents(fe); 00683 cr->get_text_extents(label, te); 00684 // See http://www.cairographics.org/tutorial/ for more information on cairo text placement 00685 // Secont "Understanding text" 00686 cr->move_to( 00687 // Move along x 00688 absthick / 2 + // half the line thickness 00689 margin + // Extra length of beginning and end barriers over actual schedule 00690 this->yaxis_size + // Y axis legend space 00691 (firstCore - 1) * this->core_size + // Find the first core in which the task is being drawn 00692 this->core_size * width / 2 - // Middle of the task to be drawn 00693 te.width / 2 - te.x_bearing, // Half the the text length 00694 // Move along y 00695 height - // Whole height of the figure 00696 absthick / 2 - // Half of line thickness 00697 start * magnify - // Starting time of the task, time by magnification factor 00698 time * magnify / 2 - // Half of the task running time 00699 fe.descent + // Space in the text under the baseline where the font is applied (lower space necessary to draw letters p, gand j for example) 00700 fe.height / 2 // Height of the rest of the text 00701 ); 00702 setColor(255); 00703 cr->show_text(label); 00704 } 00705 #endif 00706 } 00707 00708 double 00709 idealFontSize(double time, double width, string label, double startSize) 00710 { 00711 #ifdef CAIRO_HAS_SVG_SURFACE 00712 double font_size = startSize; 00713 double delta = font_size; 00714 double minError = 0.5 * this->absthick; 00715 double maxError = 1 * this->absthick; 00716 00717 while(true) 00718 { 00719 cairo_text_extents_t te; 00720 cairo_font_extents_t fe; 00721 cr->set_font_size(font_size); 00722 cr->select_font_face("Sans", FONT_SLANT_NORMAL, FONT_WEIGHT_BOLD); 00723 cr->get_font_extents(fe); 00724 cr->get_text_extents(label, te); 00725 double text_width = te.width - te.x_bearing; 00726 double text_height = te.height; 00727 00728 if(((text_width >= (width * this->core_size - 2 * absthick - minError)) || (text_height >= (time * this->magnify - 2 * absthick - minError))) && delta > 0) 00729 { 00730 delta = delta / 2; 00731 font_size = font_size - delta; 00732 } 00733 else if(((text_width <= (width * this->core_size - 2 * absthick - maxError)) && (text_height <= (time * this->magnify - 2 * absthick - maxError))) && delta > 0) 00734 { 00735 font_size = font_size + delta; 00736 } 00737 else 00738 { 00739 return font_size; 00740 } 00741 } 00742 #endif 00743 } 00744 00745 void 00746 drawBarrier(double time) 00747 { 00748 #ifdef CAIRO_HAS_SVG_SURFACE 00749 //cr->move_to(this->absthick / 2 + this->yaxis_size, height - time * magnify - this->absthick / 2); 00750 //cr->line_to(width - this->absthick / 2 - legend_size, height - time * magnify - this->absthick / 2); 00751 cr->move_to(this->absthick / 2 + this->yaxis_size, height - time - this->absthick / 2); 00752 cr->line_to(width - this->absthick / 2 - legend_size, height - time - this->absthick / 2); 00753 setColor(255); // solid black 00754 cr->stroke(); 00755 #endif 00756 } 00757 00758 double 00759 getFontSize() const 00760 { 00761 return this->fontSize; 00762 } 00763 00764 void 00765 setFontSize(double size) 00766 { 00767 this->fontSize = size; 00768 this->cr->set_font_size(this->fontSize); 00769 } 00770 00771 double 00772 getWidth() const 00773 { 00774 return this->width; 00775 } 00776 00777 double 00778 getHeight() const 00779 { 00780 return this->height; 00781 } 00782 00783 protected: 00784 void 00785 setColor(uint32_t rgba) 00786 { 00787 cr->set_source_rgba((float)decode(rgba, 3) / 255, (float)decode(rgba, 2) / 255, (float)decode(rgba, 1) / 255, (float)decode(rgba, 0) / 255); 00788 } 00789 00790 float thickness; 00791 double magnify; 00792 double height; 00793 double width; 00794 double absthick; 00795 double core_size; 00796 double margin; 00797 double legend_size; 00798 double fontSize; 00799 double yaxis_size; 00800 bool drawDeadline; 00801 bool showFrequencies; 00802 map<float, uint32_t> colors; 00803 #ifdef CAIRO_HAS_SVG_SURFACE 00804 Cairo::RefPtr<Cairo::Context> cr; 00805 Cairo::RefPtr<Cairo::SvgSurface> surface; 00806 #endif 00807 }; 00808 00809 void 00810 TetrisSchedule::dump(ostream& os, const Schedule *sched, const Taskgraph *tg, const Platform *pt) const 00811 { 00812 set<float> frequencies; 00813 for(set<const Core*>::iterator i = pt->getCores().begin(); i != pt->getCores().end(); i++) 00814 { 00815 const Core *core = *i; 00816 for(set<float>::iterator j = core->getFrequencies().begin(); j != core->getFrequencies().end(); j++) 00817 { 00818 frequencies.insert(*j); 00819 } 00820 } 00821 00822 double thickness = 0.02; 00823 double magnify = 100; 00824 00825 Schedule::table schedule = sched->getSchedule(); 00826 00827 // Browse all tasks to find the time the last task stops 00828 double max_stop_time = 0; 00829 for(Schedule::table::const_iterator i = schedule.begin(); i != schedule.end(); i++) 00830 { 00831 for(Schedule::sequence::const_iterator j = i->second.begin(); j != i->second.end(); j++) 00832 { 00833 Task task = *j->second.first; 00834 task.setWorkload(tg->getTasks().find(task)->getWorkload()); 00835 task.setMaxWidth(tg->getTasks().find(task)->getMaxWidth()); 00836 task.setEfficiencyString(tg->getTasks().find(task)->getEfficiencyString()); 00837 double stop_time = task.getStartTime() + task.runtime(task.getWidth(), task.getFrequency()); 00838 if(stop_time > max_stop_time) 00839 { 00840 max_stop_time = stop_time; 00841 } 00842 } 00843 } 00844 00845 double deadline = tg->getDeadline(pt); 00846 bool drawDeadline = deadline > 0; 00847 deadline = deadline > 0 ? deadline : max_stop_time; 00848 Canvas(deadline, deadline * ratio, thickness, magnify, makeGradient(colors, frequencies), drawDeadline, this->showFrequencies).dump(os, sched, tg, pt, showTaskId, useTaskName, strokeSize); 00849 } 00850 00851 TetrisSchedule* 00852 TetrisSchedule::clone() const 00853 { 00854 return new TetrisSchedule(); 00855 } 00856