// src/holt_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 "cairo_elements.hh" #include #include #include #include #include #include #include "holt_widget.hh" #include #include #include #include #ifndef NDEBUG #include #endif #include using namespace sgpem; using namespace std; #ifndef M_SQRT1_2 #define M_SQRT1_2 0.70710678118654752440 #endif #ifndef M_PI #define M_PI 3.14159265358979323846 #endif HoltNode::HoltNode(Vec2 pt) : _radius(20) { //_x = pt.real(); _y = pt.imag(); _pos = pt; } HoltNode::~HoltNode() { } Vec2 HoltNode::set_position(Vec2 pt) { Vec2 pt_old = _pos; _pos = pt; return pt_old; } Vec2 HoltNode::get_position() { return _pos; } double HoltNode::set_radius(double radius) { double old_rad = _radius; _radius = radius; return old_rad; } double HoltNode::get_radius() { return _radius; } // double HoltNode::_radius = 20; HoltResource::HoltResource(const Resource& resource, resource_key_t resource_key, Vec2 pt) : HoltNode(pt) { _resource = &resource; _resource_key = resource_key; } HoltResource::~HoltResource() { } void HoltResource::draw(cairo_t *cr) { static const Color white(1, 1, 1); static const float x_percent = 3.5f / 4; static const float y_percent = 4.5f / 5; CairoElements ce(cr); // outline cairo_set_source_rgb (cr, 0, 0, 0); // draw rectangle Rectangle area(_pos.real() - _radius, _pos.imag() - _radius, 2*_radius, 2*_radius); ce.draw_3dcube(area, white, x_percent, y_percent); cairo_save(cr); // clip text outside region cairo_rectangle(cr, _pos.real() - _radius, _pos.imag() - _radius, 2 * _radius * x_percent, 2 * _radius * y_percent); cairo_clip(cr); // draw text cairo_text_extents_t extents; cairo_text_extents(cr, _resource->get_name().c_str(), &extents); double xpos = _pos.real() - extents.width * (1 - x_percent + x_percent / 2); // left aligned if too large if(xpos<_pos.real() - _radius) xpos = _pos.real() - _radius; cairo_move_to(cr, xpos, _pos.imag() + extents.height * ((1 - y_percent) / 2 + 0.5) ); cairo_show_text(cr, _resource->get_name().c_str()); // stroke all cairo_stroke (cr); cairo_restore(cr); } Vec2 HoltResource::get_intersection_to(Vec2 pt) { Vec2 final = _pos; Vec2 segment = pt - _pos; double len = std::abs(segment); if(len>0) { // segment to unary modulus vector (versor) segment /= len; if(abs(segment.real())>=M_SQRT1_2) { // direction East(>0) or West(<0) segment *= _radius/abs(segment.real()); } else { // direction North(<0) or South(>0) segment *= _radius/abs(segment.imag()); } final = _pos + segment; } return final; } HoltSchedulable::HoltSchedulable(const Schedulable& schedulable, Vec2 pt) : HoltNode(pt) { _schedulable = &schedulable; } HoltSchedulable::~HoltSchedulable() { } void HoltSchedulable::draw(cairo_t *cr) { static const Color red(1, 0, 0); static const Color yellow(1, 0.8, 0); static const Color green(0, 1, 0); cairo_save(cr); // save context state const Point center(_pos.real(), _pos.imag()); const Color* color; // draw circle CairoElements cel(cr); // filling switch(_schedulable->get_state()) { case Schedulable::state_running: color = &green; break; case Schedulable::state_ready: color = &yellow; break; case Schedulable::state_blocked: color = &red; break; case Schedulable::state_future: case Schedulable::state_terminated: // should never get here assert((_schedulable->get_state() & (Schedulable::state_future | Schedulable::state_terminated)) == 0); } cel.draw_3dsphere(center, _radius, *color); // clip text outside region cairo_arc(cr, _pos.real(), _pos.imag(), _radius, 0, 2*M_PI); cairo_clip(cr); // draw text cairo_text_extents_t extents; cairo_text_extents(cr, _schedulable->get_name().c_str(), &extents); double text_width = extents.width; if(text_width>_radius*2.0) text_width=_radius*2.0; cairo_move_to(cr, _pos.real() - text_width/2, _pos.imag() + extents.height/2); cairo_show_text(cr, _schedulable->get_name().c_str()); // stroke all cairo_stroke (cr); cairo_restore(cr); // restore context state } Vec2 HoltSchedulable::get_intersection_to(Vec2 pt) { Vec2 final = _pos; Vec2 segment = pt - _pos; double len = std::abs(segment); if(len>0) { segment *= _radius/len; final = _pos + segment; } return final; } HoltRequest::HoltRequest(HoltSchedulable& hp, HoltResource& hr, Request::state state) : _hp(&hp), _hr(&hr), _state(state) { } HoltRequest::~HoltRequest() { } void HoltRequest::draw(cairo_t *cr) { Vec2 resource = _hp->get_intersection_to(_hr->get_position()); Vec2 schedulable = _hr->get_intersection_to(_hp->get_position()); cairo_save(cr); // cairo_set_line_width(cr, 0.5*cairo_get_line_width(cr)); switch(_state) { case Request::state_unallocable: // red cairo_set_source_rgb(cr, 1, 0, 0); arrow(cr, schedulable, resource); break; case Request::state_allocated: // green cairo_set_source_rgb(cr, 0, 1, 0); arrow(cr, resource, schedulable); break; case Request::state_future: break; case Request::state_exhausted: break; case Request::state_allocable: // yellow cairo_set_source_rgb(cr, 1, 0.7, 0); arrow(cr, schedulable, resource); break; } // stroke all cairo_stroke (cr); cairo_restore(cr); } void HoltRequest::arrow(cairo_t *cr, Vec2 first, Vec2 second) { cairo_move_to(cr, second.real(), second.imag()); cairo_line_to(cr, first.real(), first.imag()); Vec2 arrowside = second-first; arrowside *= 10.0/std::abs(arrowside); Vec2 deviation(5.0, 1.0); deviation /= std::abs(deviation);// = std::polar(1,M_PI/6.0); Vec2 side1 = arrowside * deviation; Vec2 side2 = arrowside * conj(deviation); cairo_move_to(cr, first.real(), first.imag()); cairo_line_to(cr, first.real()+side1.real(), first.imag()+side1.imag()); cairo_move_to(cr, first.real(), first.imag()); cairo_line_to(cr, first.real()+side2.real(), first.imag()+side2.imag()); } HoltWidget::HoltWidget(Simulation& simulation) : Glib::ObjectBase("sgpem_HoltWidget"), CairoWidget(), SimulationObserver(), HistoryObserver(), _simulation(&simulation), _n_proc(0), _n_res(0), _radius(20), _show_threads(false), _arrange_mode(arrange_horizontal) { // Register this SimulationObserver: _simulation->attach(*this); // Register this HistoryObserver: _simulation->get_history().attach(*this); } HoltWidget::~HoltWidget() { // Free allocated memory const HoltResources& const_holt_resources = _holt_resources; for(Iseq it = iseq(const_holt_resources); it; ++it) delete it->second; for_each_in(_holt_schedulables, memory::deletor()); for_each_in(_holt_requests, memory::deletor()); // Unregister this HistoryObserver: _simulation->get_history().detach(*this); // Unregister this SimulationObserver: _simulation->detach(*this); } double HoltWidget::get_radius() { return _arrange_mode; } double HoltWidget::set_radius(double radius) { double old_radius = _radius; if(radius>0) _radius = radius; // resize_redraw(); return old_radius; } HoltWidget::arrange_mode HoltWidget::get_arrange_mode() { return _arrange_mode; } HoltWidget::arrange_mode HoltWidget::set_arrange_mode(arrange_mode mode) { arrange_mode old_mode = _arrange_mode; _arrange_mode = mode; arrange(); // resize_redraw(); return old_mode; } void HoltWidget::arrange() { std::cout << "HoltWidget::arrange" << endl; // cout << "START:" << endl; // _x_req = 0; // _y_req = 0; Vec2 pos, inc, mul, cen; if(_arrange_mode==arrange_horizontal) { pos = Vec2(2*_radius, 2*_radius); inc = Vec2(3*_radius, 0); } else if(_arrange_mode==arrange_vertical) { pos = Vec2(2*_radius, 2*_radius); inc = Vec2(0, 3*_radius); } else // _arrange_mode==arrange_circular { int sx = _draw_w; // get_width(); int sy = _draw_h; // get_height(); int nelem = _holt_resources.size()+_holt_schedulables.size(); if(sx<=sy) inc = Vec2(sx/2-2*_radius, 0); else inc = Vec2(sy/2-2*_radius, 0); if(nelem>0) mul = Vec2(cos(2*M_PI/(double)nelem), sin(2*M_PI/(double)nelem)); else mul = Vec2(0,0); // cen = Vec2(sx/2, sy/2); cen = Vec2(2*_radius+inc.real(), 2*_radius+inc.real()); pos = inc + cen; // cout << "A) pos=" << pos << " cen=" << cen << " inc=" << inc << " mul=" << mul << endl; } HoltResources::const_iterator riter = _holt_resources.begin(); while(riter!=_holt_resources.end()) { HoltResource* hr = (*riter).second; // cout << "r-A) pos=" << pos << " cen=" << cen << " inc=" << inc << " mul=" << mul << endl; hr->set_position(pos); hr->set_radius(_radius); /* if(pos.real()+_radius>_x_req) _x_req = pos.real()+_radius; if(pos.imag()+_radius>_y_req) _y_req = pos.imag()+_radius; */ if(_arrange_mode!=arrange_circular) { pos += inc; } else // _arrange_mode==arrange_circular { inc *= mul; pos = cen + inc; } riter++; // cout << "r-B) pos=" << pos << " cen=" << cen << " inc=" << inc << " mul=" << mul << endl; } if(_arrange_mode==arrange_horizontal) { pos = Vec2(2*_radius, 8*_radius); inc = Vec2(3*_radius, 0); } else if(_arrange_mode==arrange_vertical) { pos = Vec2(8*_radius, 2*_radius); inc = Vec2(0, 3*_radius); } typedef HoltProcesses::const_iterator holt_proc_iterator; holt_proc_iterator piter = _holt_schedulables.begin(); while(piter!=_holt_schedulables.end()) { HoltSchedulable* hp = (*piter); // cout << "p-A) pos=" << pos << " cen=" << cen << " inc=" << inc << " mul=" << mul << endl; hp->set_position(pos); hp->set_radius(_radius); /* if(pos.real()+_radius>_x_req) _x_req = pos.real()+_radius; if(pos.imag()+_radius>_y_req) _y_req = pos.imag()+_radius; */ if(_arrange_mode!=arrange_circular) { pos += inc; } else // _arrange_mode==arrange_circular { inc *= mul; pos = cen + inc; } // cout << "p-B) pos=" << pos << " cen=" << cen << " inc=" << inc << " mul=" << mul << endl; piter++; } } bool HoltWidget::get_show_threads() { return _show_threads; } bool HoltWidget::set_show_threads(bool show) { bool old_show = _show_threads; _show_threads = show; // resize_redraw(); return old_show; } void HoltWidget::update(const Simulation& changed_simulation) { std::cout << "HoltWidget::update - Simulation" << endl; // Force redraw //redraw(); // acquire(); // resize_redraw(); } void HoltWidget::update(const History& changed_history) { std::cout << "HoltWidget::update - History" << endl; // Force redraw //redraw(); acquire(); resize_redraw(); } void HoltWidget::acquire() { std::cout << "HoltWidget::acquire" << endl; const HoltResources& const_holt_resources = _holt_resources; for(Iseq it = iseq(const_holt_resources); it; ++it) delete it->second; _holt_resources.clear(); for_each_in(_holt_schedulables, memory::deletor()); _holt_schedulables.clear(); for_each_in(_holt_requests, memory::deletor()); _holt_requests.clear(); _n_res = _n_proc = 0; const History& hist = _simulation->get_history(); const Environment& env = hist.get_last_environment(); Vec2 pos(2*_radius, 2*_radius); const Environment::Resources& rvect = env.get_resources(); Environment::Resources::const_iterator riter = rvect.begin(); while(riter!=rvect.end()) { resource_key_t index = (*riter).first; Resource* r = (*riter).second; HoltResource *hr = new HoltResource(*r, index, pos); HoltResources::iterator temp = _holt_resources.insert(std::pair(index, hr)).first; _n_res++; riter++; pos += Vec2(4*_radius, 0); } pos = Vec2(2*_radius, 8*_radius); // iter trough processes const Environment::Processes& pvect = env.get_processes(); Environment::Processes::const_iterator proc_iter = pvect.begin(); while(proc_iter!=pvect.end()) { Process* p = (*proc_iter); proc_iter++; Schedulable::state proc_state = p->get_state(); if(proc_state==Schedulable::state_running || proc_state==Schedulable::state_ready || proc_state==Schedulable::state_blocked ) { HoltSchedulable *hp; if(!_show_threads) { hp = new HoltSchedulable(*p, pos); _holt_schedulables.push_back(hp); pos += Vec2(4*_radius, 0); _n_proc++; } // iter trough threads, requests, subrequests // FIXME // typedef std::vector Threads; // typedef std::vector::const_iterator thr_iterator; 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++; /* os << " thread name: " << t->get_name() << " arrival_time: " << t->get_arrival_time() << " base_priority: " << t->get_base_priority() << endl; */ Schedulable::state thr_state = t->get_state(); if(thr_state==Schedulable::state_running || thr_state==Schedulable::state_ready || thr_state==Schedulable::state_blocked ) { if(_show_threads) { hp = new HoltSchedulable(*t, pos); _holt_schedulables.push_back(hp); pos += Vec2(4*_radius, 0); _n_proc++; } // iter trough requests const std::vector& rvect = t->get_requests(); std::vector::const_iterator req_iter = rvect.begin(); while(req_iter!=rvect.end()) { Request* r = (*req_iter); req_iter++; // os << " request arrival_time: " << r->get_instant() << endl; // iter trough subrequests const std::vector& srvect = r->get_subrequests(); std::vector::const_iterator subr_iter = srvect.begin(); while(subr_iter!=srvect.end()) { SubRequest* sr = (*subr_iter); subr_iter++; // os << " sub request: " /* << " resource_key: " << sr->get_resource_key() */; Request::state subr_state = sr->get_state(); if(subr_state==Request::state_unallocable || subr_state==Request::state_allocated || subr_state==Request::state_allocable ) { Environment::Resources::const_iterator pos = env.get_resources().find(sr->get_resource_key()); HoltResources::const_iterator hpos = _holt_resources.find(sr->get_resource_key()); if (pos != env.get_resources().end() && hpos!=_holt_resources.end()) { // associates process (or thread) with resource) HoltRequest *hreq = new HoltRequest(*hp, *(hpos->second), sr->get_state()); _holt_requests.push_back(hreq); // cout << "added HoltRequest\n" // os << " name: " << pos->second->get_name(); } } // ~ if(subr_state==Request::state_unallocable ... etc /* os << " length: " << sr->get_length(); os << " state: " << sr->get_state() << endl; */ } // ~ while(subr_iter!=srvect.end()) } // ~ while(req_iter!=rvect.end()) } // ~ if(thr_state==Schedulable::state_running ... } // ~ while(thr_iter!=tvect.end()) } // ~ if(proc_state==Schedulable::state_running ...etc } // arrange(); } void HoltWidget::draw_widget(cairo_t* ctx) { std::cout << "HoltWidget::draw_widget" << endl; // dispose objects arrange(); // draw text: T = n as title if(_draw_w>0) { const History& hist = _simulation->get_history(); const unsigned int hist_front = hist.get_front() == 0 ? 0 : hist.get_front() - 1; cairo_text_extents_t extents; stringstream ss; ss << "T = " << hist_front; cairo_text_extents(ctx, ss.str().c_str(), &extents); cairo_move_to(ctx, _draw_w/2 - extents.width/2.0, extents.height*2.0); cairo_show_text(ctx, ss.str().c_str()); cairo_stroke(ctx); } // draw all resources typedef HoltResources::const_iterator holt_res_iterator; holt_res_iterator riter = _holt_resources.begin(); while(riter!=_holt_resources.end()) { HoltResource* hr = (*riter).second; hr->draw(ctx); riter++; } // draw all schedulables typedef HoltProcesses::const_iterator holt_proc_iterator; holt_proc_iterator piter = _holt_schedulables.begin(); while(piter!=_holt_schedulables.end()) { HoltSchedulable* hp = (*piter); hp->draw(ctx); piter++; } // draw all arrows typedef HoltRequests::const_iterator holt_requ_iterator; holt_requ_iterator reqiter = _holt_requests.begin(); while(reqiter!=_holt_requests.end()) { HoltRequest* hreq = (*reqiter); hreq->draw(ctx); reqiter++; } } void HoltWidget::calc_drawing_size(cairo_t* ctx, size_t& width, size_t& height) { #ifndef DNDEBUG cout << "Holt widget BEFORE calc_drawing_size width=" << width << " height=" << height << endl; #endif // int pos = _simulation->get_front(); // const History& hist = _simulation->get_history(); int max = _n_proc; if(_n_res>_n_proc) max = _n_res; cairo_text_extents_t extents; // std::cout << " x_unit: " << std::endl; static const Glib::ustring val("Process 999 Resource 999"); cairo_text_extents(ctx, val.c_str(), &extents); _radius = extents.width/4.0; switch(_arrange_mode) { case arrange_horizontal: width = max * 4 * _radius; height = 10 * _radius; break; case arrange_vertical: width = 10 * _radius; height = max * 4 * _radius; break; case arrange_circular: int tot = (_n_proc + _n_res); double alpha = 0; if(tot>0) alpha = M_PI / tot; double side = 2 * sin(alpha/2); double diam = 4 * _radius; if(side>0) { diam = 4 * _radius / side; } if(diam<4 * _radius) diam = 4 * _radius; width = height = diam + 4 * _radius; break; } cout << "Holt widget AFTER calc_drawing_size width=" << width << " height=" << height << endl; } void HoltWidget::calc_widget_size(size_t& width, size_t& height) { cout << "Holt widget BEFORE calc_widget_size width=" << width << " height=" << height << endl; width = height = 20; // default minimum size }