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