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