diff --git a/pandatool/src/bam/bamInfo.cxx b/pandatool/src/bam/bamInfo.cxx index 2ac083fe37..2435649b8f 100644 --- a/pandatool/src/bam/bamInfo.cxx +++ b/pandatool/src/bam/bamInfo.cxx @@ -28,6 +28,7 @@ #include "dcast.h" #include "pvector.h" #include "bamCacheRecord.h" +#include "bamCacheIndex.h" //////////////////////////////////////////////////////////////////// // Function: BamInfo::Constructor @@ -162,6 +163,10 @@ get_info(const Filename &filename) { objects[0]->is_of_type(Texture::get_class_type())) { describe_texture(DCAST(Texture, objects[0])); + } else if (objects.size() == 1 && + objects[0]->is_of_type(BamCacheIndex::get_class_type())) { + describe_cache_index(DCAST(BamCacheIndex, objects[0])); + } else if (!objects.empty() && objects[0]->is_of_type(RecorderHeader::get_class_type())) { describe_session(DCAST(RecorderHeader, objects[0]), objects); @@ -216,6 +221,17 @@ describe_texture(Texture *tex) { tex->write(nout, 2); } +//////////////////////////////////////////////////////////////////// +// Function: BamInfo::describe_cache_index +// Access: Private +// Description: Called for Bam files that contain a BamCacheIndex +// object. +//////////////////////////////////////////////////////////////////// +void BamInfo:: +describe_cache_index(BamCacheIndex *index) { + index->write(nout, 2); +} + //////////////////////////////////////////////////////////////////// // Function: BamInfo::describe_session // Access: Private diff --git a/pandatool/src/bam/bamInfo.h b/pandatool/src/bam/bamInfo.h index 6b9def0d48..16bb9101d3 100644 --- a/pandatool/src/bam/bamInfo.h +++ b/pandatool/src/bam/bamInfo.h @@ -28,6 +28,9 @@ #include "pvector.h" class TypedWritable; +class PandaNode; +class Texture; +class BamCacheIndex; class RecorderHeader; //////////////////////////////////////////////////////////////////// @@ -49,6 +52,7 @@ private: bool get_info(const Filename &filename); void describe_scene_graph(PandaNode *node); void describe_texture(Texture *tex); + void describe_cache_index(BamCacheIndex *index); void describe_session(RecorderHeader *header, const Objects &objects); void describe_general_object(TypedWritable *object); void list_hierarchy(PandaNode *node, int indent_level); diff --git a/pandatool/src/pstatserver/pStatThreadData.cxx b/pandatool/src/pstatserver/pStatThreadData.cxx index 17405dd191..cb82c1e772 100644 --- a/pandatool/src/pstatserver/pStatThreadData.cxx +++ b/pandatool/src/pstatserver/pStatThreadData.cxx @@ -313,6 +313,7 @@ void PStatThreadData:: record_new_frame(int frame_number, PStatFrameData *frame_data) { nassertv(frame_data != (PStatFrameData *)NULL); nassertv(!frame_data->is_empty()); + // frame_data->sort_time(); float time = frame_data->get_start(); // First, remove all the old frames that fall outside of our @@ -342,16 +343,18 @@ record_new_frame(int frame_number, PStatFrameData *frame_data) { } } - int index = frame_number - _first_frame_number; - nassertv(index >= 0 && index < (int)_frames.size()); - - if (_frames[index] != (PStatFrameData *)NULL) { - nout << "Got repeated frame data for frame " << frame_number << "\n"; - delete _frames[index]; + if (frame_number >= _first_frame_number) { + int index = frame_number - _first_frame_number; + nassertv(index >= 0 && index < (int)_frames.size()); + + if (_frames[index] != (PStatFrameData *)NULL) { + nout << "Got repeated frame data for frame " << frame_number << "\n"; + delete _frames[index]; + } + + _frames[index] = frame_data; + _computed_elapsed_frames = false; } - - _frames[index] = frame_data; - _computed_elapsed_frames = false; } //////////////////////////////////////////////////////////////////// diff --git a/pandatool/src/pstatserver/pStatView.cxx b/pandatool/src/pstatserver/pStatView.cxx index db76ae1acd..8669e4d13a 100644 --- a/pandatool/src/pstatserver/pStatView.cxx +++ b/pandatool/src/pstatserver/pStatView.cxx @@ -27,105 +27,6 @@ #include - -//////////////////////////////////////////////////////////////////// -// Class : FrameSample -// Description : This class is used within this module only--in fact, -// within PStatView::set_to_frame() only--to help -// collect event data out of the PStatFrameData object -// and boil it down to a list of elapsed times. -//////////////////////////////////////////////////////////////////// -class FrameSample { -public: - typedef plist Started; - - FrameSample() { - _touched = false; - _is_started = false; - _pushed = false; - _net_time = 0.0; - } - void data_point(float time, bool is_start, Started &started) { - _touched = true; - - // 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); - nassertv(si != started.end()); - started.erase(si); - - } else { - if (_is_started) { - _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); - } - } - } - void push(float time) { - if (!_pushed) { - _pushed = true; - if (_is_started) { - _net_time += time; - } - } - } - void pop(float time) { - if (_pushed) { - _pushed = false; - if (_is_started) { - _net_time -= time; - } - } - } - - void push_all(float time, Started &started) { - Started::iterator si; - for (si = started.begin(); si != started.end(); ++si) { - (*si)->push(time); - } - } - - void pop_one(float time, Started &started) { - Started::reverse_iterator si; - for (si = started.rbegin(); si != started.rend(); ++si) { - if ((*si)->_pushed) { - (*si)->pop(time); - return; - } - } - } - - bool _touched; - bool _is_started; - bool _pushed; - float _net_time; -}; - - - //////////////////////////////////////////////////////////////////// // Function: PStatView::Constructor // Access: Public @@ -322,66 +223,10 @@ get_level(int collector) { //////////////////////////////////////////////////////////////////// void PStatView:: update_time_data(const PStatFrameData &frame_data) { - int num_events = frame_data.get_num_events(); - - typedef pvector Samples; - Samples samples(_client_data->get_num_collectors()); - - FrameSample::Started started; - _all_collectors_known = true; - - // This tracks the set of samples we actually care about. - typedef pset GotSamples; - GotSamples got_samples; - - int i; - for (i = 0; i < num_events; i++) { - 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; - - } else { - nassertv(collector_index >= 0 && collector_index < (int)samples.size()); - - if (_client_data->get_child_distance(_constraint, collector_index) >= 0) { - // Here's a data point we care about: anything at constraint - // level or below. - if (is_start == samples[collector_index]._is_started) { - if (!is_start) { - // A "stop" in the middle of a frame implies a "start" - // since time 0 (that is, since the first data point in - // the frame). - samples[collector_index].data_point(frame_data.get_time(0), true, started); - samples[collector_index].data_point(frame_data.get_time(i), is_start, started); - } else { - // An extra "start" for a collector that's already started - // is an error. - nout << "Unexpected data point for " - << _client_data->get_collector_fullname(collector_index) - << "\n"; - } - } else { - samples[collector_index].data_point(frame_data.get_time(i), is_start, started); - got_samples.insert(collector_index); - } - } - } - } - - // Make sure everything is stopped. - - Samples::iterator si; - for (i = 0, si = samples.begin(); si != samples.end(); ++i, ++si) { - if ((*si)._is_started) { - (*si).data_point(frame_data.get_end(), false, started); - } - } - - nassertv(started.empty()); + Samples samples(_client_data->get_num_collectors()); + fill_samples(samples, frame_data); bool any_new_levels = false; @@ -401,26 +246,23 @@ update_time_data(const PStatFrameData &frame_data) { } int collector_index = level->_collector; - GotSamples::iterator gi; - gi = got_samples.find(collector_index); - if (gi != got_samples.end()) { + if (samples[collector_index]._touched) { level->_value_alone = samples[collector_index]._net_time; - got_samples.erase(gi); + samples[collector_index]._touched = false; } li = lnext; } - // Finally, any samples left over in the got_samples set are new + // Finally, any samples left over in the samples list are new // collectors that we need to add to the Levels list. - if (!got_samples.empty()) { - any_new_levels = true; - - GotSamples::const_iterator gi; - for (gi = got_samples.begin(); gi != got_samples.end(); ++gi) { - int collector_index = (*gi); + for (int collector_index = 0; + collector_index < (int)samples.size(); + ++collector_index) { + if (samples[collector_index]._touched) { + any_new_levels = true; PStatViewLevel *level = get_level(collector_index); - level->_value_alone = samples[*gi]._net_time; + level->_value_alone = samples[collector_index]._net_time; } } @@ -429,6 +271,102 @@ update_time_data(const PStatFrameData &frame_data) { } } +//////////////////////////////////////////////////////////////////// +// Function: PStatView::fill_samples +// Access: Private +// Description: Fills up samples with the net time accumulated +// uniquely in each collector. +//////////////////////////////////////////////////////////////////// +void PStatView:: +fill_samples(Samples &samples, const PStatFrameData &frame_data) { + int num_events = frame_data.get_num_events(); + if (num_events == 0) { + return; + } + + cerr << "start fill_samples\n"; + + Started started; + + Samples::iterator si; + for (si = samples.begin(); si != samples.end(); ++si) { + (*si).initialize(frame_data.get_start(), started); + int collector_index = si - samples.begin(); + cerr << " " << _client_data->get_collector_fullname(collector_index) + << " " << (*si)._started << " " << (*si)._pushed + << " " << (*si)._net_time << "\n"; + } + + for (int i = 0; i < num_events; i++) { + int collector_index = frame_data.get_time_collector(i); + bool is_start = frame_data.is_start(i); + + cerr << " event: " + << _client_data->get_collector_fullname(collector_index) + << " " << is_start << " " << frame_data.get_time(i) << "\n"; + + if (!_client_data->has_collector(collector_index)) { + _all_collectors_known = false; + + } else { + nassertv(collector_index >= 0 && collector_index < (int)samples.size()); + + if (_client_data->get_child_distance(_constraint, collector_index) >= 0) { + // Here's a data point we care about: anything at constraint + // level or below. + if (is_start == samples[collector_index]._started) { + if (!is_start && !samples[collector_index]._touched) { + // A "stop" in the middle of a frame probably means the + // collector wrapped around the end of the frame and back + // to the beginning. This is very difficult to record + // properly--which collectors did it shadow from the + // beginning the frame? This will require going back and + // re-interpreting the frame from the beginning. For now, + // we'll set a flag; when we later encounter this + // collector's "start" time, we'll interpret this flag. + samples[collector_index]._reset_initially_started = true; + + } else { + // An extra "start" for a collector that's already started + // is an error. + nout << "Unexpected data point for " + << _client_data->get_collector_fullname(collector_index) + << "\n"; + } + } else { + if (is_start && samples[collector_index]._reset_initially_started) { + // OK, here's the initial start for this collector. This + // means that we push all of the collectors that are + // currently active now. It also means that all of these + // collectors will still be pushed at the beginning of the + // next frame (or, assuming the frames are largely + // similar, at the beginning of this frame). + Started::iterator sti; + for (sti = started.begin(); sti != started.end(); ++sti) { + (*sti)->_initially_pushed = true; + } + samples[collector_index]._initially_started = true; + // Now go back and try again, re-examining the data from + // the beginning of the frame. + cerr << "recurse on " + << _client_data->get_collector_fullname(collector_index) + << "\n"; + fill_samples(samples, frame_data); + return; + } + samples[collector_index].data_point(frame_data.get_time(i), is_start, started); + } + } + } + } + + for (si = samples.begin(); si != samples.end(); ++si) { + (*si).finalize(frame_data.get_end(), started); + } + + nassertv(started.empty()); +} + //////////////////////////////////////////////////////////////////// // Function: PStatView::update_level_data // Access: Private @@ -614,3 +552,185 @@ reset_level(PStatViewLevel *level) { } + +//////////////////////////////////////////////////////////////////// +// Function: PStatView::FrameSample::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +PStatView::FrameSample:: +FrameSample() { + _touched = false; + _started = false; + _pushed = false; + _initially_pushed = false; + _initially_started = false; + _reset_initially_started = false; + _net_time = 0.0; +} + +//////////////////////////////////////////////////////////////////// +// Function: PStatView::FrameSample::data_point +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +void PStatView::FrameSample:: +data_point(float time, bool is_start, PStatView::Started &started) { + cerr << "data_point(" << time << ", " << is_start << ",)\n"; + _touched = true; + nassertv(is_start != _started); + + // The _net_time value has two possible different meanings, + // according to the current state of the frame. When the + // collector is not actively accumulating time, then _net_start + // represents the total time already accumulated towards the + // collector. However, while the collector is actively + // accumulating time, then _net_start is a stange value, liable to + // be negative, which is actually the total time accumulated so + // far less the start time of the collector. + + // You can tell which state _net_time is in by examining + // _started and _pushed. The four cases are: + + // When !_started && !_pushed, _net_time is valid. + // When !_started && _pushed, _net_time is valid. + // When _started && !_pushed, _net_time is invalid (the + // collector is running). + // When _started && _pushed, _net_time is valid. + + _started = is_start; + + if (_started) { + // Starting the collector. + if (!_pushed) { + // (!_started && !_pushed) -> (_started && !_pushed) + _net_time -= time; + + // Starting a new collector obscures, or "pushes", all of the + // collectors already started. + push_all(time, started); + } + started.push_back(this); + + } else { + // Stopping the collector. + if (_pushed) { + // We have been pushed below some other collector. In this + // case, the time has already been stopped. Just remove + // this collector from the pushed stack. + Started::iterator si = find(started.begin(), started.end(), this); + nassertv(si != started.end()); + started.erase(si); + + // (_started && _pushed) -> (!_started && _pushed) + nassertv(_net_time >= 0.0); + + } else { + // We are still active. Accumulate the time since we started. + // (_started && !_pushed) -> (!_started && !_pushed) + _net_time += time; + nassertv(_net_time >= 0.0); + + // Now reveal, or "pop", the topmost of the collectors that + // were previously obscured. + Started::iterator si = find(started.begin(), started.end(), this); + nassertv(si != started.end()); + started.erase(si); + pop_one(time, started); + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: PStatView::FrameSample::push +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +void PStatView::FrameSample:: +push(float time) { + if (!_pushed) { + _pushed = true; + if (_started) { + // (_started && !_pushed) -> (_started && _pushed) + _net_time += time; + nassertv(_net_time >= 0.0); + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: PStatView::FrameSample::pop +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +void PStatView::FrameSample:: +pop(float time) { + nassertv(_pushed); + _pushed = false; + if (_started) { + // (_started && _pushed) -> (_started && !_pushed) + _net_time -= time; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: PStatView::FrameSample::push_all +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +void PStatView::FrameSample:: +push_all(float time, PStatView::Started &started) { + Started::iterator si; + for (si = started.begin(); si != started.end(); ++si) { + (*si)->push(time); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: PStatView::FrameSample::pop_one +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +void PStatView::FrameSample:: +pop_one(float time, PStatView::Started &started) { + Started::reverse_iterator si; + for (si = started.rbegin(); si != started.rend(); ++si) { + if ((*si)->_pushed) { + (*si)->pop(time); + return; + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: PStatView::FrameSample::initialize +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +void PStatView::FrameSample:: +initialize(float start_time, PStatView::Started &started) { + _touched = false; + _pushed = _initially_pushed; + _started = _initially_started; + _reset_initially_started = false; + _net_time = 0.0; + + if (_started) { + started.push_back(this); + if (!_pushed) { + _net_time -= start_time; + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: PStatView::FrameSample::finalize +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +void PStatView::FrameSample:: +finalize(float end_time, PStatView::Started &started) { + if (_started) { + data_point(end_time, false, started); + } +} diff --git a/pandatool/src/pstatserver/pStatView.h b/pandatool/src/pstatserver/pStatView.h index 74d98ee528..7d54ce348f 100644 --- a/pandatool/src/pstatserver/pStatView.h +++ b/pandatool/src/pstatserver/pStatView.h @@ -24,8 +24,9 @@ #include "pStatClientData.h" #include "pStatThreadData.h" #include "pStatViewLevel.h" - #include "pointerTo.h" +#include "pvector.h" +#include "plist.h" //////////////////////////////////////////////////////////////////// // Class : PStatView @@ -69,6 +70,37 @@ private: void clear_levels(); bool reset_level(PStatViewLevel *level); + // FrameSample is used to help collect event data out of the + // PStatFrameData object and boil it down to a list of elapsed + // times. + class FrameSample; + typedef plist Started; + + class FrameSample { + public: + FrameSample(); + void data_point(float time, bool is_start, Started &started); + void push(float time); + void pop(float time); + + void push_all(float time, Started &started); + void pop_one(float time, Started &started); + + void initialize(float start_time, Started &started); + void finalize(float end_time, Started &started); + + bool _touched; + bool _started; + bool _pushed; + bool _initially_pushed; + bool _initially_started; + bool _reset_initially_started; + float _net_time; + }; + typedef pvector Samples; + + void fill_samples(Samples &samples, const PStatFrameData &frame_data); + int _constraint; bool _show_level; bool _all_collectors_known; diff --git a/pandatool/src/ptloader/loaderFileTypePandatool.cxx b/pandatool/src/ptloader/loaderFileTypePandatool.cxx index 586501a134..50dc1db801 100644 --- a/pandatool/src/ptloader/loaderFileTypePandatool.cxx +++ b/pandatool/src/ptloader/loaderFileTypePandatool.cxx @@ -109,7 +109,8 @@ resolve_filename(Filename &path) const { // Description: //////////////////////////////////////////////////////////////////// PT(PandaNode) LoaderFileTypePandatool:: -load_file(const Filename &path, const LoaderOptions &options) const { +load_file(const Filename &path, const LoaderOptions &options, + BamCacheRecord *record) const { PT(PandaNode) result; PT(EggData) egg_data = new EggData; diff --git a/pandatool/src/ptloader/loaderFileTypePandatool.h b/pandatool/src/ptloader/loaderFileTypePandatool.h index d6a416ac9b..ac7df7a820 100644 --- a/pandatool/src/ptloader/loaderFileTypePandatool.h +++ b/pandatool/src/ptloader/loaderFileTypePandatool.h @@ -43,7 +43,8 @@ public: virtual bool supports_compressed() const; virtual void resolve_filename(Filename &path) const; - virtual PT(PandaNode) load_file(const Filename &path, const LoaderOptions &options) const; + virtual PT(PandaNode) load_file(const Filename &path, const LoaderOptions &options, + BamCacheRecord *record) const; private: SomethingToEggConverter *_converter;