Panda3D

pStatThreadData.cxx

00001 // Filename: pStatThreadData.cxx
00002 // Created by:  drose (09Jul00)
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 "pStatThreadData.h"
00016 
00017 #include "pStatFrameData.h"
00018 #include "pStatCollectorDef.h"
00019 #include "config_pstats.h"
00020 
00021 
00022 PStatFrameData PStatThreadData::_null_frame;
00023 
00024 ////////////////////////////////////////////////////////////////////
00025 //     Function: PStatThreadData::Constructor
00026 //       Access: Public
00027 //  Description:
00028 ////////////////////////////////////////////////////////////////////
00029 PStatThreadData::
00030 PStatThreadData(const PStatClientData *client_data) :
00031   _client_data(client_data)
00032 {
00033   _first_frame_number = 0;
00034   _history = pstats_history;
00035   _computed_elapsed_frames = false;
00036 }
00037 
00038 ////////////////////////////////////////////////////////////////////
00039 //     Function: PStatThreadData::Destructor
00040 //       Access: Public
00041 //  Description:
00042 ////////////////////////////////////////////////////////////////////
00043 PStatThreadData::
00044 ~PStatThreadData() {
00045 }
00046 
00047 
00048 ////////////////////////////////////////////////////////////////////
00049 //     Function: PStatThreadData::is_empty
00050 //       Access: Public
00051 //  Description: Returns true if the structure contains no frames,
00052 //               false otherwise.
00053 ////////////////////////////////////////////////////////////////////
00054 bool PStatThreadData::
00055 is_empty() const {
00056   return _frames.empty();
00057 }
00058 
00059 ////////////////////////////////////////////////////////////////////
00060 //     Function: PStatThreadData::get_latest_frame_number
00061 //       Access: Public
00062 //  Description: Returns the frame number of the most recent frame
00063 //               stored in the data.
00064 ////////////////////////////////////////////////////////////////////
00065 int PStatThreadData::
00066 get_latest_frame_number() const {
00067   nassertr(!_frames.empty(), 0);
00068   return _first_frame_number + _frames.size() - 1;
00069 }
00070 
00071 ////////////////////////////////////////////////////////////////////
00072 //     Function: PStatThreadData::get_oldest_frame_number
00073 //       Access: Public
00074 //  Description: Returns the frame number of the oldest frame still
00075 //               stored in the data.
00076 ////////////////////////////////////////////////////////////////////
00077 int PStatThreadData::
00078 get_oldest_frame_number() const {
00079   nassertr(!_frames.empty(), 0);
00080   return _first_frame_number;
00081 }
00082 
00083 ////////////////////////////////////////////////////////////////////
00084 //     Function: PStatThreadData::has_frame
00085 //       Access: Public
00086 //  Description: Returns true if we have received data for the
00087 //               indicated frame number from the client and we still
00088 //               have it stored, or false otherwise.
00089 ////////////////////////////////////////////////////////////////////
00090 bool PStatThreadData::
00091 has_frame(int frame_number) const {
00092   int rel_frame = frame_number - _first_frame_number;
00093 
00094   return (rel_frame >= 0 && rel_frame < (int)_frames.size() &&
00095           _frames[rel_frame] != (PStatFrameData *)NULL);
00096 }
00097 
00098 ////////////////////////////////////////////////////////////////////
00099 //     Function: PStatThreadData::get_frame
00100 //       Access: Public
00101 //  Description: Returns a FrameData structure associated with the
00102 //               indicated frame number.  If the frame data has not
00103 //               yet been received from the client, returns the newest
00104 //               frame older than the requested frame.
00105 ////////////////////////////////////////////////////////////////////
00106 const PStatFrameData &PStatThreadData::
00107 get_frame(int frame_number) const {
00108   int rel_frame = frame_number - _first_frame_number;
00109   int num_frames = _frames.size();
00110   if (rel_frame >= num_frames) {
00111     rel_frame = num_frames - 1;
00112   }
00113 
00114   while (rel_frame >= 0 && _frames[rel_frame] == (PStatFrameData *)NULL) {
00115     rel_frame--;
00116   }
00117   if (rel_frame < 0) {
00118     // No frame data that old.  Return the oldest frame we've got.
00119     rel_frame = 0;
00120     while (rel_frame < num_frames &&
00121            _frames[rel_frame] == (PStatFrameData *)NULL) {
00122       rel_frame++;
00123     }
00124   }
00125 
00126   if (rel_frame >= 0 && rel_frame < num_frames) {
00127     PStatFrameData *frame = _frames[rel_frame];
00128     nassertr(frame != (PStatFrameData *)NULL, _null_frame);
00129     nassertr(frame->get_start() >= 0.0, _null_frame);
00130     return *frame;
00131   }
00132 
00133   nassertr(_null_frame.get_start() >= 0.0, _null_frame);
00134   return _null_frame;
00135 }
00136 
00137 ////////////////////////////////////////////////////////////////////
00138 //     Function: PStatThreadData::get_latest_time
00139 //       Access: Public
00140 //  Description: Returns the timestamp (in seconds elapsed since
00141 //               connection) of the latest available frame.
00142 ////////////////////////////////////////////////////////////////////
00143 double PStatThreadData::
00144 get_latest_time() const {
00145   nassertr(!_frames.empty(), 0.0);
00146   return _frames.back()->get_start();
00147 }
00148 
00149 ////////////////////////////////////////////////////////////////////
00150 //     Function: PStatThreadData::get_oldest_time
00151 //       Access: Public
00152 //  Description: Returns the timestamp (in seconds elapsed since
00153 //               connection) of the oldest available frame.
00154 ////////////////////////////////////////////////////////////////////
00155 double PStatThreadData::
00156 get_oldest_time() const {
00157   nassertr(!_frames.empty(), 0.0);
00158   return _frames.front()->get_start();
00159 }
00160 
00161 ////////////////////////////////////////////////////////////////////
00162 //     Function: PStatThreadData::get_frame_at_time
00163 //       Access: Public
00164 //  Description: Returns the FrameData structure associated with the
00165 //               latest frame not later than the indicated time.
00166 ////////////////////////////////////////////////////////////////////
00167 const PStatFrameData &PStatThreadData::
00168 get_frame_at_time(double time) const {
00169   return get_frame(get_frame_number_at_time(time));
00170 }
00171 
00172 ////////////////////////////////////////////////////////////////////
00173 //     Function: PStatThreadData::get_frame_number_at_time
00174 //       Access: Public
00175 //  Description: Returns the frame number of the latest frame not
00176 //               later than the indicated time.
00177 //
00178 //               If the hint is nonnegative, it represents a frame
00179 //               number that we believe the correct answer to be near,
00180 //               which may speed the search for the frame.
00181 ////////////////////////////////////////////////////////////////////
00182 int PStatThreadData::
00183 get_frame_number_at_time(double time, int hint) const {
00184   hint -= _first_frame_number;
00185   if (hint >= 0 && hint < (int)_frames.size()) {
00186     if (_frames[hint] != (PStatFrameData *)NULL &&
00187         _frames[hint]->get_start() <= time) {
00188       // The hint might be right.  Scan forward from there.
00189       int i = hint + 1;
00190       while (i < (int)_frames.size() &&
00191              (_frames[i] == (PStatFrameData *)NULL ||
00192               _frames[i]->get_start() <= time)) {
00193         if (_frames[i] != (PStatFrameData *)NULL) {
00194           hint = i;
00195         }
00196         ++i;
00197       }
00198       return _first_frame_number + hint;
00199     }
00200   }
00201 
00202   // The hint is totally wrong.  Start from the end and work
00203   // backwards.
00204 
00205   int i = _frames.size() - 1;
00206   while (i >= 0) {
00207     const PStatFrameData *frame = _frames[i];
00208     if (frame != (PStatFrameData *)NULL && frame->get_start() <= time) {
00209       break;
00210     }
00211     --i;
00212   }
00213 
00214   return _first_frame_number + i;
00215 }
00216 
00217 ////////////////////////////////////////////////////////////////////
00218 //     Function: PStatThreadData::get_latest_frame
00219 //       Access: Public
00220 //  Description: Returns the FrameData associated with the most recent
00221 //               frame.
00222 ////////////////////////////////////////////////////////////////////
00223 const PStatFrameData &PStatThreadData::
00224 get_latest_frame() const {
00225   nassertr(!_frames.empty(), _null_frame);
00226   return *_frames.back();
00227 }
00228 
00229 ////////////////////////////////////////////////////////////////////
00230 //     Function: PStatThreadData::get_elapsed_frames
00231 //       Access: Public
00232 //  Description: Computes the oldest frame number not older than
00233 //               pstats_average_time seconds, and the newest frame
00234 //               number.  Handy for computing average frame rate over
00235 //               a time.  Returns true if there is any data in that
00236 //               range, false otherwise.
00237 ////////////////////////////////////////////////////////////////////
00238 bool PStatThreadData::
00239 get_elapsed_frames(int &then_i, int &now_i) const {
00240   if (!_computed_elapsed_frames) {
00241     ((PStatThreadData *)this)->compute_elapsed_frames();
00242   }
00243 
00244   now_i = _now_i;
00245   then_i = _then_i;
00246   return _got_elapsed_frames;
00247 }
00248 
00249 ////////////////////////////////////////////////////////////////////
00250 //     Function: PStatThreadData::get_frame_rate
00251 //       Access: Public
00252 //  Description: Computes the average frame rate over the past
00253 //               pstats_average_time seconds, by counting up the
00254 //               number of frames elapsed in that time interval.
00255 ////////////////////////////////////////////////////////////////////
00256 double PStatThreadData::
00257 get_frame_rate() const {
00258   int then_i, now_i;
00259   if (!get_elapsed_frames(then_i, now_i)) {
00260     return 0.0f;
00261   }
00262 
00263   int num_frames = now_i - then_i + 1;
00264   double now = _frames[now_i - _first_frame_number]->get_end();
00265   double elapsed_time = (now - _frames[then_i - _first_frame_number]->get_start());
00266   return (double)num_frames / elapsed_time;
00267 }
00268 
00269 
00270 ////////////////////////////////////////////////////////////////////
00271 //     Function: PStatThreadData::set_history
00272 //       Access: Public
00273 //  Description: Sets the number of seconds worth of frames that will
00274 //               be retained by the ThreadData structure as each new
00275 //               frame is added.  This affects how old the oldest
00276 //               frame that may be queried is.
00277 ////////////////////////////////////////////////////////////////////
00278 void PStatThreadData::
00279 set_history(double time) {
00280   _history = time;
00281 }
00282 
00283 ////////////////////////////////////////////////////////////////////
00284 //     Function: PStatThreadData::get_history
00285 //       Access: Public
00286 //  Description: Returns the number of seconds worth of frames that
00287 //               will be retained by the ThreadData structure as each
00288 //               new frame is added.  This affects how old the oldest
00289 //               frame that may be queried is.
00290 ////////////////////////////////////////////////////////////////////
00291 double PStatThreadData::
00292 get_history() const {
00293   return _history;
00294 }
00295 
00296 
00297 ////////////////////////////////////////////////////////////////////
00298 //     Function: PStatThreadData::record_new_frame
00299 //       Access: Public
00300 //  Description: Makes room for and stores a new frame's worth of
00301 //               data.  Calling this function may cause old frame data
00302 //               to be discarded to make room, according to the amount
00303 //               of time set up via set_history().
00304 //
00305 //               The pointer will become owned by the PStatThreadData
00306 //               object and will be freed on destruction.
00307 ////////////////////////////////////////////////////////////////////
00308 void PStatThreadData::
00309 record_new_frame(int frame_number, PStatFrameData *frame_data) {
00310   nassertv(frame_data != (PStatFrameData *)NULL);
00311   nassertv(!frame_data->is_empty());
00312   double time = frame_data->get_start();
00313 
00314   // First, remove all the old frames that fall outside of our
00315   // history window.
00316   double oldest_allowable_time = time - _history;
00317   while (!_frames.empty() &&
00318          (_frames.front() == (PStatFrameData *)NULL ||
00319           _frames.front()->is_empty() ||
00320           _frames.front()->get_start() < oldest_allowable_time)) {
00321     if (_frames.front() != (PStatFrameData *)NULL) {
00322       delete _frames.front();
00323     }
00324     _frames.pop_front();
00325     _first_frame_number++;
00326   }
00327 
00328   // Now, add enough empty frame definitions to account for the latest
00329   // frame number.  This might involve some skips, since we don't
00330   // guarantee that we get all the frames in order or even at all.
00331   if (_frames.empty()) {
00332     _first_frame_number = frame_number;
00333     _frames.push_back(NULL);
00334 
00335   } else {
00336     while (_first_frame_number + (int)_frames.size() <= frame_number) {
00337       _frames.push_back(NULL);
00338     }
00339   }
00340 
00341   int index = frame_number - _first_frame_number;
00342   nassertv(index >= 0 && index < (int)_frames.size());
00343 
00344   if (_frames[index] != (PStatFrameData *)NULL) {
00345     nout << "Got repeated frame data for frame " << frame_number << "\n";
00346     delete _frames[index];
00347   }
00348 
00349   _frames[index] = frame_data;
00350   _computed_elapsed_frames = false;
00351 }
00352 
00353 ////////////////////////////////////////////////////////////////////
00354 //     Function: PStatThreadData::compute_elapsed_frames
00355 //       Access: Private
00356 //  Description: Computes the frame numbers returned by
00357 //               get_elapsed_frames().  This is non-const, but only
00358 //               updates cached values, so may safely be called from a
00359 //               const method.
00360 ////////////////////////////////////////////////////////////////////
00361 void PStatThreadData::
00362 compute_elapsed_frames() {
00363   if (_frames.empty()) {
00364     // No frames in the data at all.
00365     _got_elapsed_frames = false;
00366     
00367   } else {
00368     _now_i = _frames.size() - 1;
00369     while (_now_i > 0 && _frames[_now_i] == (PStatFrameData *)NULL) {
00370       _now_i--;
00371     }
00372     if (_now_i < 0) {
00373       // No frames have any real data.
00374       _got_elapsed_frames = false;
00375       
00376     } else {
00377       nassertv(_frames[_now_i] != (PStatFrameData *)NULL);
00378       
00379       double now = _frames[_now_i]->get_end();
00380       double then = now - pstats_average_time;
00381       
00382       int old_i = _now_i;
00383       _then_i = _now_i;
00384       
00385       while (old_i >= 0) {
00386         const PStatFrameData *frame = _frames[old_i];
00387         if (frame != (PStatFrameData *)NULL) {
00388           if (frame->get_start() > then) {
00389             _then_i = old_i;
00390           } else {
00391             break;
00392           }
00393         }
00394         old_i--;
00395       }
00396       
00397       nassertv(_then_i >= 0);
00398       nassertv(_frames[_then_i] != (PStatFrameData *)NULL);
00399       _got_elapsed_frames = true;
00400 
00401       _now_i += _first_frame_number;
00402       _then_i += _first_frame_number;
00403     }
00404   }
00405   
00406   _computed_elapsed_frames = true;
00407 }
 All Classes Functions Variables Enumerations