// src/simulation_widget.cc - Copyright 2005, 2006, University // of Padova, dept. of Pure and Applied // Mathematics // // This file is part of SGPEMv2. // // This is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // SGPEMv2 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with SGPEMv2; if not, write to the Free Software // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "simulation_widget.hh" #include "cairo_elements.hh" #include "backend/history.hh" #include "backend/simulation.hh" #include "backend/string_utils.hh" #include #ifndef NDEBUG #include #endif using namespace sgpem; SimulationWidget::SimulationWidget(Simulation& simulation) : Glib::ObjectBase("sgpem_SimulationWidget"), SimulationObserver(), HistoryObserver(), CairoWidget(), _simulation(&simulation), _x_unit(10), _y_unit(10), _n_proc(0), _n_thr(0) { // Register this SimulationObserver: _simulation->attach(*this); // Register this HistoryObserver: _simulation->get_history().attach(*this); count_elements(); /** * top margin in y units */ _yu_top_margin = 1.0; /** * left margin in x units */ _xu_left_margin = 1.0; /** * left margin in x units */ _xu_left_graph_margin = 11.0; /** * process bar spacing in y units */ _yu_process_bar_spacing = 1.0; /** * process bar height in y units */ _yu_process_bar_height = 2.0; /** * thread bar spacing in y units */ _yu_thread_bar_spacing = 0.5; /** * thread bar height in y units */ _yu_thread_bar_height = 1.0; _ready_process_gradient = 0; _running_process_gradient = 0; _blocked_process_gradient = 0; _partial_redraw = false; _last_drawn = 0; } SimulationWidget::~SimulationWidget() { // Unregister this HistoryObserver: _simulation->get_history().detach(*this); // Unregister this SimulationObserver: _simulation->detach(*this); } void SimulationWidget::update(const Simulation& /* changed_simulation */ ) { // Force redraw //count_elements(); // nedd redraw only last _partial_redraw = true; // resize_redraw(); } void SimulationWidget::update(const History& /* changed_history */ ) { // Force redraw _last_drawn = 0; _partial_redraw = false; count_elements(); resize_redraw(); } bool SimulationWidget::get_show_threads() { return _show_threads; } bool SimulationWidget::set_show_threads(bool show) { bool old_show = _show_threads; _show_threads = show; // resize_redraw(); return old_show; } void SimulationWidget::draw_widget(cairo_t* ctx) { if(_n_proc<1) // nothing to draw { cairo_move_to(ctx, 10.0, 10.0); cairo_show_text(ctx, "Simulation Widget: nothing to draw..."); return; } draw_names(ctx); draw_grid(ctx); draw_bars(ctx); } void SimulationWidget::draw_names(cairo_t* ctx) { // show processes (and thread) names... // useful constants const History& hist = _simulation->get_history(); const double top_margin = _yu_top_margin * _y_unit; const double left_margin = _x_unit; // const double left_graph_margin = _xu_left_graph_margin * _x_unit; const double process_bar_spacing = _yu_process_bar_spacing * _y_unit; const double process_bar_height = _yu_process_bar_height * _y_unit; const double process_height = (_yu_process_bar_height + 2*_yu_process_bar_spacing) * _y_unit; const double thread_height = (2.0*_yu_thread_bar_spacing+_yu_thread_bar_height) * _y_unit; // const double graph_height = _n_proc * process_height + (_show_threads?_n_thr:0) * thread_height; // set a rectangular clip region to cut long names // - set the rectangle /* cairo_rectangle(ctx, 0, top_margin, left_graph_margin - left_margin, _n_proc*process_height + _n_thr*thread_height); // - set the clip region cairo_clip(ctx); */ // draw schedulables names double ypos = top_margin + _y_unit / 2.0; // margin + half of text height const Environment::Processes& processes = hist.get_last_environment().get_processes(); Environment::Processes::const_iterator proc_iter = processes.begin(); // - draw processes names while(proc_iter!=processes.end()) { Process* p = (*proc_iter); proc_iter++; ypos += process_bar_spacing + process_bar_height/2.0; // white row before text cairo_move_to(ctx, left_margin, ypos); cairo_show_text(ctx,p->get_name().c_str()); ypos += process_bar_height/2.0; // height of process bar if(_show_threads) { const std::vector& tvect = p->get_threads(); std::vector::const_iterator thr_iter = tvect.begin(); while(thr_iter!=tvect.end()) { Thread* t = (*thr_iter); thr_iter++; ypos += thread_height/2.0; cairo_move_to(ctx, left_margin+_x_unit, ypos); cairo_show_text(ctx,t->get_name().c_str()); ypos += thread_height/2.0; // height of thread bar } // ~ while(thr_iter!=tvect.end()) } // ~ if(_show_threads) ypos += process_bar_spacing; // white row after text } // ~ while(proc_iter!=processes.end()) // cairo_reset_clip(ctx); // remove clip region } void SimulationWidget::draw_grid(cairo_t* ctx) { // std::cout << " SimulationWidget::draw_grid p=" << _n_proc << " t=" << _n_thr << std::endl; // useful constants const History& hist = _simulation->get_history(); const unsigned int hist_front = hist.get_front() == 0 ? 0 : hist.get_front() - 1; const double top_margin = _yu_top_margin * _y_unit; // const double left_margin = _x_unit; const double left_graph_margin = _xu_left_graph_margin * _x_unit; // const double process_bar_spacing = _yu_process_bar_spacing * _y_unit; // const double process_bar_height = _yu_process_bar_height * _y_unit; const double process_height = (_yu_process_bar_height + 2*_yu_process_bar_spacing) * _y_unit; const double thread_height = (2.0*_yu_thread_bar_spacing+_yu_thread_bar_height) * _y_unit; const double graph_width = (2.0 + hist_front) * _x_unit; const double graph_height = _n_proc * process_height + (_show_threads?_n_thr:0) * thread_height; // draw graph grid double ypos = top_margin; const Environment::Processes& processes = hist.get_last_environment().get_processes(); Environment::Processes::const_iterator proc_iter = processes.begin(); // - draw all HOR lines while(proc_iter!=processes.end()) { Process* p = (*proc_iter); proc_iter++; // draw one (every) )HOR line cairo_move_to(ctx, left_graph_margin, ypos); cairo_rel_line_to(ctx, graph_width, 0); // calc next line position ypos += process_height; // skip a process heigh if(_show_threads) { int nt = p->get_threads().size(); // calc next line position (if thread) ypos += thread_height * nt; } // ~ if(_show_threads) } // ~ while(proc_iter!=processes.end()) // draw last HOR line cairo_move_to(ctx, left_graph_margin, ypos); cairo_rel_line_to(ctx, graph_width, 0); // - draw left VER line cairo_move_to(ctx, left_graph_margin, top_margin); cairo_rel_line_to(ctx, 0, graph_height); if(_simulation->get_state()==Simulation::state_stopped) { // - draw right VER line cairo_move_to(ctx, left_graph_margin + graph_width, top_margin); cairo_rel_line_to(ctx, 0, graph_height); } cairo_stroke(ctx); // draw and write time line cairo_save(ctx); cairo_set_source_rgb(ctx, 0, 0, 0); cairo_set_line_width(ctx, 0.25*cairo_get_line_width(ctx)); cairo_move_to(ctx, left_graph_margin, top_margin + graph_height + 2.0 * _y_unit); cairo_show_text(ctx,"T"); for(unsigned int t=0; t<=hist_front; t++) { cairo_move_to(ctx, left_graph_margin + (t+1)*_x_unit, top_margin + graph_height); cairo_rel_line_to(ctx, 0, 0.5 * _y_unit); Glib::ustring val; to_string(t, val); cairo_move_to(ctx, left_graph_margin + (t+1)*_x_unit, top_margin + graph_height + 2.0 * _y_unit); cairo_show_text(ctx,val.c_str()); } // ~ for(int t=0; t<=pos; t++) cairo_stroke(ctx); cairo_restore(ctx); } void SimulationWidget::draw_bars(cairo_t* ctx) { //std::cout << " SimulationWidget::draw_bars " << std::endl; // show processes (and thread) bars... // useful constants const History& hist = _simulation->get_history(); unsigned int hist_front = hist.get_front(); const double top_margin = _yu_top_margin * _y_unit; // const double left_margin = _x_unit; const double left_graph_margin = _xu_left_graph_margin * _x_unit; const double process_bar_spacing = _yu_process_bar_spacing * _y_unit; const double process_bar_height = _yu_process_bar_height * _y_unit; const double thread_bar_spacing = _yu_thread_bar_spacing * _y_unit; const double thread_bar_height = _yu_thread_bar_height * _y_unit; const double process_height = (_yu_process_bar_height + 2*_yu_process_bar_spacing) * _y_unit; const double thread_height = (2.0*_yu_thread_bar_spacing+_yu_thread_bar_height) * _y_unit; unsigned int from_time; // const double graph_width = (2.0 + hist_front) * _x_unit; // const double graph_height = _n_proc * process_height + (_show_threads?_n_thr:0) * thread_height; make_gradients(); if(_partial_redraw && _last_drawn>0) { from_time = _last_drawn; } else { from_time = 1; } // We draw the interval [0, front) // so if front <= 1, we've nothing to draw if(hist_front <= 1) return; else hist_front--; #ifndef NDEBUG std::cout << " SimulationWidget::draw_bars from:" << from_time << " to:" << hist_front << std::endl; #endif for(unsigned int t=from_time; t<=hist_front; t++) { // draw schedulables bars double xpos = left_graph_margin + t * _x_unit; // left start of first process double ypos = top_margin; // vertical start of first process const Environment::Processes& processes = hist.get_environment_at(t).get_processes(); Environment::Processes::const_iterator proc_iter = processes.begin(); // - draw processes names while(proc_iter!=processes.end()) { Process* p = (*proc_iter); proc_iter++; ypos += process_bar_spacing; // white row before bar draw_instant_rect(ctx, xpos, ypos, _x_unit, process_bar_height, p->get_state()); ypos += process_bar_height; // height of process bar if(_show_threads) { const std::vector& tvect = p->get_threads(); std::vector::const_iterator thr_iter = tvect.begin(); while(thr_iter!=tvect.end()) { Thread* t = (*thr_iter); thr_iter++; draw_instant_rect(ctx, xpos, ypos + thread_bar_spacing, _x_unit, thread_bar_height, t->get_state()); ypos += thread_height; // height of thread bar } // ~ while(thr_iter!=tvect.end()) } // ~ if(_show_threads) ypos += process_bar_spacing; // white row after bar } // ~ while(proc_iter!=processes.end()) } // ~ for(int t=0; t<=hist_front; t++) _last_drawn = hist_front; _partial_redraw = false; } void SimulationWidget::draw_instant_rect(cairo_t* ctx, double x, double y, double w, double h, Schedulable::state state) { cairo_matrix_t matrix; switch(state) { case Schedulable::state_running: // cairo_set_source_rgb(ctx, 0, 1, 0); cairo_save(ctx); cairo_set_source(ctx, _running_process_gradient); // cairo_matrix_init_scale(&matrix, 1.0, y); // cairo_matrix_translate(&matrix, 0, -y); cairo_matrix_init_translate(&matrix, 0, -y); cairo_pattern_set_matrix (_running_process_gradient, &matrix); cairo_rectangle(ctx, x, y, w, h); cairo_fill(ctx); cairo_restore(ctx); break; case Schedulable::state_ready: // cairo_set_source_rgb(ctx, 1, 1, 0); cairo_save(ctx); cairo_set_source(ctx, _ready_process_gradient); cairo_matrix_init_translate(&matrix, 0, -y); // cairo_matrix_scale(&matrix, 1.0, y); cairo_pattern_set_matrix (_ready_process_gradient, &matrix); cairo_rectangle(ctx, x, y, w, h); cairo_fill(ctx); cairo_restore(ctx); break; case Schedulable::state_blocked: // cairo_set_source_rgb(ctx, 1, 0, 0); cairo_save(ctx); cairo_set_source(ctx, _blocked_process_gradient); cairo_matrix_init_translate(&matrix, 0, -y); cairo_pattern_set_matrix (_blocked_process_gradient, &matrix); cairo_rectangle(ctx, x, y, w, h); cairo_fill(ctx); cairo_restore(ctx); break; case Schedulable::state_future: return; // don't draw break; case Schedulable::state_terminated: return; // don't draw // cairo_set_source_rgb(ctx, 0, 0, 0); break; } // ~ switch(state) } void SimulationWidget::calc_drawing_size(cairo_t* ctx, size_t& width, size_t& height) { if(!_simulation) return; const History& hist = _simulation->get_history(); // const Environment::Processes& processes = hist.get_last_environment().get_processes(); int pos = _simulation->get_history().get_front(); cairo_text_extents_t extents; Glib::ustring val("999"); cairo_text_extents(ctx, val.c_str(), &extents); if(_x_unitget_history(); const Environment& env = hist.get_last_environment(); // iter trough processes const Environment::Processes& pvect = env.get_processes(); _n_proc = pvect.size(); Environment::Processes::const_iterator proc_iter = pvect.begin(); while(proc_iter!=pvect.end()) { Process* p = (*proc_iter); proc_iter++; // if(_show_threads) _n_thr += p->get_threads().size(); } } void SimulationWidget::make_gradients() { _ready_process_gradient = cairo_pattern_create_linear(0, 0, 0, _yu_process_bar_height * _y_unit); // yellow cairo_pattern_add_color_stop_rgb(_ready_process_gradient, 0.0, 1.00, 1.00, 0.0); cairo_pattern_add_color_stop_rgb(_ready_process_gradient, 0.3, 0.85, 0.85, 0.0); cairo_pattern_add_color_stop_rgb(_ready_process_gradient, 1.0, 1.00, 1.00, 0.0); _running_process_gradient = cairo_pattern_create_linear(0, 0, 0, _yu_process_bar_height * _y_unit); // green cairo_pattern_add_color_stop_rgb(_running_process_gradient, 0.0, 0.0, 0.7, 0.0); cairo_pattern_add_color_stop_rgb(_running_process_gradient, 0.3, 0.0, 1.0, 0.0); cairo_pattern_add_color_stop_rgb(_running_process_gradient, 1.0, 0.0, 0.7, 0.0); _blocked_process_gradient = cairo_pattern_create_linear(0, 0, 0, _yu_process_bar_height * _y_unit); // red cairo_pattern_add_color_stop_rgb(_blocked_process_gradient, 0.0, 0.7, 0.0, 0.0); cairo_pattern_add_color_stop_rgb(_blocked_process_gradient, 0.3, 1.0, 0.0, 0.0); cairo_pattern_add_color_stop_rgb(_blocked_process_gradient, 1.0, 0.7, 0.0, 0.0); }