Panda3D

pStatPianoRoll.cxx

00001 // Filename: pStatPianoRoll.cxx
00002 // Created by:  drose (18Jul00)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "pStatPianoRoll.h"
00016 
00017 #include "pStatFrameData.h"
00018 #include "pStatCollectorDef.h"
00019 #include "string_utils.h"
00020 #include "config_pstats.h"
00021 
00022 #include <algorithm>
00023 
00024 ////////////////////////////////////////////////////////////////////
00025 //     Function: PStatPianoRoll::BarBuilder::Constructor
00026 //       Access: Public
00027 //  Description: This class is used internally to build up the set of
00028 //               color bars defined by a frame's worth of data.
00029 ////////////////////////////////////////////////////////////////////
00030 PStatPianoRoll::BarBuilder::
00031 BarBuilder() {
00032   _is_new = true;
00033 }
00034 
00035 ////////////////////////////////////////////////////////////////////
00036 //     Function: PStatPianoRoll::BarBuilder::clear
00037 //       Access: Public
00038 //  Description: Resets the data in the BarBuilder for a new frame.
00039 ////////////////////////////////////////////////////////////////////
00040 void PStatPianoRoll::BarBuilder::
00041 clear() {
00042   _is_new = false;
00043   _color_bars.clear();
00044 }
00045 
00046 ////////////////////////////////////////////////////////////////////
00047 //     Function: PStatPianoRoll::BarBuilder::add_data_point
00048 //       Access: Public
00049 //  Description: Adds a new data point.  The first data point for a
00050 //               given collector turns in on (starts the bar), the
00051 //               second data point turns it off (ends the bar).
00052 ////////////////////////////////////////////////////////////////////
00053 void PStatPianoRoll::BarBuilder::
00054 add_data_point(double time, bool is_start) {
00055   if (is_start) {
00056     // This is a "start" data point: start the bar.
00057     if (_color_bars.empty() || _color_bars.back()._end >= 0.0) {
00058       ColorBar bar;
00059       bar._start = time;
00060       bar._end = -1.0;
00061       _color_bars.push_back(bar);
00062     }
00063 
00064   } else {
00065     // This is a "stop" data point: end the bar.
00066     if (_color_bars.empty()) {
00067       // A "stop" in the middle of the frame implies a "start" at time
00068       // 0.
00069       ColorBar bar;
00070       bar._start = 0.0;
00071       bar._end = time;
00072       _color_bars.push_back(bar);
00073 
00074     } else {
00075       _color_bars.back()._end = time;
00076     }
00077   }
00078 }
00079 
00080 ////////////////////////////////////////////////////////////////////
00081 //     Function: PStatPianoRoll::BarBuilder::finish
00082 //       Access: Public
00083 //  Description: Makes sure that each start-bar data point was matched
00084 //               by a corresponding end-bar data point.
00085 ////////////////////////////////////////////////////////////////////
00086 void PStatPianoRoll::BarBuilder::
00087 finish(double time) {
00088   if (!_color_bars.empty() && _color_bars.back()._end < 0.0) {
00089     _color_bars.back()._end = time;
00090   }
00091 }
00092 
00093 ////////////////////////////////////////////////////////////////////
00094 //     Function: PStatPianoRoll::Constructor
00095 //       Access: Public
00096 //  Description:
00097 ////////////////////////////////////////////////////////////////////
00098 PStatPianoRoll::
00099 PStatPianoRoll(PStatMonitor *monitor, int thread_index, int xsize, int ysize) :
00100   PStatGraph(monitor, xsize, ysize),
00101   _thread_index(thread_index)
00102 {
00103   _time_width = 1.0 / pstats_target_frame_rate;
00104   _start_time = 0.0;
00105 
00106   _current_frame = -1;
00107   _guide_bar_units = GBU_ms | GBU_hz | GBU_show_units;
00108   normal_guide_bars();
00109 }
00110 
00111 ////////////////////////////////////////////////////////////////////
00112 //     Function: PStatPianoRoll::Destructor
00113 //       Access: Public, Virtual
00114 //  Description:
00115 ////////////////////////////////////////////////////////////////////
00116 PStatPianoRoll::
00117 ~PStatPianoRoll() {
00118 }
00119 
00120 ////////////////////////////////////////////////////////////////////
00121 //     Function: PStatPianoRoll::update
00122 //       Access: Public
00123 //  Description: Updates the chart with the latest data.
00124 ////////////////////////////////////////////////////////////////////
00125 void PStatPianoRoll::
00126 update() {
00127   const PStatClientData *client_data = _monitor->get_client_data();
00128 
00129   // Don't bother to update the thread data until we know at least
00130   // something about the collectors and threads.
00131   if (client_data->get_num_collectors() != 0 &&
00132       client_data->get_num_threads() != 0) {
00133     const PStatThreadData *thread_data =
00134       client_data->get_thread_data(_thread_index);
00135     if (!thread_data->is_empty()) {
00136       int frame_number = thread_data->get_latest_frame_number();
00137       if (frame_number != _current_frame) {
00138         compute_page(thread_data->get_frame(frame_number));
00139         _current_frame = frame_number;
00140         force_redraw();
00141       }
00142     }
00143   }
00144 
00145   idle();
00146 }
00147 
00148 ////////////////////////////////////////////////////////////////////
00149 //     Function: PStatPianoRoll::changed_size
00150 //       Access: Protected
00151 //  Description: To be called by the user class when the widget size
00152 //               has changed.  This updates the chart's internal data
00153 //               and causes it to issue redraw commands to reflect the
00154 //               new size.
00155 ////////////////////////////////////////////////////////////////////
00156 void PStatPianoRoll::
00157 changed_size(int xsize, int ysize) {
00158   if (xsize != _xsize || ysize != _ysize) {
00159     _xsize = xsize;
00160     _ysize = ysize;
00161 
00162     normal_guide_bars();
00163     force_redraw();
00164   }
00165 }
00166 
00167 ////////////////////////////////////////////////////////////////////
00168 //     Function: PStatPianoRoll::force_redraw
00169 //       Access: Protected
00170 //  Description: To be called by the user class when the whole thing
00171 //               needs to be redrawn for some reason.
00172 ////////////////////////////////////////////////////////////////////
00173 void PStatPianoRoll::
00174 force_redraw() {
00175   if (!_labels.empty()) {
00176     begin_draw();
00177     for (int i = 0; i < (int)_labels.size(); i++) {
00178       int collector_index = _labels[i];
00179       const ColorBars &bars = _page_data[collector_index]._color_bars;
00180 
00181       begin_row(i);
00182       ColorBars::const_iterator bi;
00183       for (bi = bars.begin(); bi != bars.end(); ++bi) {
00184         const ColorBar &bar = (*bi);
00185         draw_bar(i, timestamp_to_pixel(bar._start), timestamp_to_pixel(bar._end));
00186       }
00187       end_row(i);
00188     }
00189     end_draw();
00190   }
00191 }
00192 
00193 ////////////////////////////////////////////////////////////////////
00194 //     Function: PStatPianoRoll::normal_guide_bars
00195 //       Access: Protected, Virtual
00196 //  Description: Calls update_guide_bars with parameters suitable to
00197 //               this kind of graph.
00198 ////////////////////////////////////////////////////////////////////
00199 void PStatPianoRoll::
00200 normal_guide_bars() {
00201   // We want vaguely 100 pixels between guide bars.
00202   update_guide_bars(get_xsize() / 100, _time_width);
00203 }
00204 
00205 ////////////////////////////////////////////////////////////////////
00206 //     Function: PStatPianoRoll::begin_draw
00207 //       Access: Protected, Virtual
00208 //  Description: Should be overridden by the user class.  This hook
00209 //               will be called before drawing any bars in the chart.
00210 ////////////////////////////////////////////////////////////////////
00211 void PStatPianoRoll::
00212 begin_draw() {
00213 }
00214 
00215 ////////////////////////////////////////////////////////////////////
00216 //     Function: PStatPianoRoll::begin_row
00217 //       Access: Protected, Virtual
00218 //  Description: Should be overridden by the user class.  This hook
00219 //               will be called before drawing any one row of bars.
00220 //               These bars correspond to the collector whose index is
00221 //               get_row_collector(row), and in the color
00222 //               get_row_color(row).
00223 ////////////////////////////////////////////////////////////////////
00224 void PStatPianoRoll::
00225 begin_row(int) {
00226 }
00227 
00228 ////////////////////////////////////////////////////////////////////
00229 //     Function: PStatPianoRoll::draw_bar
00230 //       Access: Protected, Virtual
00231 //  Description: Draws a single bar in the chart for the indicated
00232 //               row, in the color get_row_color(row), for the
00233 //               indicated horizontal pixel range.
00234 ////////////////////////////////////////////////////////////////////
00235 void PStatPianoRoll::
00236 draw_bar(int, int, int) {
00237 }
00238 
00239 ////////////////////////////////////////////////////////////////////
00240 //     Function: PStatPianoRoll::end_row
00241 //       Access: Protected, Virtual
00242 //  Description: Should be overridden by the user class.  This hook
00243 //               will be called after drawing a series of color bars
00244 //               for a single row.
00245 ////////////////////////////////////////////////////////////////////
00246 void PStatPianoRoll::
00247 end_row(int) {
00248 }
00249 
00250 ////////////////////////////////////////////////////////////////////
00251 //     Function: PStatPianoRoll::end_draw
00252 //       Access: Protected, Virtual
00253 //  Description: Should be overridden by the user class.  This hook
00254 //               will be called after drawing a series of color bars
00255 //               in the chart.
00256 ////////////////////////////////////////////////////////////////////
00257 void PStatPianoRoll::
00258 end_draw() {
00259 }
00260 
00261 ////////////////////////////////////////////////////////////////////
00262 //     Function: PStatPianoRoll::idle
00263 //       Access: Protected, Virtual
00264 //  Description: Should be overridden by the user class to perform any
00265 //               other updates might be necessary after the bars have
00266 //               been redrawn.
00267 ////////////////////////////////////////////////////////////////////
00268 void PStatPianoRoll::
00269 idle() {
00270 }
00271 
00272 
00273 // STL function object for sorting labels in order by the collector's
00274 // sort index, used in compute_page(), below.
00275 class SortCollectorLabels1 {
00276 public:
00277   SortCollectorLabels1(const PStatClientData *client_data) :
00278     _client_data(client_data) {
00279   }
00280   bool operator () (int a, int b) const {
00281     return
00282       _client_data->get_collector_def(a)._sort >
00283       _client_data->get_collector_def(b)._sort;
00284   }
00285   const PStatClientData *_client_data;
00286 };
00287 
00288 ////////////////////////////////////////////////////////////////////
00289 //     Function: PStatPianoRoll::compute_page
00290 //       Access: Private
00291 //  Description: Examines the given frame data and rebuilds the
00292 //               _page_data to match it.
00293 ////////////////////////////////////////////////////////////////////
00294 void PStatPianoRoll::
00295 compute_page(const PStatFrameData &frame_data) {
00296   _start_time = frame_data.get_start();
00297 
00298   // Clear out the page data and copy it to previous, so we can fill
00299   // it up again and then check to see if we changed the set of bars
00300   // this frame.
00301   PageData previous;
00302   _page_data.swap(previous);
00303 
00304   int num_events = frame_data.get_num_events();
00305   for (int i = 0; i < num_events; i++) {
00306     int collector_index = frame_data.get_time_collector(i);
00307     double time = frame_data.get_time(i);
00308     bool is_start = frame_data.is_start(i);
00309     _page_data[collector_index].add_data_point(time, is_start);
00310   }
00311 
00312   // Now check to see if the set of bars has changed.
00313   bool changed_bars = (_page_data.size() != previous.size());
00314 
00315   if (!changed_bars) {
00316     PageData::const_iterator ai, bi;
00317     ai = _page_data.begin();
00318     bi = previous.begin();
00319     while (ai != _page_data.end() && !changed_bars) {
00320       changed_bars = ((*ai).first == (*bi).first);
00321       ++ai;
00322       ++bi;
00323     }
00324   }
00325 
00326   if (changed_bars) {
00327     // If we added or removed some new bars this time, we'll have to
00328     // update our list.
00329     const PStatClientData *client_data = _monitor->get_client_data();
00330 
00331     _labels.clear();
00332     PageData::const_iterator pi;
00333     for (pi = _page_data.begin(); pi != _page_data.end(); ++pi) {
00334       int collector_index = (*pi).first;
00335       if (client_data->has_collector(collector_index)) {
00336         _labels.push_back(collector_index);
00337       }
00338     }
00339 
00340     SortCollectorLabels1 sort_labels(client_data);
00341     sort(_labels.begin(), _labels.end(), sort_labels);
00342 
00343     _labels_changed = true;
00344   }
00345 
00346   // Finally, make sure all of the bars are closed.
00347   double time = frame_data.get_end();
00348   PageData::iterator pi;
00349   for (pi = _page_data.begin(); pi != _page_data.end(); ++pi) {
00350     (*pi).second.finish(time);
00351   }
00352 }
 All Classes Functions Variables Enumerations