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  */
122 get_latest_time() const {
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  */
132 get_oldest_time() const {
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  */
191 get_latest_frame() const {
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  */
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  */
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 }
The data associated with a particular client, but not with any one particular frame or thread: the li...
Contains the raw timing and level data for a single frame.
bool is_empty() const
Returns true if the FrameData has no time or level data.
double get_start() const
Returns the time of the first data point in the frame data.
A collection of FrameData structures for recently-received frames within a particular thread.
void set_history(double time)
Sets the number of seconds worth of frames that will be retained by the ThreadData structure as each ...
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...
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 is_empty() const
Returns true if the structure contains no frames, false otherwise.
double get_history() const
Returns the number of seconds worth of frames that will be retained by the ThreadData structure as ea...
double get_frame_rate() const
Computes the average frame rate over the past pstats_average_time seconds, by counting up the number ...
const PStatFrameData & get_frame_at_time(double time) const
Returns the FrameData structure associated with the latest frame not later than the indicated time.
const PStatFrameData & get_latest_frame() const
Returns the FrameData associated with the most recent frame.
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(int frame_number) const
Returns a FrameData structure associated with the indicated frame 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.
double get_latest_time() const
Returns the timestamp (in seconds elapsed since connection) of the latest available frame.
void record_new_frame(int frame_number, PStatFrameData *frame_data)
Makes room for and stores a new frame's worth of data.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.