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

pandatool/src/pstatserver/pStatView.cxx

Go to the documentation of this file.
00001 // Filename: pStatView.cxx
00002 // Created by:  drose (10Jul00)
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 "pStatView.h"
00020 
00021 #include "pStatFrameData.h"
00022 #include "pStatCollectorDef.h"
00023 #include "vector_int.h"
00024 #include "plist.h"
00025 #include "pset.h"
00026 
00027 #include <algorithm>
00028 
00029 
00030 
00031 ////////////////////////////////////////////////////////////////////
00032 //       Class : FrameSample
00033 // Description : This class is used within this module only--in fact,
00034 //               within PStatView::set_to_frame() only--to help
00035 //               collect event data out of the PStatFrameData object
00036 //               and boil it down to a list of elapsed times.
00037 ////////////////////////////////////////////////////////////////////
00038 class FrameSample {
00039 public:
00040   typedef plist<FrameSample *> Started;
00041 
00042   FrameSample() {
00043     _touched = false;
00044     _is_started = false;
00045     _pushed = false;
00046     _net_time = 0.0;
00047   }
00048   void data_point(float time, bool is_start, Started &started) {
00049     _touched = true;
00050 
00051     // We only consider events that change the start/stop state.
00052     // With two consecutive 'start' events, for instance, we ignore
00053     // the second one.
00054 
00055     // *** That's not quite the right thing to do.  We should keep
00056     // track of the nesting level and bracket things correctly, so
00057     // that we ignore the second start and the *first* stop, but
00058     // respect the outer start/stop.  For the short term, this
00059     // works, because the client is already doing this logic and
00060     // won't send us nested start/stop pairs, but we'd like to
00061     // generalize this in the future so we can deal with these
00062     // nested pairs properly.
00063     nassertv(is_start != _is_started);
00064 
00065     _is_started = is_start;
00066 
00067     if (_pushed) {
00068       nassertv(!_is_started);
00069       Started::iterator si = find(started.begin(), started.end(), this);
00070       nassertv(si != started.end());
00071       started.erase(si);
00072 
00073     } else {
00074       if (_is_started) {
00075         _net_time -= time;
00076         push_all(time, started);
00077         started.push_back(this);
00078       } else {
00079         _net_time += time;
00080         Started::iterator si = find(started.begin(), started.end(), this);
00081         nassertv(si != started.end());
00082         started.erase(si);
00083         pop_one(time, started);
00084       }
00085     }
00086   }
00087   void push(float time) {
00088     if (!_pushed) {
00089       _pushed = true;
00090       if (_is_started) {
00091         _net_time += time;
00092       }
00093     }
00094   }
00095   void pop(float time) {
00096     if (_pushed) {
00097       _pushed = false;
00098       if (_is_started) {
00099         _net_time -= time;
00100       }
00101     }
00102   }
00103 
00104   void push_all(float time, Started &started) {
00105     Started::iterator si;
00106     for (si = started.begin(); si != started.end(); ++si) {
00107       (*si)->push(time);
00108     }
00109   }
00110 
00111   void pop_one(float time, Started &started) {
00112     Started::reverse_iterator si;
00113     for (si = started.rbegin(); si != started.rend(); ++si) {
00114       if ((*si)->_pushed) {
00115         (*si)->pop(time);
00116         return;
00117       }
00118     }
00119   }
00120 
00121   bool _touched;
00122   bool _is_started;
00123   bool _pushed;
00124   float _net_time;
00125 };
00126 
00127 
00128 
00129 ////////////////////////////////////////////////////////////////////
00130 //     Function: PStatView::Constructor
00131 //       Access: Public
00132 //  Description:
00133 ////////////////////////////////////////////////////////////////////
00134 PStatView::
00135 PStatView() {
00136   _constraint = 0;
00137   _show_level = false;
00138   _all_collectors_known = false;
00139   _level_index = 0;
00140 }
00141 
00142 ////////////////////////////////////////////////////////////////////
00143 //     Function: PStatView::Destructor
00144 //       Access: Public
00145 //  Description:
00146 ////////////////////////////////////////////////////////////////////
00147 PStatView::
00148 ~PStatView() {
00149   clear_levels();
00150 }
00151 
00152 ////////////////////////////////////////////////////////////////////
00153 //     Function: PStatView::constrain
00154 //       Access: Public
00155 //  Description: Changes the focus of the View.  By default, the View
00156 //               reports the entire time for the frame, and all of the
00157 //               Collectors that are directly parented to "Frame".  By
00158 //               constraining the view to a particular collector, you
00159 //               cause the View to zoom in on that collector's data,
00160 //               reporting only the collector and its immediate
00161 //               parents.
00162 //
00163 //               When you constrain the view, you may also specify
00164 //               whether the view should show time data or level data
00165 //               for the indicated collector.  If level data, it
00166 //               reports the levels for the collector, and all of its
00167 //               children; otherwise, it collects the elapsed time.
00168 //
00169 //               Changing the constraint causes the current frame's
00170 //               data to become invalidated; you must then call
00171 //               set_to_frame() again to get any useful data out.
00172 ////////////////////////////////////////////////////////////////////
00173 void PStatView::
00174 constrain(int collector, bool show_level) {
00175   _constraint = collector;
00176   _show_level = show_level;
00177   clear_levels();
00178 }
00179 
00180 ////////////////////////////////////////////////////////////////////
00181 //     Function: PStatView::unconstrain
00182 //       Access: Public
00183 //  Description: Restores the view to the full frame.  This is
00184 //               equivalent to calling constrain(0).
00185 ////////////////////////////////////////////////////////////////////
00186 void PStatView::
00187 unconstrain() {
00188   constrain(0, false);
00189 }
00190 
00191 ////////////////////////////////////////////////////////////////////
00192 //     Function: PStatView::set_thread_data
00193 //       Access: Public
00194 //  Description:
00195 ////////////////////////////////////////////////////////////////////
00196 void PStatView::
00197 set_thread_data(const PStatThreadData *thread_data) {
00198   _thread_data = thread_data;
00199   _client_data = thread_data->get_client_data();
00200   clear_levels();
00201   _all_collectors_known = false;
00202 }
00203 
00204 ////////////////////////////////////////////////////////////////////
00205 //     Function: PStatView::set_to_frame
00206 //       Access: Public
00207 //  Description: Supplies the View with the data for the current
00208 //               frame.  This causes the View to update all of its
00209 //               internal data to reflect the frame's data, subject to
00210 //               the current constraint.
00211 //
00212 //               It is possible that calling this will increase the
00213 //               total number of reported levels (for instance, if
00214 //               this frame introduced a new collector that hadn't
00215 //               been active previously).  In this case, the caller
00216 //               must update its display or whatever to account for
00217 //               the new level.
00218 ////////////////////////////////////////////////////////////////////
00219 void PStatView::
00220 set_to_frame(const PStatFrameData &frame_data) {
00221   nassertv(!_thread_data.is_null());
00222   nassertv(!_client_data.is_null());
00223 
00224   if (_show_level) {
00225     update_level_data(frame_data);
00226   } else {
00227     update_time_data(frame_data);
00228   }
00229 }
00230 
00231 
00232 ////////////////////////////////////////////////////////////////////
00233 //     Function: PStatView::all_collectors_known
00234 //       Access: Public
00235 //  Description: After a call to set_to_frame(), this returns true if
00236 //               all collectors in the FrameData are known by the
00237 //               PStatsData object, or false if some are still unknown
00238 //               (even those that do not appear in the view).
00239 ////////////////////////////////////////////////////////////////////
00240 bool PStatView::
00241 all_collectors_known() const {
00242   return _all_collectors_known;
00243 }
00244 
00245 ////////////////////////////////////////////////////////////////////
00246 //     Function: PStatView::get_net_value
00247 //       Access: Public
00248 //  Description: Returns the total value accounted for by the frame (or
00249 //               by whatever Collector we are constrained to).  This
00250 //               is the sum of all of the individual levels'
00251 //               get_net_value() value.
00252 ////////////////////////////////////////////////////////////////////
00253 float PStatView::
00254 get_net_value() const {
00255   float net = 0.0;
00256   Levels::const_iterator li;
00257   for (li = _levels.begin(); li != _levels.end(); ++li) {
00258     net += (*li).second->_value_alone;
00259   }
00260 
00261   return net;
00262 }
00263 
00264 ////////////////////////////////////////////////////////////////////
00265 //     Function: PStatView::get_top_level
00266 //       Access: Public
00267 //  Description: Returns a pointer to the level that corresponds to
00268 //               the Collector we've constrained to.  This is the top
00269 //               of a graph of levels; typically the next level
00270 //               down--the children of this level--will be the levels
00271 //               you want to display to the user.
00272 ////////////////////////////////////////////////////////////////////
00273 const PStatViewLevel *PStatView::
00274 get_top_level() {
00275   return get_level(_constraint);
00276 }
00277 
00278 ////////////////////////////////////////////////////////////////////
00279 //     Function: PStatView::has_level
00280 //       Access: Public
00281 //  Description: Returns true if there is a level defined for the
00282 //               particular collector, false otherwise.
00283 ////////////////////////////////////////////////////////////////////
00284 bool PStatView::
00285 has_level(int collector) const {
00286   Levels::const_iterator li;
00287   li = _levels.find(collector);
00288   return (li != _levels.end());
00289 }
00290 
00291 ////////////////////////////////////////////////////////////////////
00292 //     Function: PStatView::get_level
00293 //       Access: Public
00294 //  Description: Returns a pointer to the level that corresponds to
00295 //               the indicated Collector.  If there is no such level
00296 //               in the view, one will be created--use with caution.
00297 //               Check has_level() first if you don't want this
00298 //               behavior.
00299 ////////////////////////////////////////////////////////////////////
00300 PStatViewLevel *PStatView::
00301 get_level(int collector) {
00302   Levels::const_iterator li;
00303   li = _levels.find(collector);
00304   if (li != _levels.end()) {
00305     return (*li).second;
00306   }
00307 
00308   PStatViewLevel *level = new PStatViewLevel;
00309   level->_collector = collector;
00310   level->_parent = NULL;
00311   _levels[collector] = level;
00312 
00313   reset_level(level);
00314   return level;
00315 }
00316 
00317 ////////////////////////////////////////////////////////////////////
00318 //     Function: PStatView::update_time_data
00319 //       Access: Private
00320 //  Description: The implementation of set_to_frame() for views that
00321 //               show elapsed time.
00322 ////////////////////////////////////////////////////////////////////
00323 void PStatView::
00324 update_time_data(const PStatFrameData &frame_data) {
00325   int num_events = frame_data.get_num_events();
00326 
00327   typedef pvector<FrameSample> Samples;
00328   Samples samples(_client_data->get_num_collectors());
00329 
00330   FrameSample::Started started;
00331 
00332   _all_collectors_known = true;
00333 
00334 
00335   // This tracks the set of samples we actually care about.
00336   typedef pset<int> GotSamples;
00337   GotSamples got_samples;
00338 
00339   int i;
00340   for (i = 0; i < num_events; i++) {
00341     int collector_index = frame_data.get_time_collector(i);
00342     bool is_start = frame_data.is_start(i);
00343 
00344     if (!_client_data->has_collector(collector_index)) {
00345       _all_collectors_known = false;
00346 
00347     } else {
00348       nassertv(collector_index >= 0 && collector_index < (int)samples.size());
00349 
00350       if (_client_data->get_child_distance(_constraint, collector_index) >= 0) {
00351         // Here's a data point we care about: anything at constraint
00352         // level or below.
00353         if (is_start == samples[collector_index]._is_started) {
00354           nout << "Unexpected data point for " 
00355                << _client_data->get_collector_fullname(collector_index)
00356                << "\n";
00357         } else {
00358           samples[collector_index].data_point(frame_data.get_time(i), is_start, started);
00359           got_samples.insert(collector_index);
00360         }
00361       }
00362     }
00363   }
00364 
00365   // Make sure everything is stopped.
00366 
00367   Samples::iterator si;
00368   for (i = 0, si = samples.begin(); si != samples.end(); ++i, ++si) {
00369     if ((*si)._is_started) {
00370       nout << _client_data->get_collector_fullname(i)
00371            << " was not stopped at frame end!\n";
00372       (*si).data_point(frame_data.get_end(), false, started);
00373     }
00374   }
00375 
00376   nassertv(started.empty());
00377 
00378   bool any_new_levels = false;
00379 
00380   // Now match these samples we got up with those we already had in
00381   // the levels.
00382   Levels::iterator li, lnext;
00383   li = _levels.begin();
00384   while (li != _levels.end()) {
00385     // Be careful while traversing a container and calling functions
00386     // that could modify that container.
00387     lnext = li;
00388     ++lnext;
00389 
00390     PStatViewLevel *level = (*li).second;
00391     if (reset_level(level)) {
00392       any_new_levels = true;
00393     }
00394 
00395     int collector_index = level->_collector;
00396     GotSamples::iterator gi;
00397     gi = got_samples.find(collector_index);
00398     if (gi != got_samples.end()) {
00399       level->_value_alone = samples[collector_index]._net_time;
00400       got_samples.erase(gi);
00401     }
00402 
00403     li = lnext;
00404   }
00405 
00406   // Finally, any samples left over in the got_samples set are new
00407   // collectors that we need to add to the Levels list.
00408   if (!got_samples.empty()) {
00409     any_new_levels = true;
00410 
00411     GotSamples::const_iterator gi;
00412     for (gi = got_samples.begin(); gi != got_samples.end(); ++gi) {
00413       int collector_index = (*gi);
00414       PStatViewLevel *level = get_level(collector_index);
00415       level->_value_alone = samples[*gi]._net_time;
00416     }
00417   }
00418 
00419   if (any_new_levels) {
00420     _level_index++;
00421   }
00422 }
00423 
00424 ////////////////////////////////////////////////////////////////////
00425 //     Function: PStatView::update_level_data
00426 //       Access: Private
00427 //  Description: The implementation of set_to_frame() for views that
00428 //               show level values.
00429 ////////////////////////////////////////////////////////////////////
00430 void PStatView::
00431 update_level_data(const PStatFrameData &frame_data) {
00432   _all_collectors_known = true;
00433 
00434 
00435   // This tracks the set of level values we got.
00436   typedef pmap<int, float> GotValues;
00437   GotValues net_values;
00438 
00439   int i;
00440   int num_levels = frame_data.get_num_levels();
00441   for (i = 0; i < num_levels; i++) {
00442     int collector_index = frame_data.get_level_collector(i);
00443     float value = frame_data.get_level(i);
00444 
00445     if (!_client_data->has_collector(collector_index)) {
00446       _all_collectors_known = false;
00447 
00448     } else {
00449       if (_client_data->get_child_distance(_constraint, collector_index) >= 0) {
00450         net_values[collector_index] = value;
00451       }
00452     }
00453   }
00454 
00455   // Now that we've counted up the net level for each collector,
00456   // compute the level for each collector alone by subtracting out
00457   // each child from its parents.  If a parent has no data, nothing is
00458   // subtracted.
00459   GotValues alone_values = net_values;
00460 
00461   GotValues::iterator gi;
00462   for (gi = net_values.begin(); gi != net_values.end(); ++gi) {
00463     int collector_index = (*gi).first;
00464     float value = (*gi).second;
00465 
00466     // Walk up to the top.
00467     while (collector_index != 0 && collector_index != _constraint) {
00468       const PStatCollectorDef &def =
00469         _client_data->get_collector_def(collector_index);
00470       int parent_index = def._parent_index;
00471       GotValues::iterator pi = alone_values.find(parent_index);
00472       if (pi != alone_values.end()) {
00473         // The parent has data; subtract it.
00474         (*pi).second -= value;
00475       }
00476 
00477       collector_index = parent_index;
00478     }
00479   }
00480 
00481 
00482   bool any_new_levels = false;
00483 
00484   // Now match these samples we got up with those we already had in
00485   // the levels.
00486   Levels::iterator li, lnext;
00487   li = _levels.begin();
00488   while (li != _levels.end()) {
00489     // Be careful while traversing a container and calling functions
00490     // that could modify that container.
00491     lnext = li;
00492     ++lnext;
00493 
00494     PStatViewLevel *level = (*li).second;
00495     if (reset_level(level)) {
00496       any_new_levels = true;
00497     }
00498 
00499     int collector_index = level->_collector;
00500     GotValues::iterator gi;
00501     gi = alone_values.find(collector_index);
00502     if (gi != alone_values.end()) {
00503       level->_value_alone = (*gi).second;
00504       alone_values.erase(gi);
00505     }
00506 
00507     li = lnext;
00508   }
00509 
00510   // Finally, any values left over in the alone_values set are new
00511   // collectors that we need to add to the Levels list.
00512   if (!alone_values.empty()) {
00513     any_new_levels = true;
00514 
00515     GotValues::const_iterator gi;
00516     for (gi = alone_values.begin(); gi != alone_values.end(); ++gi) {
00517       int collector_index = (*gi).first;
00518       PStatViewLevel *level = get_level(collector_index);
00519       level->_value_alone = (*gi).second;
00520     }
00521   }
00522 
00523   if (any_new_levels) {
00524     _level_index++;
00525   }
00526 }
00527 
00528 ////////////////////////////////////////////////////////////////////
00529 //     Function: PStatView::clear_levels
00530 //       Access: Private
00531 //  Description: Resets all the levels that have been defined so far.
00532 ////////////////////////////////////////////////////////////////////
00533 void PStatView::
00534 clear_levels() {
00535   Levels::iterator li;
00536   for (li = _levels.begin(); li != _levels.end(); ++li) {
00537     delete (*li).second;
00538   }
00539   _levels.clear();
00540 }
00541 
00542 ////////////////////////////////////////////////////////////////////
00543 //     Function: PStatView::reset_level
00544 //       Access: Private
00545 //  Description: Resets the total value of the Level to zero, and also
00546 //               makes sure it is parented to the right Level
00547 //               corresponding to its Collector's parent.  Since the
00548 //               client might change its mind from time to time about
00549 //               who the Collector is parented to, we have to update
00550 //               this dynamically.
00551 //
00552 //               Returns true if any change was made to the level's
00553 //               hierarchy, false otherwise.
00554 ////////////////////////////////////////////////////////////////////
00555 bool PStatView::
00556 reset_level(PStatViewLevel *level) {
00557   bool any_changed = false;
00558   level->_value_alone = 0.0;
00559 
00560   if (level->_collector == _constraint) {
00561     return false;
00562   }
00563 
00564   if (_client_data->has_collector(level->_collector)) {
00565     int parent_index =
00566       _client_data->get_collector_def(level->_collector)._parent_index;
00567 
00568     if (level->_parent == (PStatViewLevel *)NULL) {
00569       // This level didn't know its parent before, but now it does.
00570       PStatViewLevel *parent_level = get_level(parent_index);
00571       nassertr(parent_level != level, true);
00572 
00573       level->_parent = parent_level;
00574       parent_level->_children.push_back(level);
00575       parent_level->sort_children(_client_data);
00576       any_changed = true;
00577 
00578     } else if (level->_parent->_collector != parent_index) {
00579       // This level knew about its parent, but now it's something
00580       // different.
00581       PStatViewLevel *old_parent_level = level->_parent;
00582       nassertr(old_parent_level != level, true);
00583 
00584       if (parent_index != 0) {
00585         PStatViewLevel *new_parent_level = get_level(parent_index);
00586         nassertr(new_parent_level != level, true);
00587         level->_parent = new_parent_level;
00588         new_parent_level->_children.push_back(level);
00589         new_parent_level->sort_children(_client_data);
00590       } else {
00591         level->_parent = NULL;
00592       }
00593 
00594       PStatViewLevel::Children::iterator ci =
00595         find(old_parent_level->_children.begin(),
00596              old_parent_level->_children.end(),
00597              level);
00598 
00599       nassertr(ci != old_parent_level->_children.end(), true);
00600       old_parent_level->_children.erase(ci);
00601       any_changed = true;
00602     }
00603   }
00604 
00605   return any_changed;
00606 }
00607 
00608 

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