|
|
@@ -18,8 +18,8 @@
|
|
|
// Class : FrameSample
|
|
|
// Description : This class is used within this module only--in fact,
|
|
|
// within PStatView::set_to_frame() only--to help
|
|
|
-// collect data out of the PStatFrameData object and
|
|
|
-// boil it down to a list of elapsed times.
|
|
|
+// collect event data out of the PStatFrameData object
|
|
|
+// and boil it down to a list of elapsed times.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
class FrameSample {
|
|
|
public:
|
|
|
@@ -31,10 +31,25 @@ public:
|
|
|
_pushed = false;
|
|
|
_net_time = 0.0;
|
|
|
}
|
|
|
- void data_point(double time, Started &started) {
|
|
|
+ void data_point(float time, bool is_start, Started &started) {
|
|
|
_touched = true;
|
|
|
- _is_started = !_is_started;
|
|
|
|
|
|
+ // We only consider events that change the start/stop state.
|
|
|
+ // With two consecutive 'start' events, for instance, we ignore
|
|
|
+ // the second one.
|
|
|
+
|
|
|
+ // *** That's not quite the right thing to do. We should keep
|
|
|
+ // track of the nesting level and bracket things correctly, so
|
|
|
+ // that we ignore the second start and the *first* stop, but
|
|
|
+ // respect the outer start/stop. For the short term, this
|
|
|
+ // works, because the client is already doing this logic and
|
|
|
+ // won't send us nested start/stop pairs, but we'd like to
|
|
|
+ // generalize this in the future so we can deal with these
|
|
|
+ // nested pairs properly.
|
|
|
+ nassertv(is_start != _is_started);
|
|
|
+
|
|
|
+ _is_started = is_start;
|
|
|
+
|
|
|
if (_pushed) {
|
|
|
nassertv(!_is_started);
|
|
|
Started::iterator si = find(started.begin(), started.end(), this);
|
|
|
@@ -43,19 +58,19 @@ public:
|
|
|
|
|
|
} else {
|
|
|
if (_is_started) {
|
|
|
- _net_time -= time;
|
|
|
- push_all(time, started);
|
|
|
- started.push_back(this);
|
|
|
+ _net_time -= time;
|
|
|
+ push_all(time, started);
|
|
|
+ started.push_back(this);
|
|
|
} else {
|
|
|
- _net_time += time;
|
|
|
- Started::iterator si = find(started.begin(), started.end(), this);
|
|
|
- nassertv(si != started.end());
|
|
|
- started.erase(si);
|
|
|
- pop_one(time, started);
|
|
|
+ _net_time += time;
|
|
|
+ Started::iterator si = find(started.begin(), started.end(), this);
|
|
|
+ nassertv(si != started.end());
|
|
|
+ started.erase(si);
|
|
|
+ pop_one(time, started);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- void push(double time) {
|
|
|
+ void push(float time) {
|
|
|
if (!_pushed) {
|
|
|
_pushed = true;
|
|
|
if (_is_started) {
|
|
|
@@ -63,7 +78,7 @@ public:
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- void pop(double time) {
|
|
|
+ void pop(float time) {
|
|
|
if (_pushed) {
|
|
|
_pushed = false;
|
|
|
if (_is_started) {
|
|
|
@@ -72,14 +87,14 @@ public:
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- void push_all(double time, Started &started) {
|
|
|
+ void push_all(float time, Started &started) {
|
|
|
Started::iterator si;
|
|
|
for (si = started.begin(); si != started.end(); ++si) {
|
|
|
(*si)->push(time);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- void pop_one(double time, Started &started) {
|
|
|
+ void pop_one(float time, Started &started) {
|
|
|
Started::reverse_iterator si;
|
|
|
for (si = started.rbegin(); si != started.rend(); ++si) {
|
|
|
if ((*si)->_pushed) {
|
|
|
@@ -92,7 +107,7 @@ public:
|
|
|
bool _touched;
|
|
|
bool _is_started;
|
|
|
bool _pushed;
|
|
|
- double _net_time;
|
|
|
+ float _net_time;
|
|
|
};
|
|
|
|
|
|
|
|
|
@@ -105,6 +120,7 @@ public:
|
|
|
PStatView::
|
|
|
PStatView() {
|
|
|
_constraint = 0;
|
|
|
+ _show_level = false;
|
|
|
_all_collectors_known = false;
|
|
|
_level_index = 0;
|
|
|
}
|
|
|
@@ -130,13 +146,20 @@ PStatView::
|
|
|
// reporting only the collector and its immediate
|
|
|
// parents.
|
|
|
//
|
|
|
+// When you constrain the view, you may also specify
|
|
|
+// whether the view should show time data or level data
|
|
|
+// for the indicated collector. If level data, it
|
|
|
+// reports the levels for the collector, and all of its
|
|
|
+// children; otherwise, it collects the elapsed time.
|
|
|
+//
|
|
|
// Changing the constraint causes the current frame's
|
|
|
// data to become invalidated; you must then call
|
|
|
// set_to_frame() again to get any useful data out.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
void PStatView::
|
|
|
-constrain(int collector) {
|
|
|
+constrain(int collector, bool show_level) {
|
|
|
_constraint = collector;
|
|
|
+ _show_level = show_level;
|
|
|
clear_levels();
|
|
|
}
|
|
|
|
|
|
@@ -148,7 +171,7 @@ constrain(int collector) {
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
void PStatView::
|
|
|
unconstrain() {
|
|
|
- constrain(0);
|
|
|
+ constrain(0, false);
|
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
@@ -184,6 +207,107 @@ set_to_frame(const PStatFrameData &frame_data) {
|
|
|
nassertv(!_thread_data.is_null());
|
|
|
nassertv(!_client_data.is_null());
|
|
|
|
|
|
+ if (_show_level) {
|
|
|
+ update_level_data(frame_data);
|
|
|
+ } else {
|
|
|
+ update_time_data(frame_data);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: PStatView::all_collectors_known
|
|
|
+// Access: Public
|
|
|
+// Description: After a call to set_to_frame(), this returns true if
|
|
|
+// all collectors in the FrameData are known by the
|
|
|
+// PStatsData object, or false if some are still unknown
|
|
|
+// (even those that do not appear in the view).
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+bool PStatView::
|
|
|
+all_collectors_known() const {
|
|
|
+ return _all_collectors_known;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: PStatView::get_net_value
|
|
|
+// Access: Public
|
|
|
+// Description: Returns the total value accounted for by the frame (or
|
|
|
+// by whatever Collector we are constrained to). This
|
|
|
+// is the sum of all of the individual levels'
|
|
|
+// get_net_value() value.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+float PStatView::
|
|
|
+get_net_value() const {
|
|
|
+ float net = 0.0;
|
|
|
+ Levels::const_iterator li;
|
|
|
+ for (li = _levels.begin(); li != _levels.end(); ++li) {
|
|
|
+ net += (*li).second->_value_alone;
|
|
|
+ }
|
|
|
+
|
|
|
+ return net;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: PStatView::get_top_level
|
|
|
+// Access: Public
|
|
|
+// Description: Returns a pointer to the level that corresponds to
|
|
|
+// the Collector we've constrained to. This is the top
|
|
|
+// of a graph of levels; typically the next level
|
|
|
+// down--the children of this level--will be the levels
|
|
|
+// you want to display to the user.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+const PStatViewLevel *PStatView::
|
|
|
+get_top_level() {
|
|
|
+ return get_level(_constraint);
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: PStatView::has_level
|
|
|
+// Access: Public
|
|
|
+// Description: Returns true if there is a level defined for the
|
|
|
+// particular collector, false otherwise.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+bool PStatView::
|
|
|
+has_level(int collector) const {
|
|
|
+ Levels::const_iterator li;
|
|
|
+ li = _levels.find(collector);
|
|
|
+ return (li != _levels.end());
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: PStatView::get_level
|
|
|
+// Access: Public
|
|
|
+// Description: Returns a pointer to the level that corresponds to
|
|
|
+// the indicated Collector. If there is no such level
|
|
|
+// in the view, one will be created--use with caution.
|
|
|
+// Check has_level() first if you don't want this
|
|
|
+// behavior.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+PStatViewLevel *PStatView::
|
|
|
+get_level(int collector) {
|
|
|
+ Levels::const_iterator li;
|
|
|
+ li = _levels.find(collector);
|
|
|
+ if (li != _levels.end()) {
|
|
|
+ return (*li).second;
|
|
|
+ }
|
|
|
+
|
|
|
+ PStatViewLevel *level = new PStatViewLevel;
|
|
|
+ level->_collector = collector;
|
|
|
+ level->_parent = NULL;
|
|
|
+ _levels[collector] = level;
|
|
|
+
|
|
|
+ reset_level(level);
|
|
|
+ return level;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: PStatView::update_time_data
|
|
|
+// Access: Private
|
|
|
+// Description: The implementation of set_to_frame() for views that
|
|
|
+// show elapsed time.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void PStatView::
|
|
|
+update_time_data(const PStatFrameData &frame_data) {
|
|
|
int num_events = frame_data.get_num_events();
|
|
|
|
|
|
typedef vector<FrameSample> Samples;
|
|
|
@@ -200,7 +324,8 @@ set_to_frame(const PStatFrameData &frame_data) {
|
|
|
|
|
|
int i;
|
|
|
for (i = 0; i < num_events; i++) {
|
|
|
- int collector_index = (frame_data.get_collector(i) & 0x7fff);
|
|
|
+ int collector_index = frame_data.get_time_collector(i);
|
|
|
+ bool is_start = frame_data.is_start(i);
|
|
|
|
|
|
if (!_client_data->has_collector(collector_index)) {
|
|
|
_all_collectors_known = false;
|
|
|
@@ -211,7 +336,7 @@ set_to_frame(const PStatFrameData &frame_data) {
|
|
|
if (_client_data->get_child_distance(_constraint, collector_index) >= 0) {
|
|
|
// Here's a data point we care about: anything at constraint
|
|
|
// level or below.
|
|
|
- samples[collector_index].data_point(frame_data.get_time(i), started);
|
|
|
+ samples[collector_index].data_point(frame_data.get_time(i), is_start, started);
|
|
|
got_samples.insert(collector_index);
|
|
|
}
|
|
|
}
|
|
|
@@ -224,7 +349,7 @@ set_to_frame(const PStatFrameData &frame_data) {
|
|
|
if ((*si)._is_started) {
|
|
|
nout << _client_data->get_collector_fullname(i)
|
|
|
<< " was not stopped at frame end!\n";
|
|
|
- (*si).data_point(frame_data.get_end(), started);
|
|
|
+ (*si).data_point(frame_data.get_end(), false, started);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -251,7 +376,7 @@ set_to_frame(const PStatFrameData &frame_data) {
|
|
|
GotSamples::iterator gi;
|
|
|
gi = got_samples.find(collector_index);
|
|
|
if (gi != got_samples.end()) {
|
|
|
- level->_time_alone = samples[collector_index]._net_time;
|
|
|
+ level->_value_alone = samples[collector_index]._net_time;
|
|
|
got_samples.erase(gi);
|
|
|
}
|
|
|
|
|
|
@@ -267,7 +392,7 @@ set_to_frame(const PStatFrameData &frame_data) {
|
|
|
for (gi = got_samples.begin(); gi != got_samples.end(); ++gi) {
|
|
|
int collector_index = (*gi);
|
|
|
PStatViewLevel *level = get_level(collector_index);
|
|
|
- level->_time_alone = samples[*gi]._net_time;
|
|
|
+ level->_value_alone = samples[*gi]._net_time;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -276,90 +401,108 @@ set_to_frame(const PStatFrameData &frame_data) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: PStatView::all_collectors_known
|
|
|
-// Access: Public
|
|
|
-// Description: After a call to set_to_frame(), this returns true if
|
|
|
-// all collectors in the FrameData are known by the
|
|
|
-// PStatsData object, or false if some are still unknown
|
|
|
-// (even those that do not appear in the view).
|
|
|
+// Function: PStatView::update_level_data
|
|
|
+// Access: Private
|
|
|
+// Description: The implementation of set_to_frame() for views that
|
|
|
+// show level values.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-bool PStatView::
|
|
|
-all_collectors_known() const {
|
|
|
- return _all_collectors_known;
|
|
|
-}
|
|
|
+void PStatView::
|
|
|
+update_level_data(const PStatFrameData &frame_data) {
|
|
|
+ _all_collectors_known = true;
|
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-// Function: PStatView::get_net_time
|
|
|
-// Access: Public
|
|
|
-// Description: Returns the total time accounted for by the frame (or
|
|
|
-// by whatever Collector we are constrained to). This
|
|
|
-// is the sum of all of the individual levels'
|
|
|
-// get_net_time() value.
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-double PStatView::
|
|
|
-get_net_time() const {
|
|
|
- double net = 0.0;
|
|
|
- Levels::const_iterator li;
|
|
|
- for (li = _levels.begin(); li != _levels.end(); ++li) {
|
|
|
- net += (*li).second->_time_alone;
|
|
|
+
|
|
|
+ // This tracks the set of level values we got.
|
|
|
+ typedef map<int, float> GotValues;
|
|
|
+ GotValues net_values;
|
|
|
+
|
|
|
+ int i;
|
|
|
+ int num_levels = frame_data.get_num_levels();
|
|
|
+ for (i = 0; i < num_levels; i++) {
|
|
|
+ int collector_index = frame_data.get_level_collector(i);
|
|
|
+ float value = frame_data.get_level(i);
|
|
|
+
|
|
|
+ if (!_client_data->has_collector(collector_index)) {
|
|
|
+ _all_collectors_known = false;
|
|
|
+
|
|
|
+ } else {
|
|
|
+ if (_client_data->get_child_distance(_constraint, collector_index) >= 0) {
|
|
|
+ net_values[collector_index] = value;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- return net;
|
|
|
-}
|
|
|
+ // Now that we've counted up the net level for each collector,
|
|
|
+ // compute the level for each collector alone by subtracting out
|
|
|
+ // each child from its parents. If a parent has no data, nothing is
|
|
|
+ // subtracted.
|
|
|
+ GotValues alone_values = net_values;
|
|
|
+
|
|
|
+ GotValues::iterator gi;
|
|
|
+ for (gi = net_values.begin(); gi != net_values.end(); ++gi) {
|
|
|
+ int collector_index = (*gi).first;
|
|
|
+ float value = (*gi).second;
|
|
|
+
|
|
|
+ // Walk up to the top.
|
|
|
+ while (collector_index != 0 && collector_index != _constraint) {
|
|
|
+ const PStatCollectorDef &def =
|
|
|
+ _client_data->get_collector_def(collector_index);
|
|
|
+ int parent_index = def._parent_index;
|
|
|
+ GotValues::iterator pi = alone_values.find(parent_index);
|
|
|
+ if (pi != alone_values.end()) {
|
|
|
+ // The parent has data; subtract it.
|
|
|
+ (*pi).second -= value;
|
|
|
+ }
|
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-// Function: PStatView::get_top_level
|
|
|
-// Access: Public
|
|
|
-// Description: Returns a pointer to the level that corresponds to
|
|
|
-// the Collector we've constrained to. This is the top
|
|
|
-// of a graph of levels; typically the next level
|
|
|
-// down--the children of this level--will be the levels
|
|
|
-// you want to display to the user.
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-const PStatViewLevel *PStatView::
|
|
|
-get_top_level() {
|
|
|
- return get_level(_constraint);
|
|
|
-}
|
|
|
+ collector_index = parent_index;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-// Function: PStatView::has_level
|
|
|
-// Access: Public
|
|
|
-// Description: Returns true if there is a level defined for the
|
|
|
-// particular collector, false otherwise.
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-bool PStatView::
|
|
|
-has_level(int collector) const {
|
|
|
- Levels::const_iterator li;
|
|
|
- li = _levels.find(collector);
|
|
|
- return (li != _levels.end());
|
|
|
-}
|
|
|
+ bool any_new_levels = false;
|
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-// Function: PStatView::get_level
|
|
|
-// Access: Public
|
|
|
-// Description: Returns a pointer to the level that corresponds to
|
|
|
-// the indicated Collector. If there is no such level
|
|
|
-// in the view, one will be created--use with caution.
|
|
|
-// Check has_level() first if you don't want this
|
|
|
-// behavior.
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-PStatViewLevel *PStatView::
|
|
|
-get_level(int collector) {
|
|
|
- Levels::const_iterator li;
|
|
|
- li = _levels.find(collector);
|
|
|
- if (li != _levels.end()) {
|
|
|
- return (*li).second;
|
|
|
+ // Now match these samples we got up with those we already had in
|
|
|
+ // the levels.
|
|
|
+ Levels::iterator li, lnext;
|
|
|
+ li = _levels.begin();
|
|
|
+ while (li != _levels.end()) {
|
|
|
+ // Be careful while traversing a container and calling functions
|
|
|
+ // that could modify that container.
|
|
|
+ lnext = li;
|
|
|
+ ++lnext;
|
|
|
+
|
|
|
+ PStatViewLevel *level = (*li).second;
|
|
|
+ if (reset_level(level)) {
|
|
|
+ any_new_levels = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ int collector_index = level->_collector;
|
|
|
+ GotValues::iterator gi;
|
|
|
+ gi = alone_values.find(collector_index);
|
|
|
+ if (gi != alone_values.end()) {
|
|
|
+ level->_value_alone = (*gi).second;
|
|
|
+ alone_values.erase(gi);
|
|
|
+ }
|
|
|
+
|
|
|
+ li = lnext;
|
|
|
}
|
|
|
|
|
|
- PStatViewLevel *level = new PStatViewLevel;
|
|
|
- level->_collector = collector;
|
|
|
- level->_parent = NULL;
|
|
|
- _levels[collector] = level;
|
|
|
+ // Finally, any values left over in the alone_values set are new
|
|
|
+ // collectors that we need to add to the Levels list.
|
|
|
+ if (!alone_values.empty()) {
|
|
|
+ any_new_levels = true;
|
|
|
|
|
|
- reset_level(level);
|
|
|
- return level;
|
|
|
+ GotValues::const_iterator gi;
|
|
|
+ for (gi = alone_values.begin(); gi != alone_values.end(); ++gi) {
|
|
|
+ int collector_index = (*gi).first;
|
|
|
+ PStatViewLevel *level = get_level(collector_index);
|
|
|
+ level->_value_alone = (*gi).second;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (any_new_levels) {
|
|
|
+ _level_index++;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
@@ -379,7 +522,7 @@ clear_levels() {
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
// Function: PStatView::reset_level
|
|
|
// Access: Private
|
|
|
-// Description: Resets the total time of the Level to zero, and also
|
|
|
+// Description: Resets the total value of the Level to zero, and also
|
|
|
// makes sure it is parented to the right Level
|
|
|
// corresponding to its Collector's parent. Since the
|
|
|
// client might change its mind from time to time about
|
|
|
@@ -392,7 +535,7 @@ clear_levels() {
|
|
|
bool PStatView::
|
|
|
reset_level(PStatViewLevel *level) {
|
|
|
bool any_changed = false;
|
|
|
- level->_time_alone = 0.0;
|
|
|
+ level->_value_alone = 0.0;
|
|
|
|
|
|
if (level->_collector == _constraint) {
|
|
|
return false;
|