Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

pandatool/src/pstatserver/pStatStripChart.cxx

Go to the documentation of this file.
00001 // Filename: pStatStripChart.cxx
00002 // Created by:  drose (15Jul00)
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 "pStatStripChart.h"
00020 #include "pStatClientData.h"
00021 #include "pStatMonitor.h"
00022 
00023 #include <pStatFrameData.h>
00024 #include <pStatCollectorDef.h>
00025 #include <string_utils.h>
00026 #include <config_pstats.h>
00027 
00028 #include <algorithm>
00029 
00030 ////////////////////////////////////////////////////////////////////
00031 //     Function: PStatStripChart::Constructor
00032 //       Access: Public
00033 //  Description:
00034 ////////////////////////////////////////////////////////////////////
00035 PStatStripChart::
00036 PStatStripChart(PStatMonitor *monitor, PStatView &view,
00037                 int collector_index, int xsize, int ysize) :
00038   PStatGraph(monitor, xsize, ysize),
00039   _view(view),
00040   _collector_index(collector_index)
00041 {
00042   _scroll_mode = pstats_scroll_mode;
00043 
00044   _next_frame = 0;
00045   _first_data = true;
00046   _cursor_pixel = 0;
00047 
00048   _time_width = 20.0;
00049   _value_height = 1.0/10.0;
00050   _start_time = 0.0;
00051 
00052   _level_index = 0;
00053 
00054   const PStatClientData *client_data = _monitor->get_client_data();
00055   if (client_data->has_collector(_collector_index)) {
00056     const PStatCollectorDef &def = client_data->get_collector_def(_collector_index);
00057     _unit_name = def._level_units;
00058     if (!_unit_name.empty()) {
00059       _guide_bar_units = GBU_named;
00060     }
00061   }
00062 
00063   set_default_vertical_scale();
00064 }
00065 
00066 ////////////////////////////////////////////////////////////////////
00067 //     Function: PStatStripChart::Destructor
00068 //       Access: Public, Virtual
00069 //  Description:
00070 ////////////////////////////////////////////////////////////////////
00071 PStatStripChart::
00072 ~PStatStripChart() {
00073 }
00074 
00075 ////////////////////////////////////////////////////////////////////
00076 //     Function: PStatStripChart::new_data
00077 //       Access: Public
00078 //  Description: Indicates that new data has become available.
00079 ////////////////////////////////////////////////////////////////////
00080 void PStatStripChart::
00081 new_data(int frame_number) {
00082   // If the new frame is older than the last one we've drawn, we'll
00083   // need to back up and redraw it.  This can happen when frames
00084   // arrive out of order from the client.
00085   _next_frame = min(frame_number, _next_frame);
00086 }
00087 
00088 ////////////////////////////////////////////////////////////////////
00089 //     Function: PStatStripChart::update
00090 //       Access: Public
00091 //  Description: Updates the chart with the latest data.
00092 ////////////////////////////////////////////////////////////////////
00093 void PStatStripChart::
00094 update() {
00095   const PStatClientData *client_data = get_monitor()->get_client_data();
00096 
00097   // Don't bother to update the thread data until we know at least
00098   // something about the collectors and threads.
00099   if (client_data->get_num_collectors() != 0 &&
00100       client_data->get_num_threads() != 0) {
00101     const PStatThreadData *thread_data = _view.get_thread_data();
00102     if (!thread_data->is_empty()) {
00103       int latest = thread_data->get_latest_frame_number();
00104 
00105       if (latest > _next_frame) {
00106         draw_frames(_next_frame, latest);
00107       }
00108       _next_frame = latest;
00109 
00110       // Clean out the old data.
00111       float oldest_time =
00112         thread_data->get_frame(latest).get_start() - _time_width;
00113 
00114       Data::iterator di;
00115       di = _data.begin();
00116       while (di != _data.end() &&
00117              thread_data->get_frame((*di).first).get_start() < oldest_time) {
00118         _data.erase(di);
00119         di = _data.begin();
00120       }
00121     }
00122   }
00123 
00124   if (_level_index != _view.get_level_index()) {
00125     update_labels();
00126   }
00127 
00128   idle();
00129 }
00130 
00131 ////////////////////////////////////////////////////////////////////
00132 //     Function: PStatStripChart::first_data
00133 //       Access: Public
00134 //  Description: Returns true if the chart has seen its first data
00135 //               appear on it, false if it is still a virgin chart.
00136 ////////////////////////////////////////////////////////////////////
00137 bool PStatStripChart::
00138 first_data() const {
00139   return _first_data;
00140 }
00141 
00142 ////////////////////////////////////////////////////////////////////
00143 //     Function: PStatStripChart::set_default_vertical_scale
00144 //       Access: Public
00145 //  Description: Sets the vertical scale according to the suggested
00146 //               scale of the base collector, if any, or to center the
00147 //               target frame rate bar otherwise.
00148 ////////////////////////////////////////////////////////////////////
00149 void PStatStripChart::
00150 set_default_vertical_scale() {
00151   const PStatClientData *client_data = _monitor->get_client_data();
00152   if (client_data->has_collector(_collector_index)) {
00153     const PStatCollectorDef &def =
00154       client_data->get_collector_def(_collector_index);
00155     if (def._suggested_scale != 0.0) {
00156       set_vertical_scale(def._suggested_scale);
00157       return;
00158     }
00159   }
00160 
00161   set_vertical_scale(2.0 / get_target_frame_rate());
00162 }
00163 
00164 ////////////////////////////////////////////////////////////////////
00165 //     Function: PStatStripChart::set_auto_vertical_scale
00166 //       Access: Public
00167 //  Description: Sets the vertical scale to make all the data visible.
00168 ////////////////////////////////////////////////////////////////////
00169 void PStatStripChart::
00170 set_auto_vertical_scale() {
00171   const PStatThreadData *thread_data = _view.get_thread_data();
00172 
00173   float max_value = 0.0;
00174 
00175   int frame_number = -1;
00176   for (int x = 0; x <= _xsize; x++) {
00177     float time = pixel_to_timestamp(x);
00178     frame_number =
00179       thread_data->get_frame_number_at_time(time, frame_number);
00180 
00181     if (thread_data->has_frame(frame_number)) {
00182       const FrameData &frame = get_frame_data(frame_number);
00183 
00184       float overall_value = 0.0;
00185       FrameData::const_iterator fi;
00186       for (fi = frame.begin(); fi != frame.end(); ++fi) {
00187         const ColorData &cd = (*fi);
00188         overall_value += cd._net_value;
00189       }
00190       max_value = max(max_value, overall_value);
00191     }
00192   }
00193 
00194   // Ok, now we know what the max value visible in the chart is.
00195   // Choose a scale that will show all of this sensibly.
00196   if (max_value == 0.0) {
00197     set_vertical_scale(1.0);
00198   } else {
00199     set_vertical_scale(max_value * 1.1);
00200   }
00201 }
00202 
00203 ////////////////////////////////////////////////////////////////////
00204 //     Function: PStatStripChart::get_collector_under_pixel
00205 //       Access: Public
00206 //  Description: Return the collector index associated with the
00207 //               particular band of color at the indicated pixel
00208 //               location, or -1 if no band of color was at the pixel.
00209 ////////////////////////////////////////////////////////////////////
00210 int PStatStripChart::
00211 get_collector_under_pixel(int xpoint, int ypoint) {
00212   // First, we need to know what frame it was; to know that, we need
00213   // to determine the time corresponding to the x pixel.
00214   float time = pixel_to_timestamp(xpoint);
00215 
00216   // Now use that time to determine the frame.
00217   const PStatThreadData *thread_data = _view.get_thread_data();
00218   int frame_number = thread_data->get_frame_number_at_time(time);
00219 
00220   // And now we can determine which collector within the frame,
00221   // based on the value height.
00222   const FrameData &frame = get_frame_data(frame_number);
00223   float overall_value = 0.0;
00224   int y = get_ysize();
00225 
00226   FrameData::const_iterator fi;
00227   for (fi = frame.begin(); fi != frame.end(); ++fi) {
00228     const ColorData &cd = (*fi);
00229     overall_value += cd._net_value;
00230     y = height_to_pixel(overall_value);
00231     if (y <= ypoint) {
00232       return cd._collector_index;
00233     }
00234   }
00235 
00236   return -1;
00237 }
00238 
00239 ////////////////////////////////////////////////////////////////////
00240 //     Function: PStatStripChart::get_frame_data
00241 //       Access: Protected
00242 //  Description: Returns the cached FrameData associated with the
00243 //               given frame number.  This describes the lengths of
00244 //               the color bands for a single vertical stripe in the
00245 //               chart.
00246 ////////////////////////////////////////////////////////////////////
00247 const PStatStripChart::FrameData &PStatStripChart::
00248 get_frame_data(int frame_number) {
00249   Data::const_iterator di;
00250   di = _data.find(frame_number);
00251   if (di != _data.end()) {
00252     return (*di).second;
00253   }
00254 
00255   const PStatThreadData *thread_data = _view.get_thread_data();
00256   _view.set_to_frame(thread_data->get_frame(frame_number));
00257 
00258   FrameData &data = _data[frame_number];
00259 
00260   const PStatViewLevel *level = _view.get_level(_collector_index);
00261   int num_children = level->get_num_children();
00262   for (int i = 0; i < num_children; i++) {
00263     const PStatViewLevel *child = level->get_child(i);
00264     ColorData cd;
00265     cd._collector_index = child->get_collector();
00266     cd._net_value = child->get_net_value();
00267     if (cd._net_value != 0.0) {
00268       data.push_back(cd);
00269     }
00270   }
00271 
00272   // Also, there might be some value in the overall Collector that
00273   // wasn't included in all of the children.
00274   ColorData cd;
00275   cd._collector_index = level->get_collector();
00276   cd._net_value = level->get_value_alone();
00277   if (cd._net_value != 0.0) {
00278     data.push_back(cd);
00279   }
00280 
00281   return data;
00282 }
00283 
00284 ////////////////////////////////////////////////////////////////////
00285 //     Function: PStatStripChart::changed_size
00286 //       Access: Protected
00287 //  Description: To be called by the user class when the widget size
00288 //               has changed.  This updates the chart's internal data
00289 //               and causes it to issue redraw commands to reflect the
00290 //               new size.
00291 ////////////////////////////////////////////////////////////////////
00292 void PStatStripChart::
00293 changed_size(int xsize, int ysize) {
00294   if (xsize != _xsize || ysize != _ysize) {
00295     _cursor_pixel = xsize * _cursor_pixel / _xsize;
00296     _xsize = xsize;
00297     _ysize = ysize;
00298 
00299     if (!_first_data) {
00300       if (_scroll_mode) {
00301         draw_pixels(0, _xsize);
00302 
00303       } else {
00304         // Redraw the stats that were there before.
00305         float old_start_time = _start_time;
00306 
00307         // Back up a bit to draw the stuff to the right of the cursor.
00308         _start_time -= _time_width;
00309         draw_pixels(_cursor_pixel, _xsize);
00310 
00311         // Now draw the stuff to the left of the cursor.
00312         _start_time = old_start_time;
00313         draw_pixels(0, _cursor_pixel);
00314       }
00315     }
00316   }
00317 }
00318 
00319 ////////////////////////////////////////////////////////////////////
00320 //     Function: PStatStripChart::force_redraw
00321 //       Access: Protected
00322 //  Description: To be called by the user class when the whole thing
00323 //               needs to be redrawn for some reason.
00324 ////////////////////////////////////////////////////////////////////
00325 void PStatStripChart::
00326 force_redraw() {
00327   if (!_first_data) {
00328     draw_pixels(0, _xsize);
00329   }
00330 }
00331 
00332 ////////////////////////////////////////////////////////////////////
00333 //     Function: PStatStripChart::force_reset
00334 //       Access: Protected
00335 //  Description: To be called by the user class to cause the chart to
00336 //               reset to empty and start filling again.
00337 ////////////////////////////////////////////////////////////////////
00338 void PStatStripChart::
00339 force_reset() {
00340   clear_region();
00341   _first_data = true;
00342 }
00343 
00344 
00345 ////////////////////////////////////////////////////////////////////
00346 //     Function: PStatStripChart::clear_region
00347 //       Access: Protected, Virtual
00348 //  Description: Should be overridden by the user class to wipe out
00349 //               the entire strip chart region.
00350 ////////////////////////////////////////////////////////////////////
00351 void PStatStripChart::
00352 clear_region() {
00353 }
00354 
00355 ////////////////////////////////////////////////////////////////////
00356 //     Function: PStatStripChart::copy_region
00357 //       Access: Protected, Virtual
00358 //  Description: Should be overridden by the user class to copy a
00359 //               region of the chart from one part of the chart to
00360 //               another.  This is used to implement scrolling.
00361 ////////////////////////////////////////////////////////////////////
00362 void PStatStripChart::
00363 copy_region(int, int, int) {
00364 }
00365 
00366 ////////////////////////////////////////////////////////////////////
00367 //     Function: PStatStripChart::begin_draw
00368 //       Access: Protected, Virtual
00369 //  Description: Should be overridden by the user class.  This hook
00370 //               will be called before drawing any color bars in the
00371 //               strip chart; it gives the pixel range that's about to
00372 //               be redrawn.
00373 ////////////////////////////////////////////////////////////////////
00374 void PStatStripChart::
00375 begin_draw(int, int) {
00376 }
00377 
00378 ////////////////////////////////////////////////////////////////////
00379 //     Function: PStatStripChart::draw_slice
00380 //       Access: Protected, Virtual
00381 //  Description: Should be overridden by the user class to draw a
00382 //               single vertical slice in the strip chart at the
00383 //               indicated pixel, with the data for the indicated
00384 //               frame.  Call get_frame_data() to get the actual color
00385 //               data for the given frame_number.  This call will only
00386 //               be made between a corresponding call to begin_draw()
00387 //               and end_draw().
00388 ////////////////////////////////////////////////////////////////////
00389 void PStatStripChart::
00390 draw_slice(int, int) {
00391 }
00392 
00393 ////////////////////////////////////////////////////////////////////
00394 //     Function: PStatStripChart::draw_empty
00395 //       Access: Protected, Virtual
00396 //  Description: This is similar to draw_slice(), except it should
00397 //               draw a vertical line of the background color to
00398 //               represent a portion of the chart that has no data.
00399 ////////////////////////////////////////////////////////////////////
00400 void PStatStripChart::
00401 draw_empty(int) {
00402 }
00403 
00404 ////////////////////////////////////////////////////////////////////
00405 //     Function: PStatStripChart::draw_cursor
00406 //       Access: Protected, Virtual
00407 //  Description: This is similar to draw_slice(), except that it
00408 //               should draw the black vertical stripe that represents
00409 //               the current position when not in scrolling mode.
00410 ////////////////////////////////////////////////////////////////////
00411 void PStatStripChart::
00412 draw_cursor(int) {
00413 }
00414 
00415 ////////////////////////////////////////////////////////////////////
00416 //     Function: PStatStripChart::end_draw
00417 //       Access: Protected, Virtual
00418 //  Description: Should be overridden by the user class.  This hook
00419 //               will be called after drawing a series of color bars
00420 //               in the strip chart; it gives the pixel range that
00421 //               was just redrawn.
00422 ////////////////////////////////////////////////////////////////////
00423 void PStatStripChart::
00424 end_draw(int, int) {
00425 }
00426 
00427 ////////////////////////////////////////////////////////////////////
00428 //     Function: PStatStripChart::idle
00429 //       Access: Protected, Virtual
00430 //  Description: Should be overridden by the user class to perform any
00431 //               other updates might be necessary after the color bars
00432 //               have been redrawn.  For instance, it could check the
00433 //               state of _labels_changed, and redraw the labels if it
00434 //               is true.
00435 ////////////////////////////////////////////////////////////////////
00436 void PStatStripChart::
00437 idle() {
00438 }
00439 
00440 
00441 // STL function object for sorting labels in order by the collector's
00442 // sort index, used in update_labels(), below.
00443 class SortCollectorLabels2 {
00444 public:
00445   SortCollectorLabels2(const PStatClientData *client_data) :
00446     _client_data(client_data) {
00447   }
00448   bool operator () (int a, int b) const {
00449     return
00450       _client_data->get_collector_def(a)._sort >
00451       _client_data->get_collector_def(b)._sort;
00452   }
00453   const PStatClientData *_client_data;
00454 };
00455 
00456 ////////////////////////////////////////////////////////////////////
00457 //     Function: PStatStripChart::update_labels
00458 //       Access: Protected
00459 //  Description: Resets the list of labels.
00460 ////////////////////////////////////////////////////////////////////
00461 void PStatStripChart::
00462 update_labels() {
00463   const PStatViewLevel *level = _view.get_level(_collector_index);
00464   _labels.clear();
00465 
00466   int num_children = level->get_num_children();
00467   for (int i = 0; i < num_children; i++) {
00468     const PStatViewLevel *child = level->get_child(i);
00469     int collector = child->get_collector();
00470     _labels.push_back(collector);
00471   }
00472 
00473   SortCollectorLabels2 sort_labels(get_monitor()->get_client_data());
00474   sort(_labels.begin(), _labels.end(), sort_labels);
00475 
00476   int collector = level->get_collector();
00477   _labels.push_back(collector);
00478 
00479   _labels_changed = true;
00480   _level_index = _view.get_level_index();
00481 }
00482 
00483 ////////////////////////////////////////////////////////////////////
00484 //     Function: PStatStripChart::normal_guide_bars
00485 //       Access: Protected, Virtual
00486 //  Description: Calls update_guide_bars with parameters suitable to
00487 //               this kind of graph.
00488 ////////////////////////////////////////////////////////////////////
00489 void PStatStripChart::
00490 normal_guide_bars() {
00491   update_guide_bars(4, _value_height);
00492 }
00493 
00494 
00495 ////////////////////////////////////////////////////////////////////
00496 //     Function: PStatStripChart::draw_frames
00497 //       Access: Private
00498 //  Description: Draws the levels for the indicated frame range.
00499 ////////////////////////////////////////////////////////////////////
00500 void PStatStripChart::
00501 draw_frames(int first_frame, int last_frame) {
00502   const PStatThreadData *thread_data = _view.get_thread_data();
00503 
00504   last_frame = min(last_frame, thread_data->get_latest_frame_number());
00505 
00506   if (_first_data) {
00507     if (_scroll_mode) {
00508       _start_time =
00509         thread_data->get_frame(last_frame).get_start() - _time_width;
00510     } else {
00511       _start_time = thread_data->get_frame(first_frame).get_start();
00512       _cursor_pixel = 0;
00513     }
00514   }
00515 
00516   int first_pixel;
00517   if (thread_data->has_frame(first_frame)) {
00518     first_pixel =
00519       timestamp_to_pixel(thread_data->get_frame(first_frame).get_start());
00520   } else {
00521     first_pixel = 0;
00522   }
00523 
00524   int last_pixel =
00525     timestamp_to_pixel(thread_data->get_frame(last_frame).get_start());
00526 
00527   if (_first_data && !_scroll_mode) {
00528     first_pixel = min(_cursor_pixel, first_pixel);
00529   }
00530   _first_data = false;
00531 
00532   if (last_pixel - first_pixel >= _xsize) {
00533     // If we're drawing the whole thing all in this one swoop, just
00534     // start over.
00535     _start_time = thread_data->get_frame(last_frame).get_start() - _time_width;
00536     first_pixel = 0;
00537     last_pixel = _xsize;
00538   }
00539 
00540   if (last_pixel <= _xsize) {
00541     // It all fits in one block.
00542     _cursor_pixel = last_pixel;
00543     draw_pixels(first_pixel, last_pixel);
00544 
00545   } else {
00546     if (_scroll_mode) {
00547       // In scrolling mode, slide the world back.
00548       int slide_pixels = last_pixel - _xsize;
00549       copy_region(slide_pixels, first_pixel, 0);
00550       first_pixel -= slide_pixels;
00551       last_pixel -= slide_pixels;
00552       _start_time += (float)slide_pixels / (float)_xsize * _time_width;
00553       draw_pixels(first_pixel, last_pixel);
00554 
00555     } else {
00556       // In wrapping mode, do it in two blocks.
00557       _cursor_pixel = -1;
00558       draw_pixels(first_pixel, _xsize);
00559       _start_time = pixel_to_timestamp(_xsize);
00560       last_pixel -= _xsize;
00561       _cursor_pixel = last_pixel;
00562       draw_pixels(0, last_pixel);
00563     }
00564   }
00565 }
00566 
00567 ////////////////////////////////////////////////////////////////////
00568 //     Function: PStatStripChart::draw_pixels
00569 //       Access: Private
00570 //  Description: Draws the levels for the indicated pixel range.
00571 ////////////////////////////////////////////////////////////////////
00572 void PStatStripChart::
00573 draw_pixels(int first_pixel, int last_pixel) {
00574   begin_draw(first_pixel, last_pixel);
00575   const PStatThreadData *thread_data = _view.get_thread_data();
00576 
00577   int frame_number = -1;
00578   for (int x = first_pixel; x <= last_pixel; x++) {
00579     if (x == _cursor_pixel && !_scroll_mode) {
00580       draw_cursor(x);
00581 
00582     } else {
00583       float time = pixel_to_timestamp(x);
00584       frame_number = thread_data->get_frame_number_at_time(time, frame_number);
00585 
00586       if (thread_data->has_frame(frame_number)) {
00587         draw_slice(x, frame_number);
00588       } else {
00589         draw_empty(x);
00590       }
00591     }
00592   }
00593   end_draw(first_pixel, last_pixel);
00594 }

Generated on Fri May 2 03:21:40 2003 for Panda-Tool by doxygen1.3