Panda3D
|
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 }