Panda3D
 All Classes Functions Variables Enumerations
pStatThreadData.cxx
1 // Filename: pStatThreadData.cxx
2 // Created by: drose (09Jul00)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "pStatThreadData.h"
16 
17 #include "pStatFrameData.h"
18 #include "pStatCollectorDef.h"
19 #include "config_pstats.h"
20 
21 
22 PStatFrameData PStatThreadData::_null_frame;
23 
24 ////////////////////////////////////////////////////////////////////
25 // Function: PStatThreadData::Constructor
26 // Access: Public
27 // Description:
28 ////////////////////////////////////////////////////////////////////
29 PStatThreadData::
30 PStatThreadData(const PStatClientData *client_data) :
31  _client_data(client_data)
32 {
33  _first_frame_number = 0;
34  _history = pstats_history;
35  _computed_elapsed_frames = false;
36 }
37 
38 ////////////////////////////////////////////////////////////////////
39 // Function: PStatThreadData::Destructor
40 // Access: Public
41 // Description:
42 ////////////////////////////////////////////////////////////////////
43 PStatThreadData::
44 ~PStatThreadData() {
45 }
46 
47 
48 ////////////////////////////////////////////////////////////////////
49 // Function: PStatThreadData::is_empty
50 // Access: Public
51 // Description: Returns true if the structure contains no frames,
52 // false otherwise.
53 ////////////////////////////////////////////////////////////////////
55 is_empty() const {
56  return _frames.empty();
57 }
58 
59 ////////////////////////////////////////////////////////////////////
60 // Function: PStatThreadData::get_latest_frame_number
61 // Access: Public
62 // Description: Returns the frame number of the most recent frame
63 // stored in the data.
64 ////////////////////////////////////////////////////////////////////
67  nassertr(!_frames.empty(), 0);
68  return _first_frame_number + _frames.size() - 1;
69 }
70 
71 ////////////////////////////////////////////////////////////////////
72 // Function: PStatThreadData::get_oldest_frame_number
73 // Access: Public
74 // Description: Returns the frame number of the oldest frame still
75 // stored in the data.
76 ////////////////////////////////////////////////////////////////////
79  nassertr(!_frames.empty(), 0);
80  return _first_frame_number;
81 }
82 
83 ////////////////////////////////////////////////////////////////////
84 // Function: PStatThreadData::has_frame
85 // Access: Public
86 // Description: Returns true if we have received data for the
87 // indicated frame number from the client and we still
88 // have it stored, or false otherwise.
89 ////////////////////////////////////////////////////////////////////
91 has_frame(int frame_number) const {
92  int rel_frame = frame_number - _first_frame_number;
93 
94  return (rel_frame >= 0 && rel_frame < (int)_frames.size() &&
95  _frames[rel_frame] != (PStatFrameData *)NULL);
96 }
97 
98 ////////////////////////////////////////////////////////////////////
99 // Function: PStatThreadData::get_frame
100 // Access: Public
101 // Description: Returns a FrameData structure associated with the
102 // indicated frame number. If the frame data has not
103 // yet been received from the client, returns the newest
104 // frame older than the requested frame.
105 ////////////////////////////////////////////////////////////////////
107 get_frame(int frame_number) const {
108  int rel_frame = frame_number - _first_frame_number;
109  int num_frames = _frames.size();
110  if (rel_frame >= num_frames) {
111  rel_frame = num_frames - 1;
112  }
113 
114  while (rel_frame >= 0 && _frames[rel_frame] == (PStatFrameData *)NULL) {
115  rel_frame--;
116  }
117  if (rel_frame < 0) {
118  // No frame data that old. Return the oldest frame we've got.
119  rel_frame = 0;
120  while (rel_frame < num_frames &&
121  _frames[rel_frame] == (PStatFrameData *)NULL) {
122  rel_frame++;
123  }
124  }
125 
126  if (rel_frame >= 0 && rel_frame < num_frames) {
127  PStatFrameData *frame = _frames[rel_frame];
128  nassertr(frame != (PStatFrameData *)NULL, _null_frame);
129  nassertr(frame->get_start() >= 0.0, _null_frame);
130  return *frame;
131  }
132 
133  nassertr(_null_frame.get_start() >= 0.0, _null_frame);
134  return _null_frame;
135 }
136 
137 ////////////////////////////////////////////////////////////////////
138 // Function: PStatThreadData::get_latest_time
139 // Access: Public
140 // Description: Returns the timestamp (in seconds elapsed since
141 // connection) of the latest available frame.
142 ////////////////////////////////////////////////////////////////////
143 double PStatThreadData::
145  nassertr(!_frames.empty(), 0.0);
146  return _frames.back()->get_start();
147 }
148 
149 ////////////////////////////////////////////////////////////////////
150 // Function: PStatThreadData::get_oldest_time
151 // Access: Public
152 // Description: Returns the timestamp (in seconds elapsed since
153 // connection) of the oldest available frame.
154 ////////////////////////////////////////////////////////////////////
155 double PStatThreadData::
157  nassertr(!_frames.empty(), 0.0);
158  return _frames.front()->get_start();
159 }
160 
161 ////////////////////////////////////////////////////////////////////
162 // Function: PStatThreadData::get_frame_at_time
163 // Access: Public
164 // Description: Returns the FrameData structure associated with the
165 // latest frame not later than the indicated time.
166 ////////////////////////////////////////////////////////////////////
168 get_frame_at_time(double time) const {
169  return get_frame(get_frame_number_at_time(time));
170 }
171 
172 ////////////////////////////////////////////////////////////////////
173 // Function: PStatThreadData::get_frame_number_at_time
174 // Access: Public
175 // Description: Returns the frame number of the latest frame not
176 // later than the indicated time.
177 //
178 // If the hint is nonnegative, it represents a frame
179 // number that we believe the correct answer to be near,
180 // which may speed the search for the frame.
181 ////////////////////////////////////////////////////////////////////
183 get_frame_number_at_time(double time, int hint) const {
184  hint -= _first_frame_number;
185  if (hint >= 0 && hint < (int)_frames.size()) {
186  if (_frames[hint] != (PStatFrameData *)NULL &&
187  _frames[hint]->get_start() <= time) {
188  // The hint might be right. Scan forward from there.
189  int i = hint + 1;
190  while (i < (int)_frames.size() &&
191  (_frames[i] == (PStatFrameData *)NULL ||
192  _frames[i]->get_start() <= time)) {
193  if (_frames[i] != (PStatFrameData *)NULL) {
194  hint = i;
195  }
196  ++i;
197  }
198  return _first_frame_number + hint;
199  }
200  }
201 
202  // The hint is totally wrong. Start from the end and work
203  // backwards.
204 
205  int i = _frames.size() - 1;
206  while (i >= 0) {
207  const PStatFrameData *frame = _frames[i];
208  if (frame != (PStatFrameData *)NULL && frame->get_start() <= time) {
209  break;
210  }
211  --i;
212  }
213 
214  return _first_frame_number + i;
215 }
216 
217 ////////////////////////////////////////////////////////////////////
218 // Function: PStatThreadData::get_latest_frame
219 // Access: Public
220 // Description: Returns the FrameData associated with the most recent
221 // frame.
222 ////////////////////////////////////////////////////////////////////
225  nassertr(!_frames.empty(), _null_frame);
226  return *_frames.back();
227 }
228 
229 ////////////////////////////////////////////////////////////////////
230 // Function: PStatThreadData::get_elapsed_frames
231 // Access: Public
232 // Description: Computes the oldest frame number not older than
233 // pstats_average_time seconds, and the newest frame
234 // number. Handy for computing average frame rate over
235 // a time. Returns true if there is any data in that
236 // range, false otherwise.
237 ////////////////////////////////////////////////////////////////////
239 get_elapsed_frames(int &then_i, int &now_i) const {
240  if (!_computed_elapsed_frames) {
241  ((PStatThreadData *)this)->compute_elapsed_frames();
242  }
243 
244  now_i = _now_i;
245  then_i = _then_i;
246  return _got_elapsed_frames;
247 }
248 
249 ////////////////////////////////////////////////////////////////////
250 // Function: PStatThreadData::get_frame_rate
251 // Access: Public
252 // Description: Computes the average frame rate over the past
253 // pstats_average_time seconds, by counting up the
254 // number of frames elapsed in that time interval.
255 ////////////////////////////////////////////////////////////////////
256 double PStatThreadData::
257 get_frame_rate() const {
258  int then_i, now_i;
259  if (!get_elapsed_frames(then_i, now_i)) {
260  return 0.0f;
261  }
262 
263  int num_frames = now_i - then_i + 1;
264  double now = _frames[now_i - _first_frame_number]->get_end();
265  double elapsed_time = (now - _frames[then_i - _first_frame_number]->get_start());
266  return (double)num_frames / elapsed_time;
267 }
268 
269 
270 ////////////////////////////////////////////////////////////////////
271 // Function: PStatThreadData::set_history
272 // Access: Public
273 // Description: Sets the number of seconds worth of frames that will
274 // be retained by the ThreadData structure as each new
275 // frame is added. This affects how old the oldest
276 // frame that may be queried is.
277 ////////////////////////////////////////////////////////////////////
279 set_history(double time) {
280  _history = time;
281 }
282 
283 ////////////////////////////////////////////////////////////////////
284 // Function: PStatThreadData::get_history
285 // Access: Public
286 // Description: Returns the number of seconds worth of frames that
287 // will be retained by the ThreadData structure as each
288 // new frame is added. This affects how old the oldest
289 // frame that may be queried is.
290 ////////////////////////////////////////////////////////////////////
291 double PStatThreadData::
292 get_history() const {
293  return _history;
294 }
295 
296 
297 ////////////////////////////////////////////////////////////////////
298 // Function: PStatThreadData::record_new_frame
299 // Access: Public
300 // Description: Makes room for and stores a new frame's worth of
301 // data. Calling this function may cause old frame data
302 // to be discarded to make room, according to the amount
303 // of time set up via set_history().
304 //
305 // The pointer will become owned by the PStatThreadData
306 // object and will be freed on destruction.
307 ////////////////////////////////////////////////////////////////////
309 record_new_frame(int frame_number, PStatFrameData *frame_data) {
310  nassertv(frame_data != (PStatFrameData *)NULL);
311  nassertv(!frame_data->is_empty());
312  double time = frame_data->get_start();
313 
314  // First, remove all the old frames that fall outside of our
315  // history window.
316  double oldest_allowable_time = time - _history;
317  while (!_frames.empty() &&
318  (_frames.front() == (PStatFrameData *)NULL ||
319  _frames.front()->is_empty() ||
320  _frames.front()->get_start() < oldest_allowable_time)) {
321  if (_frames.front() != (PStatFrameData *)NULL) {
322  delete _frames.front();
323  }
324  _frames.pop_front();
325  _first_frame_number++;
326  }
327 
328  // Now, add enough empty frame definitions to account for the latest
329  // frame number. This might involve some skips, since we don't
330  // guarantee that we get all the frames in order or even at all.
331  if (_frames.empty()) {
332  _first_frame_number = frame_number;
333  _frames.push_back(NULL);
334 
335  } else {
336  while (_first_frame_number + (int)_frames.size() <= frame_number) {
337  _frames.push_back(NULL);
338  }
339  }
340 
341  int index = frame_number - _first_frame_number;
342  nassertv(index >= 0 && index < (int)_frames.size());
343 
344  if (_frames[index] != (PStatFrameData *)NULL) {
345  nout << "Got repeated frame data for frame " << frame_number << "\n";
346  delete _frames[index];
347  }
348 
349  _frames[index] = frame_data;
350  _computed_elapsed_frames = false;
351 }
352 
353 ////////////////////////////////////////////////////////////////////
354 // Function: PStatThreadData::compute_elapsed_frames
355 // Access: Private
356 // Description: Computes the frame numbers returned by
357 // get_elapsed_frames(). This is non-const, but only
358 // updates cached values, so may safely be called from a
359 // const method.
360 ////////////////////////////////////////////////////////////////////
361 void PStatThreadData::
362 compute_elapsed_frames() {
363  if (_frames.empty()) {
364  // No frames in the data at all.
365  _got_elapsed_frames = false;
366 
367  } else {
368  _now_i = _frames.size() - 1;
369  while (_now_i > 0 && _frames[_now_i] == (PStatFrameData *)NULL) {
370  _now_i--;
371  }
372  if (_now_i < 0) {
373  // No frames have any real data.
374  _got_elapsed_frames = false;
375 
376  } else {
377  nassertv(_frames[_now_i] != (PStatFrameData *)NULL);
378 
379  double now = _frames[_now_i]->get_end();
380  double then = now - pstats_average_time;
381 
382  int old_i = _now_i;
383  _then_i = _now_i;
384 
385  while (old_i >= 0) {
386  const PStatFrameData *frame = _frames[old_i];
387  if (frame != (PStatFrameData *)NULL) {
388  if (frame->get_start() > then) {
389  _then_i = old_i;
390  } else {
391  break;
392  }
393  }
394  old_i--;
395  }
396 
397  nassertv(_then_i >= 0);
398  nassertv(_frames[_then_i] != (PStatFrameData *)NULL);
399  _got_elapsed_frames = true;
400 
401  _now_i += _first_frame_number;
402  _then_i += _first_frame_number;
403  }
404  }
405 
406  _computed_elapsed_frames = true;
407 }
void set_history(double time)
Sets the number of seconds worth of frames that will be retained by the ThreadData structure as each ...
bool is_empty() const
Returns true if the FrameData has no time or level data.
void record_new_frame(int frame_number, PStatFrameData *frame_data)
Makes room for and stores a new frame&#39;s worth of data.
bool is_empty() const
Returns true if the structure contains no frames, false otherwise.
bool get_elapsed_frames(int &then_i, int &now_i) const
Computes the oldest frame number not older than pstats_average_time seconds, and the newest frame num...
The data associated with a particular client, but not with any one particular frame or thread: the li...
int get_frame_number_at_time(double time, int hint=-1) const
Returns the frame number of the latest frame not later than the indicated time.
const PStatFrameData & get_frame_at_time(double time) const
Returns the FrameData structure associated with the latest frame not later than the indicated time...
double get_oldest_time() const
Returns the timestamp (in seconds elapsed since connection) of the oldest available frame...
double get_start() const
Returns the time of the first data point in the frame data.
Contains the raw timing and level data for a single frame.
const PStatFrameData & get_latest_frame() const
Returns the FrameData associated with the most recent frame.
A collection of FrameData structures for recently-received frames within a particular thread...
double get_history() const
Returns the number of seconds worth of frames that will be retained by the ThreadData structure as ea...
const PStatFrameData & get_frame(int frame_number) const
Returns a FrameData structure associated with the indicated frame number.
bool has_frame(int frame_number) const
Returns true if we have received data for the indicated frame number from the client and we still hav...
double get_latest_time() const
Returns the timestamp (in seconds elapsed since connection) of the latest available frame...
double get_frame_rate() const
Computes the average frame rate over the past pstats_average_time seconds, by counting up the number ...
int get_latest_frame_number() const
Returns the frame number of the most recent frame stored in the data.
int get_oldest_frame_number() const
Returns the frame number of the oldest frame still stored in the data.