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