// 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"), CairoWidget(), SimulationObserver(), HistoryObserver(), _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; /** * bar spacing in y units */ _yu_process_bar_spacing = 1.0; /** * process bar height in y units */ _yu_process_bar_height = 1.0; /** * thread bar spacing in y units */ _yu_thread_bar_spacing = 0.4; /** * thread bar height in y units */ _yu_thread_bar_height = 0.2; } 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(); resize_redraw(); } void SimulationWidget::update(const History& changed_history) { // Force redraw //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 return; draw_names(ctx); draw_grid(ctx); draw_bars(ctx); } /* // 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; // bar spacing in y units _yu_process_bar_spacing = 1.0; // process bar height in y units _yu_process_bar_height = 1.0; // thread bar spacing in y units _yu_thread_bar_spacing = 0.2; // thread bar height in y units _yu_thread_bar_height = 0.6; */ void SimulationWidget::draw_names(cairo_t* ctx) { // std::cout << " SimulationWidget::draw_names " << std::endl; // 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; // margin + 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; // white row before text cairo_move_to(ctx, left_margin, ypos); cairo_show_text(ctx,p->get_name().c_str()); 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++; cairo_move_to(ctx, left_margin+_x_unit, ypos); cairo_show_text(ctx,t->get_name().c_str()); ypos += thread_height; // 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 int hist_size = hist.get_size(); const 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 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); // - 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(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(); const 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; 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; for(int t=1; 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_size; t++) } void SimulationWidget::draw_instant_rect(cairo_t* ctx, double x, double y, double w, double h, Schedulable::state state) { switch(state) { case Schedulable::state_running: cairo_set_source_rgb(ctx, 0, 1, 0); break; case Schedulable::state_ready: cairo_set_source_rgb(ctx, 1, 1, 0); break; case Schedulable::state_blocked: cairo_set_source_rgb(ctx, 1, 0, 0); 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) cairo_rectangle(ctx, x, y, w, h); cairo_fill(ctx); } // OLD - START *************** /* void SimulationWidget::draw_widget(cairo_t* ctx) { const History& hist = _simulation->get_history(); const Environment::Processes& processes = hist.get_last_environment().get_processes(); if(_n_proc<1) // nothing to draw return; double text_maxw = 0; bool* terminated = 0; double top_margin = _y_unit; double left_margin = _x_unit; double top_graph_margin = 1.0 * _y_unit; //3.0 * _y_unit; double left_graph_margin = 11.0 * _x_unit; double process_label_delta = 1.0 * _y_unit; double process_bar_delta = 1.0 * _y_unit; double process_bar_height = 1.0 * _y_unit; double process_height = process_bar_height + 2*process_bar_delta; double thread_bar_height = 1.0 * _y_unit; Simulation::state sim_state = _simulation->get_state(); cairo_text_extents_t extents; int item_index; if(_n_proc+_n_thr>0) terminated = new bool[_n_proc+_n_thr]; // show processes names... // set clip region to cut long names cairo_rectangle(ctx, 0, top_graph_margin, left_graph_margin - _x_unit, _n_proc*process_height + _n_thr*thread_bar_height); cairo_clip(ctx); // set the rectangular clip region { // draw schedulables names block item_index = 0; double ypos = top_graph_margin; // height of process bar const Environment::Processes& processes = hist.get_last_environment().get_processes(); Environment::Processes::const_iterator proc_iter = processes.begin(); while(proc_iter!=processes.end()) { Process* p = (*proc_iter); proc_iter++; ypos += process_bar_delta; // white row before cairo_move_to(ctx, left_margin, ypos); cairo_show_text(ctx,p->get_name().c_str()); ypos += process_bar_delta; // height of process bar terminated[item_index] = false; item_index++; 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++; cairo_move_to(ctx, left_margin+_x_unit, ypos); cairo_show_text(ctx,t->get_name().c_str()); ypos += thread_bar_height; // height of process bar terminated[item_index] = false; item_index++; } } ypos += process_bar_delta; // white row after } // ~ while(proc_iter!=processes.end()) } // ~ draw schedulables names block cairo_reset_clip(ctx); // remove clip region // std::cout << " draw_widget not_stop " << std::endl; unsigned int pos = _simulation->get_history().get_front(); // show grid cairo_save(ctx); cairo_set_line_width(ctx, 0.5*cairo_get_line_width(ctx)); // _n_proc+1 horizontal lines for(int i=0; i<=_n_proc; i++) { cairo_move_to(ctx, left_graph_margin, top_graph_margin + process_height*i); cairo_line_to(ctx, left_graph_margin + (pos+2)*_x_unit, top_graph_margin + process_height*i); } // opening vertical line cairo_move_to(ctx, left_graph_margin, top_graph_margin); cairo_line_to(ctx, left_graph_margin, top_graph_margin + process_height*_n_proc); cairo_stroke(ctx); // closing vertical line if(sim_state!=Simulation::state_stopped) { double dashes = 1.5; cairo_set_dash(ctx, &dashes, 1, 0.0); } cairo_move_to(ctx, left_graph_margin + (pos+2)*_x_unit, top_graph_margin); cairo_line_to(ctx, left_graph_margin + (pos+2)*_x_unit, top_graph_margin + process_height*_n_proc); cairo_stroke(ctx); cairo_restore(ctx); item_index = 0; for(int t=1; t<=pos; t++) { double ypos = top_graph_margin; const Environment::Processes& processes = hist.get_environment_at(t).get_processes(); double xpos = left_graph_margin + t*_x_unit; Environment::Processes::const_iterator proc_iter = processes.begin(); while(proc_iter!=processes.end()) { Process* p = (*proc_iter); proc_iter++; ypos += process_bar_delta; // space y before process bar Schedulable::state st = p->get_state(); // Schedulable::state st = processes[i]->get_state(); switch(st) { case Schedulable::state_running: cairo_set_source_rgb(ctx, 0, 1, 0); cairo_rectangle(ctx, xpos, ypos, _x_unit, _y_unit); cairo_fill(ctx); break; case Schedulable::state_ready: cairo_set_source_rgb(ctx, 1, 1, 0); cairo_rectangle(ctx, xpos, ypos, _x_unit, _y_unit); cairo_fill(ctx); break; case Schedulable::state_blocked: cairo_set_source_rgb(ctx, 1, 0, 0); cairo_rectangle(ctx, xpos, ypos, _x_unit, _y_unit); cairo_fill(ctx); break; case Schedulable::state_future: break; case Schedulable::state_terminated: if(!terminated[item_index]) { cairo_set_source_rgb(ctx, 0, 0, 0); cairo_rectangle(ctx, xpos, ypos, _x_unit, _y_unit); cairo_fill(ctx); } terminated[item_index] = true; break; } ypos += process_bar_delta; // height of process bar item_index++; 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++; Schedulable::state thr_state = t->get_state(); switch(thr_state) { case Schedulable::state_running: cairo_set_source_rgb(ctx, 0, 1, 0); cairo_rectangle(ctx, xpos, ypos+_y_unit/3.0, _x_unit, _y_unit/3.0); cairo_fill(ctx); break; case Schedulable::state_ready: cairo_set_source_rgb(ctx, 1, 1, 0); cairo_rectangle(ctx, xpos, ypos+_y_unit/3.0, _x_unit, _y_unit/3.0); cairo_fill(ctx); break; case Schedulable::state_blocked: cairo_set_source_rgb(ctx, 1, 0, 0); cairo_rectangle(ctx, xpos, ypos+_y_unit/3.0, _x_unit, _y_unit/3.0); cairo_fill(ctx); break; case Schedulable::state_future: break; case Schedulable::state_terminated: if(!terminated[item_index]) { cairo_set_source_rgb(ctx, 0, 0, 0); cairo_rectangle(ctx, xpos, ypos+_y_unit/3.0, _x_unit, _y_unit/3.0); cairo_fill(ctx); } terminated[item_index] = true; break; } // ~ switch(thr_state) - thread item_index++; ypos += thread_bar_height; // height of process bar } // ~ while(thr_iter!=tvect.end()) } } } // ~ for(int t=1; t<=pos; t++) delete[] terminated; } // ~ draw_widget // OLD - END ****************** */ 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; // std::cout << " x_unit: " << std::endl; 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(); } std::cout << " _n_proc=" << _n_proc << " _n_thr=" << _n_thr << std::endl; // count_elements(); }