Panda3D
 All Classes Functions Variables Enumerations
pStatStripChart.cxx
00001 // Filename: pStatStripChart.cxx
00002 // Created by:  drose (15Jul00)
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 "pStatStripChart.h"
00016 #include "pStatClientData.h"
00017 #include "pStatMonitor.h"
00018 
00019 #include "pStatFrameData.h"
00020 #include "pStatCollectorDef.h"
00021 #include "string_utils.h"
00022 #include "config_pstats.h"
00023 
00024 #include <algorithm>
00025 
00026 ////////////////////////////////////////////////////////////////////
00027 //     Function: PStatStripChart::Constructor
00028 //       Access: Public
00029 //  Description:
00030 ////////////////////////////////////////////////////////////////////
00031 PStatStripChart::
00032 PStatStripChart(PStatMonitor *monitor, PStatView &view,
00033                 int thread_index, int collector_index, int xsize, int ysize) :
00034   PStatGraph(monitor, xsize, ysize),
00035   _thread_index(thread_index),
00036   _view(view),
00037   _collector_index(collector_index)
00038 {
00039   _scroll_mode = pstats_scroll_mode;
00040   _average_mode = false;
00041 
00042   _next_frame = 0;
00043   _first_data = true;
00044   _cursor_pixel = 0;
00045 
00046   _time_width = 20.0;
00047   _value_height = 1.0/10.0;
00048   _start_time = 0.0;
00049 
00050   _level_index = -1;
00051   _title_unknown = true;
00052 
00053   const PStatClientData *client_data = _monitor->get_client_data();
00054   if (client_data->has_collector(_collector_index)) {
00055     const PStatCollectorDef &def = client_data->get_collector_def(_collector_index);
00056     _unit_name = def._level_units;
00057   }
00058 
00059   set_default_vertical_scale();
00060 }
00061 
00062 ////////////////////////////////////////////////////////////////////
00063 //     Function: PStatStripChart::Destructor
00064 //       Access: Public, Virtual
00065 //  Description:
00066 ////////////////////////////////////////////////////////////////////
00067 PStatStripChart::
00068 ~PStatStripChart() {
00069 }
00070 
00071 ////////////////////////////////////////////////////////////////////
00072 //     Function: PStatStripChart::new_data
00073 //       Access: Public
00074 //  Description: Indicates that new data has become available.
00075 ////////////////////////////////////////////////////////////////////
00076 void PStatStripChart::
00077 new_data(int frame_number) {
00078   // If the new frame is older than the last one we've drawn, we'll
00079   // need to back up and redraw it.  This can happen when frames
00080   // arrive out of order from the client.
00081   _next_frame = min(frame_number, _next_frame);
00082 }
00083 
00084 ////////////////////////////////////////////////////////////////////
00085 //     Function: PStatStripChart::update
00086 //       Access: Public
00087 //  Description: Updates the chart with the latest data.
00088 ////////////////////////////////////////////////////////////////////
00089 void PStatStripChart::
00090 update() {
00091   const PStatClientData *client_data = get_monitor()->get_client_data();
00092 
00093   // Don't bother to update the thread data until we know at least
00094   // something about the collectors and threads.
00095   if (client_data->get_num_collectors() != 0 &&
00096       client_data->get_num_threads() != 0) {
00097     const PStatThreadData *thread_data = _view.get_thread_data();
00098     if (!thread_data->is_empty()) {
00099       int latest = thread_data->get_latest_frame_number();
00100 
00101       if (latest > _next_frame) {
00102         draw_frames(_next_frame, latest);
00103       }
00104       _next_frame = latest;
00105 
00106       // Clean out the old data.
00107       double oldest_time =
00108         thread_data->get_frame(latest).get_start() - _time_width;
00109 
00110       Data::iterator di;
00111       di = _data.begin();
00112       while (di != _data.end() &&
00113              thread_data->get_frame((*di).first).get_start() < oldest_time) {
00114         dec_label_usage((*di).second);
00115         _data.erase(di);
00116         di = _data.begin();
00117       }
00118     }
00119   }
00120 
00121   if (_level_index != _view.get_level_index()) {
00122     update_labels();
00123   }
00124 
00125   idle();
00126 }
00127 
00128 ////////////////////////////////////////////////////////////////////
00129 //     Function: PStatStripChart::first_data
00130 //       Access: Public
00131 //  Description: Returns true if the chart has seen its first data
00132 //               appear on it, false if it is still a virgin chart.
00133 ////////////////////////////////////////////////////////////////////
00134 bool PStatStripChart::
00135 first_data() const {
00136   return _first_data;
00137 }
00138 
00139 ////////////////////////////////////////////////////////////////////
00140 //     Function: PStatStripChart::set_collector_index
00141 //       Access: Public
00142 //  Description: Changes the collector represented by this strip
00143 //               chart.  This may force a redraw.
00144 ////////////////////////////////////////////////////////////////////
00145 void PStatStripChart::
00146 set_collector_index(int collector_index) {
00147   if (_collector_index != collector_index) {
00148     _collector_index = collector_index;
00149     _title_unknown = true;
00150     _data.clear();
00151     clear_label_usage();
00152     force_redraw();
00153     update_labels();
00154   }
00155 }
00156 
00157 ////////////////////////////////////////////////////////////////////
00158 //     Function: PStatStripChart::set_default_vertical_scale
00159 //       Access: Public
00160 //  Description: Sets the vertical scale according to the suggested
00161 //               scale of the base collector, if any, or to center the
00162 //               target frame rate bar otherwise.
00163 ////////////////////////////////////////////////////////////////////
00164 void PStatStripChart::
00165 set_default_vertical_scale() {
00166   const PStatClientData *client_data = _monitor->get_client_data();
00167   if (client_data->has_collector(_collector_index)) {
00168     const PStatCollectorDef &def =
00169       client_data->get_collector_def(_collector_index);
00170     if (def._suggested_scale != 0.0) {
00171       set_vertical_scale(def._suggested_scale);
00172       return;
00173     }
00174   }
00175 
00176   set_vertical_scale(2.0 / get_target_frame_rate());
00177 }
00178 
00179 ////////////////////////////////////////////////////////////////////
00180 //     Function: PStatStripChart::set_auto_vertical_scale
00181 //       Access: Public
00182 //  Description: Sets the vertical scale to make all the data visible.
00183 ////////////////////////////////////////////////////////////////////
00184 void PStatStripChart::
00185 set_auto_vertical_scale() {
00186   const PStatThreadData *thread_data = _view.get_thread_data();
00187 
00188   double max_value = 0.0;
00189 
00190   int frame_number = -1;
00191   for (int x = 0; x <= _xsize; x++) {
00192     double time = pixel_to_timestamp(x);
00193     frame_number =
00194       thread_data->get_frame_number_at_time(time, frame_number);
00195 
00196     if (thread_data->has_frame(frame_number)) {
00197       double net_value = get_net_value(frame_number);
00198       max_value = max(max_value, net_value);
00199     }
00200   }
00201 
00202   // Ok, now we know what the max value visible in the chart is.
00203   // Choose a scale that will show all of this sensibly.
00204   if (max_value == 0.0) {
00205     set_vertical_scale(1.0);
00206   } else {
00207     set_vertical_scale(max_value * 1.1);
00208   }
00209 }
00210 
00211 ////////////////////////////////////////////////////////////////////
00212 //     Function: PStatStripChart::get_collector_under_pixel
00213 //       Access: Public
00214 //  Description: Return the collector index associated with the
00215 //               particular band of color at the indicated pixel
00216 //               location, or -1 if no band of color was at the pixel.
00217 ////////////////////////////////////////////////////////////////////
00218 int PStatStripChart::
00219 get_collector_under_pixel(int xpoint, int ypoint) {
00220   // First, we need to know what frame it was; to know that, we need
00221   // to determine the time corresponding to the x pixel.
00222   double time = pixel_to_timestamp(xpoint);
00223 
00224   // Now use that time to determine the frame.
00225   const PStatThreadData *thread_data = _view.get_thread_data();
00226 
00227   // And now we can determine which collector within the frame,
00228   // based on the value height.
00229   if (_average_mode) {
00230     double start_time = pixel_to_timestamp(xpoint);
00231     int then_i = thread_data->get_frame_number_at_time(start_time - pstats_average_time);
00232     int now_i = thread_data->get_frame_number_at_time(start_time, then_i);
00233 
00234     FrameData fdata;
00235     compute_average_pixel_data(fdata, then_i, now_i, start_time);
00236     double overall_value = 0.0;
00237     int y = get_ysize();
00238     
00239     FrameData::const_iterator fi;
00240     for (fi = fdata.begin(); fi != fdata.end(); ++fi) {
00241       const ColorData &cd = (*fi);
00242       overall_value += cd._net_value;
00243       y = height_to_pixel(overall_value);
00244       if (y <= ypoint) {
00245         return cd._collector_index;
00246       }
00247     }
00248 
00249   } else {
00250     int frame_number = thread_data->get_frame_number_at_time(time);
00251     const FrameData &fdata = get_frame_data(frame_number);
00252     double overall_value = 0.0;
00253     int y = get_ysize();
00254     
00255     FrameData::const_iterator fi;
00256     for (fi = fdata.begin(); fi != fdata.end(); ++fi) {
00257       const ColorData &cd = (*fi);
00258       overall_value += cd._net_value;
00259       y = height_to_pixel(overall_value);
00260       if (y <= ypoint) {
00261         return cd._collector_index;
00262       }
00263     }
00264   }
00265     
00266   return -1;
00267 }
00268 
00269 ////////////////////////////////////////////////////////////////////
00270 //     Function: PStatStripChart::get_title_text
00271 //       Access: Private
00272 //  Description: Returns the text suitable for the title label on the
00273 //               top line.
00274 ////////////////////////////////////////////////////////////////////
00275 string PStatStripChart::
00276 get_title_text() {
00277   string text;
00278 
00279   _title_unknown = false;
00280 
00281   const PStatClientData *client_data = _monitor->get_client_data();
00282   if (client_data->has_collector(_collector_index)) {
00283     text = client_data->get_collector_fullname(_collector_index);
00284     const PStatCollectorDef &def = client_data->get_collector_def(_collector_index);
00285     if (_view.get_show_level()) {
00286       if (!def._level_units.empty()) {
00287         text += " (" + def._level_units + ")";
00288       }
00289     } else {
00290       text += " time";
00291     }
00292   } else {
00293     _title_unknown = true;
00294   }
00295 
00296   if (_thread_index != 0) {
00297     if (client_data->has_thread(_thread_index)) {
00298       text += " (" + client_data->get_thread_name(_thread_index) + " thread)";
00299     } else {
00300       _title_unknown = true;
00301     }
00302   }
00303 
00304   return text;
00305 }
00306 
00307 ////////////////////////////////////////////////////////////////////
00308 //     Function: PStatStripChart::is_title_unknown
00309 //       Access: Public
00310 //  Description: Returns true if get_title_text() has never yet
00311 //               returned an answer, false if it has.
00312 ////////////////////////////////////////////////////////////////////
00313 bool PStatStripChart::
00314 is_title_unknown() const {
00315   return _title_unknown;
00316 }
00317 
00318 ////////////////////////////////////////////////////////////////////
00319 //     Function: PStatStripChart::accumulate_frame_data
00320 //       Access: Protected, Static
00321 //  Description: Adds the data from additional into the data from
00322 //               fdata, after applying the scale weight.
00323 ////////////////////////////////////////////////////////////////////
00324 void PStatStripChart::
00325 accumulate_frame_data(FrameData &fdata, const FrameData &additional, 
00326                       double weight) {
00327   FrameData::iterator ai;
00328   FrameData::const_iterator bi;
00329 
00330   ai = fdata.begin();
00331   bi = additional.begin();
00332 
00333   FrameData result;
00334 
00335   if (fdata.size() == additional.size()) {
00336     // Start out assuming that fdata and additional contain exactly
00337     // the same set of collectors.  If we discover otherwise, we'll
00338     // have to bail at that point.
00339     while (ai != fdata.end() &&
00340            (*ai)._collector_index == (*bi)._collector_index) {
00341       (*ai)._net_value += ((*bi)._net_value * weight);
00342       ++ai;
00343       ++bi;
00344     }
00345 
00346     if (ai == fdata.end()) {
00347       // If we successfully reached the end of the list, great!
00348       // We're done without any merging.
00349       return;
00350     }
00351 
00352     // Otherwise, the two lists weren't identical.  In that case, copy
00353     // the accumulated data so far and continue from this point with
00354     // the full-blown merge.
00355     result.reserve(max(fdata.size(), additional.size()));
00356     FrameData::const_iterator ci;
00357     for (ci = fdata.begin(); ci != ai; ++ci) {
00358       result.push_back(*ci);
00359     }
00360 
00361   } else {
00362     // If the two lists had different lengths, clearly they aren't
00363     // identical.
00364     result.reserve(max(fdata.size(), additional.size()));
00365   }
00366 
00367   while (ai != fdata.end() && bi != additional.end()) {
00368     if ((*ai)._i < (*bi)._i) {
00369       // Here's a data value that's in data, but not in additional.
00370       result.push_back(*ai);
00371       ++ai;
00372 
00373     } else if ((*bi)._i < (*ai)._i) {
00374       // Here's a data value that's in additional, but not in data.
00375       ColorData scaled;
00376       scaled._collector_index = (*bi)._collector_index;
00377       scaled._i = (*bi)._i;
00378       scaled._net_value = (*bi)._net_value * weight;
00379       result.push_back(scaled);
00380       ++bi;
00381 
00382     } else {
00383       // Here's a data value that's in both.
00384       ColorData combined;
00385       combined._collector_index = (*ai)._collector_index;
00386       combined._i = (*bi)._i;
00387       combined._net_value = (*ai)._net_value + (*bi)._net_value * weight;
00388       result.push_back(combined);
00389       ++ai;
00390       ++bi;
00391     }
00392   }
00393 
00394   while (ai != fdata.end()) {
00395     // Here's a data value that's in data, but not in additional.
00396     result.push_back(*ai);
00397     ++ai;
00398   }
00399 
00400   while (bi != additional.end()) {
00401     // Here's a data value that's in additional, but not in data.
00402     ColorData scaled;
00403     scaled._collector_index = (*bi)._collector_index;
00404     scaled._i = (*bi)._i;
00405     scaled._net_value = (*bi)._net_value * weight;
00406     result.push_back(scaled);
00407     ++bi;
00408   }
00409 
00410   fdata.swap(result);
00411 }
00412 
00413 ////////////////////////////////////////////////////////////////////
00414 //     Function: PStatStripChart::scale_frame_data
00415 //       Access: Protected, Static
00416 //  Description: Applies the indicated scale to all collector values
00417 //               in data.
00418 ////////////////////////////////////////////////////////////////////
00419 void PStatStripChart::
00420 scale_frame_data(FrameData &fdata, double factor) {
00421   FrameData::iterator fi;
00422   for (fi = fdata.begin(); fi != fdata.end(); ++fi) {
00423     (*fi)._net_value *= factor;
00424   }
00425 }
00426 
00427 
00428 ////////////////////////////////////////////////////////////////////
00429 //     Function: PStatStripChart::get_frame_data
00430 //       Access: Protected
00431 //  Description: Returns the cached FrameData associated with the
00432 //               given frame number.  This describes the lengths of
00433 //               the color bands for a single vertical stripe in the
00434 //               chart.
00435 ////////////////////////////////////////////////////////////////////
00436 const PStatStripChart::FrameData &PStatStripChart::
00437 get_frame_data(int frame_number) {
00438   Data::const_iterator di;
00439   di = _data.find(frame_number);
00440   if (di != _data.end()) {
00441     return (*di).second;
00442   }
00443 
00444   const PStatThreadData *thread_data = _view.get_thread_data();
00445   _view.set_to_frame(thread_data->get_frame(frame_number));
00446 
00447   FrameData &fdata = _data[frame_number];
00448 
00449   const PStatViewLevel *level = _view.get_level(_collector_index);
00450   int num_children = level->get_num_children();
00451   for (int i = 0; i < num_children; i++) {
00452     const PStatViewLevel *child = level->get_child(i);
00453     ColorData cd;
00454     cd._collector_index = (unsigned short)child->get_collector();
00455     cd._i = (unsigned short)i;
00456     cd._net_value = child->get_net_value();
00457     if (cd._net_value != 0.0) {
00458       fdata.push_back(cd);
00459     }
00460   }
00461 
00462   // Also, there might be some value in the overall Collector that
00463   // wasn't included in all of the children.
00464   ColorData cd;
00465   cd._collector_index = (unsigned short)level->get_collector();
00466   cd._i = (unsigned short)num_children;
00467   cd._net_value = level->get_value_alone();
00468   if (cd._net_value > 0.0) {
00469     fdata.push_back(cd);
00470   }
00471 
00472   inc_label_usage(fdata);
00473 
00474   return fdata;
00475 }
00476 
00477 ////////////////////////////////////////////////////////////////////
00478 //     Function: PStatStripChart::compute_average_pixel_data
00479 //       Access: Protected
00480 //  Description: Fills the indicated FrameData structure with the
00481 //               color data for the indicated pixel, averaged over the
00482 //               past pstats_average_time seconds.
00483 //
00484 //               now is the timestamp for which we are computing the
00485 //               data; then_i and now_i are the frame numbers that
00486 //               bound (now - pstats_average_time) and now.  At
00487 //               function initialization time, these should be at or
00488 //               below the actual values; they will be incremented as
00489 //               needed by this function.  This allows the function to
00490 //               be called repeatedly for successive pixels.
00491 ////////////////////////////////////////////////////////////////////
00492 void PStatStripChart::
00493 compute_average_pixel_data(PStatStripChart::FrameData &result, 
00494                            int &then_i, int &now_i, double now) {
00495   result.clear();
00496 
00497   const PStatThreadData *thread_data = _view.get_thread_data();
00498   if (thread_data->is_empty() || thread_data->get_oldest_time() > now) {
00499     // No data.
00500     return;
00501   }
00502 
00503   double then = now - pstats_average_time;
00504 
00505   int latest_frame = thread_data->get_latest_frame_number();
00506   while (then_i <= latest_frame &&
00507          thread_data->get_frame(then_i).get_end() < then) {
00508     then_i++;
00509   }
00510   while (now_i <= latest_frame &&
00511          thread_data->get_frame(now_i).get_end() < now) {
00512     now_i++;
00513   }
00514 
00515   then = max(then, thread_data->get_frame(then_i).get_start());
00516 
00517   // Sum up a weighted average of all of the individual frames we
00518   // pass.
00519 
00520   // We start with just the portion of frame then_i that actually
00521   // does fall within our "then to now" window.
00522   accumulate_frame_data(result, get_frame_data(then_i), 
00523                         thread_data->get_frame(then_i).get_end() - then);
00524   double last = thread_data->get_frame(then_i).get_end();
00525 
00526   // Then we get all of each of the middle frames.
00527   for (int frame_number = then_i + 1; 
00528        frame_number < now_i; 
00529        frame_number++) {
00530     accumulate_frame_data(result, get_frame_data(frame_number),
00531                           thread_data->get_frame(frame_number).get_end() - last);
00532     last = thread_data->get_frame(frame_number).get_end();
00533   }
00534 
00535   // And finally, we get the remainder as now_i.
00536   if (last <= now) {
00537     accumulate_frame_data(result, get_frame_data(now_i), now - last);
00538   }
00539   
00540   scale_frame_data(result, 1.0f / (now - then));
00541 }
00542 
00543 ////////////////////////////////////////////////////////////////////
00544 //     Function: PStatStripChart::get_net_value
00545 //       Access: Protected
00546 //  Description: Returns the net value of the chart's collector for
00547 //               the indicated frame number.
00548 ////////////////////////////////////////////////////////////////////
00549 double PStatStripChart::
00550 get_net_value(int frame_number) const {
00551   const FrameData &frame = 
00552     ((PStatStripChart *)this)->get_frame_data(frame_number);
00553 
00554   double net_value = 0.0;
00555   FrameData::const_iterator fi;
00556   for (fi = frame.begin(); fi != frame.end(); ++fi) {
00557     const ColorData &cd = (*fi);
00558     net_value += cd._net_value;
00559   }
00560 
00561   return net_value;
00562 }
00563   
00564 ////////////////////////////////////////////////////////////////////
00565 //     Function: PStatStripChart::get_average_net_value
00566 //       Access: Protected
00567 //  Description: Computes the average value of the chart's collector
00568 //               over the past pstats_average_time number of seconds.
00569 ////////////////////////////////////////////////////////////////////
00570 double PStatStripChart::
00571 get_average_net_value() const {
00572   const PStatThreadData *thread_data = _view.get_thread_data();
00573   int now_i, then_i;
00574   if (!thread_data->get_elapsed_frames(then_i, now_i)) {
00575     return 0.0f;
00576   }
00577   double now = _time_width + _start_time;
00578   double then = now - pstats_average_time;
00579 
00580   int num_frames = now_i - then_i + 1;
00581 
00582   if (_collector_index == 0 && !_view.get_show_level()) {
00583     // If we're showing the time for the whole frame, compute this
00584     // from the total elapsed time, rather than summing up individual
00585     // frames.  This is more accurate and exactly matches what is
00586     // reported by thread_data->get_frame_rate().
00587 
00588     const PStatFrameData &now_frame_data = thread_data->get_frame(now_i);
00589     const PStatFrameData &then_frame_data = thread_data->get_frame(then_i);
00590     double now = now_frame_data.get_end();
00591     double elapsed_time = (now - then_frame_data.get_start());
00592     return elapsed_time / (double)num_frames;
00593 
00594   } else {
00595     // On the other hand, if we're showing the time for some
00596     // sub-frame, we have to do it the less-accurate way of summing up
00597     // individual frames, which might introduce errors if we are
00598     // missing data for some frames, but what can you do?
00599 
00600     const PStatThreadData *thread_data = _view.get_thread_data();
00601     
00602     double net_value = 0.0f;
00603     double net_time = 0.0f;
00604 
00605     // We start with just the portion of frame then_i that actually
00606     // does fall within our "then to now" window (usually some portion
00607     // of it will).
00608     if (thread_data->get_frame(then_i).get_end() > then) {
00609       double this_time = (thread_data->get_frame(then_i).get_end() - then);
00610       net_value += get_net_value(then_i) * this_time;
00611       net_time += this_time;
00612     }
00613     // Then we get all of each of the remaining frames.
00614     for (int frame_number = then_i + 1; 
00615          frame_number <= now_i; 
00616          frame_number++) {
00617       double this_time = thread_data->get_frame(frame_number).get_net_time();
00618       net_value += get_net_value(frame_number) * this_time;
00619       net_time += this_time;
00620     }
00621 
00622     return net_value / net_time;
00623   }
00624 }
00625 
00626 ////////////////////////////////////////////////////////////////////
00627 //     Function: PStatStripChart::changed_size
00628 //       Access: Protected
00629 //  Description: To be called by the user class when the widget size
00630 //               has changed.  This updates the chart's internal data
00631 //               and causes it to issue redraw commands to reflect the
00632 //               new size.
00633 ////////////////////////////////////////////////////////////////////
00634 void PStatStripChart::
00635 changed_size(int xsize, int ysize) {
00636   if (xsize != _xsize || ysize != _ysize) {
00637     _xsize = xsize;
00638     _ysize = ysize;
00639     if (_xsize > 0 && _ysize > 0) {
00640       _cursor_pixel = xsize * _cursor_pixel / _xsize;
00641 
00642       if (!_first_data) {
00643         if (_scroll_mode) {
00644           draw_pixels(0, _xsize);
00645 
00646         } else {
00647           // Redraw the stats that were there before.
00648           double old_start_time = _start_time;
00649 
00650           // Back up a bit to draw the stuff to the right of the cursor.
00651           _start_time -= _time_width;
00652           draw_pixels(_cursor_pixel, _xsize);
00653 
00654           // Now draw the stuff to the left of the cursor.
00655           _start_time = old_start_time;
00656           draw_pixels(0, _cursor_pixel);
00657         }
00658       }
00659     }
00660   }
00661 }
00662 
00663 ////////////////////////////////////////////////////////////////////
00664 //     Function: PStatStripChart::force_redraw
00665 //       Access: Protected
00666 //  Description: To be called by the user class when the whole thing
00667 //               needs to be redrawn for some reason.
00668 ////////////////////////////////////////////////////////////////////
00669 void PStatStripChart::
00670 force_redraw() {
00671   if (!_first_data) {
00672     draw_pixels(0, _xsize);
00673   }
00674 }
00675 
00676 ////////////////////////////////////////////////////////////////////
00677 //     Function: PStatStripChart::force_reset
00678 //       Access: Protected
00679 //  Description: To be called by the user class to cause the chart to
00680 //               reset to empty and start filling again.
00681 ////////////////////////////////////////////////////////////////////
00682 void PStatStripChart::
00683 force_reset() {
00684   clear_region();
00685   _first_data = true;
00686 }
00687 
00688 
00689 ////////////////////////////////////////////////////////////////////
00690 //     Function: PStatStripChart::clear_region
00691 //       Access: Protected, Virtual
00692 //  Description: Should be overridden by the user class to wipe out
00693 //               the entire strip chart region.
00694 ////////////////////////////////////////////////////////////////////
00695 void PStatStripChart::
00696 clear_region() {
00697 }
00698 
00699 ////////////////////////////////////////////////////////////////////
00700 //     Function: PStatStripChart::copy_region
00701 //       Access: Protected, Virtual
00702 //  Description: Should be overridden by the user class to copy a
00703 //               region of the chart from one part of the chart to
00704 //               another.  This is used to implement scrolling.
00705 ////////////////////////////////////////////////////////////////////
00706 void PStatStripChart::
00707 copy_region(int, int, int) {
00708 }
00709 
00710 ////////////////////////////////////////////////////////////////////
00711 //     Function: PStatStripChart::begin_draw
00712 //       Access: Protected, Virtual
00713 //  Description: Should be overridden by the user class.  This hook
00714 //               will be called before drawing any color bars in the
00715 //               strip chart; it gives the pixel range that's about to
00716 //               be redrawn.
00717 ////////////////////////////////////////////////////////////////////
00718 void PStatStripChart::
00719 begin_draw(int, int) {
00720 }
00721 
00722 ////////////////////////////////////////////////////////////////////
00723 //     Function: PStatStripChart::draw_slice
00724 //       Access: Protected, Virtual
00725 //  Description: Should be overridden by the user class to draw a
00726 //               single vertical slice in the strip chart at the
00727 //               indicated pixel, with the data for the indicated
00728 //               frame.  
00729 ////////////////////////////////////////////////////////////////////
00730 void PStatStripChart::
00731 draw_slice(int, int, const PStatStripChart::FrameData &fdata) {
00732 }
00733 
00734 ////////////////////////////////////////////////////////////////////
00735 //     Function: PStatStripChart::draw_empty
00736 //       Access: Protected, Virtual
00737 //  Description: This is similar to draw_slice(), except it should
00738 //               draw a vertical line of the background color to
00739 //               represent a portion of the chart that has no data.
00740 ////////////////////////////////////////////////////////////////////
00741 void PStatStripChart::
00742 draw_empty(int, int) {
00743 }
00744 
00745 ////////////////////////////////////////////////////////////////////
00746 //     Function: PStatStripChart::draw_cursor
00747 //       Access: Protected, Virtual
00748 //  Description: This is similar to draw_slice(), except that it
00749 //               should draw the black vertical stripe that represents
00750 //               the current position when not in scrolling mode.
00751 ////////////////////////////////////////////////////////////////////
00752 void PStatStripChart::
00753 draw_cursor(int) {
00754 }
00755 
00756 ////////////////////////////////////////////////////////////////////
00757 //     Function: PStatStripChart::end_draw
00758 //       Access: Protected, Virtual
00759 //  Description: Should be overridden by the user class.  This hook
00760 //               will be called after drawing a series of color bars
00761 //               in the strip chart; it gives the pixel range that
00762 //               was just redrawn.
00763 ////////////////////////////////////////////////////////////////////
00764 void PStatStripChart::
00765 end_draw(int, int) {
00766 }
00767 
00768 ////////////////////////////////////////////////////////////////////
00769 //     Function: PStatStripChart::idle
00770 //       Access: Protected, Virtual
00771 //  Description: Should be overridden by the user class to perform any
00772 //               other updates might be necessary after the color bars
00773 //               have been redrawn.  For instance, it could check the
00774 //               state of _labels_changed, and redraw the labels if it
00775 //               is true.
00776 ////////////////////////////////////////////////////////////////////
00777 void PStatStripChart::
00778 idle() {
00779 }
00780 
00781 
00782 // STL function object for sorting labels in order by the collector's
00783 // sort index, used in update_labels(), below.
00784 class SortCollectorLabels2 {
00785 public:
00786   SortCollectorLabels2(const PStatClientData *client_data) :
00787     _client_data(client_data) {
00788   }
00789   bool operator () (int a, int b) const {
00790     return
00791       _client_data->get_collector_def(a)._sort >
00792       _client_data->get_collector_def(b)._sort;
00793   }
00794   const PStatClientData *_client_data;
00795 };
00796 
00797 ////////////////////////////////////////////////////////////////////
00798 //     Function: PStatStripChart::update_labels
00799 //       Access: Protected, Virtual
00800 //  Description: Resets the list of labels.
00801 ////////////////////////////////////////////////////////////////////
00802 void PStatStripChart::
00803 update_labels() {
00804   const PStatViewLevel *level = _view.get_level(_collector_index);
00805   _labels.clear();
00806 
00807   int num_children = level->get_num_children();
00808   for (int i = 0; i < num_children; i++) {
00809     const PStatViewLevel *child = level->get_child(i);
00810     int collector_index = child->get_collector();
00811     if (is_label_used(collector_index)) {
00812       _labels.push_back(collector_index);
00813     }
00814   }
00815 
00816   SortCollectorLabels2 sort_labels(get_monitor()->get_client_data());
00817   sort(_labels.begin(), _labels.end(), sort_labels);
00818 
00819   int collector_index = level->get_collector();
00820   _labels.push_back(collector_index);
00821 
00822   _labels_changed = true;
00823   _level_index = _view.get_level_index();
00824 }
00825 
00826 ////////////////////////////////////////////////////////////////////
00827 //     Function: PStatStripChart::normal_guide_bars
00828 //       Access: Protected, Virtual
00829 //  Description: Calls update_guide_bars with parameters suitable to
00830 //               this kind of graph.
00831 ////////////////////////////////////////////////////////////////////
00832 void PStatStripChart::
00833 normal_guide_bars() {
00834   update_guide_bars(4, _value_height);
00835 }
00836 
00837 
00838 ////////////////////////////////////////////////////////////////////
00839 //     Function: PStatStripChart::draw_frames
00840 //       Access: Private
00841 //  Description: Draws the levels for the indicated frame range.
00842 ////////////////////////////////////////////////////////////////////
00843 void PStatStripChart::
00844 draw_frames(int first_frame, int last_frame) {
00845   const PStatThreadData *thread_data = _view.get_thread_data();
00846 
00847   last_frame = min(last_frame, thread_data->get_latest_frame_number());
00848 
00849   if (_first_data) {
00850     if (_scroll_mode) {
00851       _start_time =
00852         thread_data->get_frame(last_frame).get_start() - _time_width;
00853     } else {
00854       _start_time = thread_data->get_frame(first_frame).get_start();
00855       _cursor_pixel = 0;
00856     }
00857   }
00858 
00859   int first_pixel;
00860   if (thread_data->has_frame(first_frame)) {
00861     first_pixel =
00862       timestamp_to_pixel(thread_data->get_frame(first_frame).get_start());
00863   } else {
00864     first_pixel = 0;
00865   }
00866 
00867   int last_pixel =
00868     timestamp_to_pixel(thread_data->get_frame(last_frame).get_start());
00869 
00870   if (_first_data && !_scroll_mode) {
00871     first_pixel = min(_cursor_pixel, first_pixel);
00872   }
00873   _first_data = false;
00874 
00875   if (last_pixel - first_pixel >= _xsize) {
00876     // If we're drawing the whole thing all in this one swoop, just
00877     // start over.
00878     _start_time = thread_data->get_frame(last_frame).get_start() - _time_width;
00879     first_pixel = 0;
00880     last_pixel = _xsize;
00881   }
00882 
00883   if (last_pixel <= _xsize) {
00884     // It all fits in one block.
00885     _cursor_pixel = last_pixel;
00886     draw_pixels(first_pixel, last_pixel);
00887 
00888   } else {
00889     if (_scroll_mode) {
00890       // In scrolling mode, slide the world back.
00891       int slide_pixels = last_pixel - _xsize;
00892       copy_region(slide_pixels, first_pixel, 0);
00893       first_pixel -= slide_pixels;
00894       last_pixel -= slide_pixels;
00895       _start_time += (double)slide_pixels / (double)_xsize * _time_width;
00896       draw_pixels(first_pixel, last_pixel);
00897 
00898     } else {
00899       // In wrapping mode, do it in two blocks.
00900       _cursor_pixel = -1;
00901       draw_pixels(first_pixel, _xsize);
00902       _start_time = pixel_to_timestamp(_xsize);
00903       last_pixel -= _xsize;
00904       _cursor_pixel = last_pixel;
00905       draw_pixels(0, last_pixel);
00906     }
00907   }
00908 }
00909 
00910 ////////////////////////////////////////////////////////////////////
00911 //     Function: PStatStripChart::draw_pixels
00912 //       Access: Private
00913 //  Description: Draws the levels for the indicated pixel range.
00914 ////////////////////////////////////////////////////////////////////
00915 void PStatStripChart::
00916 draw_pixels(int first_pixel, int last_pixel) {
00917   begin_draw(first_pixel, last_pixel);
00918   const PStatThreadData *thread_data = _view.get_thread_data();
00919 
00920   if (_average_mode && !thread_data->is_empty()) {
00921     // In average mode, we have to calculate the average value for each pixel.
00922     double start_time = pixel_to_timestamp(first_pixel);
00923     int then_i = thread_data->get_frame_number_at_time(start_time - pstats_average_time);
00924     int now_i = thread_data->get_frame_number_at_time(start_time, then_i);
00925     for (int x = first_pixel; x <= last_pixel; x++) {
00926       if (x == _cursor_pixel && !_scroll_mode) {
00927         draw_cursor(x);
00928       } else {
00929         FrameData fdata;
00930         compute_average_pixel_data(fdata, then_i, now_i, pixel_to_timestamp(x));
00931         draw_slice(x, 1, fdata);
00932       }
00933     }
00934 
00935   } else {
00936     // When average mode is false, we are in frame mode; just show the
00937     // actual frame data.
00938     int frame_number = -1;
00939     int x = first_pixel;
00940     while (x <= last_pixel) {
00941       if (x == _cursor_pixel && !_scroll_mode) {
00942         draw_cursor(x);
00943         x++;
00944         
00945       } else {
00946         double time = pixel_to_timestamp(x);
00947         frame_number = thread_data->get_frame_number_at_time(time, frame_number);
00948         int w = 1;
00949         int stop_pixel = last_pixel;
00950         if (!_scroll_mode) {
00951           stop_pixel = min(stop_pixel, _cursor_pixel);
00952         }
00953         while (x + w < stop_pixel && 
00954                thread_data->get_frame_number_at_time(pixel_to_timestamp(x + w), frame_number) == frame_number) {
00955           w++;
00956         }
00957         if (thread_data->has_frame(frame_number)) {
00958           draw_slice(x, w, get_frame_data(frame_number));
00959         } else {
00960           draw_empty(x, w);
00961         }
00962         x += w;
00963       }
00964     }
00965   }
00966 
00967   end_draw(first_pixel, last_pixel);
00968 }
00969 
00970 ////////////////////////////////////////////////////////////////////
00971 //     Function: PStatStripChart::clear_label_usage
00972 //       Access: Private
00973 //  Description: Erases all elements from the label usage data.
00974 ////////////////////////////////////////////////////////////////////
00975 void PStatStripChart::
00976 clear_label_usage() {
00977   _label_usage.clear();
00978 }
00979 
00980 ////////////////////////////////////////////////////////////////////
00981 //     Function: PStatStripChart::dec_label_usage
00982 //       Access: Private
00983 //  Description: Erases the indicated frame data from the current
00984 //               label usage.  This indicates that the given FrameData
00985 //               has fallen off the end of the chart.  This must have
00986 //               been proceeded by an earlier call to
00987 //               inc_label_usage() for the same FrameData
00988 ////////////////////////////////////////////////////////////////////
00989 void PStatStripChart::
00990 dec_label_usage(const FrameData &fdata) {
00991   FrameData::const_iterator fi;
00992   for (fi = fdata.begin(); fi != fdata.end(); ++fi) {
00993     const ColorData &cd = (*fi);
00994     nassertv(cd._collector_index < (int)_label_usage.size());
00995     nassertv(_label_usage[cd._collector_index] > 0);
00996     _label_usage[cd._collector_index]--;
00997     if (_label_usage[cd._collector_index] == 0) {
00998       // If a label drops out of usage, it's time to regenerate
00999       // labels.
01000       _level_index = -1;
01001     }
01002   }
01003 }
01004 
01005 ////////////////////////////////////////////////////////////////////
01006 //     Function: PStatStripChart::inc_label_usage
01007 //       Access: Private
01008 //  Description: Records the labels named in the indicated FrameData
01009 //               in the table of current labels in use.  This should
01010 //               be called when the given FrameData has been added to
01011 //               the chart; it will increment the reference count for
01012 //               each collector named in the FrameData.  The reference
01013 //               count will eventually be decremented when
01014 //               dec_label_usage() is called later.
01015 ////////////////////////////////////////////////////////////////////
01016 void PStatStripChart::
01017 inc_label_usage(const FrameData &fdata) {
01018   FrameData::const_iterator fi;
01019   for (fi = fdata.begin(); fi != fdata.end(); ++fi) {
01020     const ColorData &cd = (*fi);
01021     while (cd._collector_index >= (int)_label_usage.size()) {
01022       _label_usage.push_back(0);
01023     }
01024     nassertv(_label_usage[cd._collector_index] >= 0);
01025     _label_usage[cd._collector_index]++;
01026     if (_label_usage[cd._collector_index] == 1) {
01027       // If a label appears for the first time, it's time to
01028       // regenerate labels.
01029       _level_index = -1;
01030     }
01031   }
01032 }
 All Classes Functions Variables Enumerations