Panda3D
|
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 }