Panda3D
Loading...
Searching...
No Matches
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
21PStatFrameData PStatThreadData::_null_frame;
22
23/**
24 *
25 */
26PStatThreadData::
27PStatThreadData(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 */
38PStatThreadData::
39~PStatThreadData() {
40}
41
42
43/**
44 * Returns true if the structure contains no frames, false otherwise.
45 */
47is_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 */
74has_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 */
87get_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 */
122get_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 */
132get_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 */
142get_frame_at_time(double time) const {
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 */
154get_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 */
191get_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 */
203get_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 */
218get_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 */
237set_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 */
247get_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 */
261record_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
294 // It's possible to receive frames out of order.
295 while (index < 0) {
296 _frames.push_front(nullptr);
297 ++index;
298 --_first_frame_number;
299 }
300
301 nassertv(index >= 0 && index < (int)_frames.size());
302
303 if (_frames[index] != nullptr) {
304 nout << "Got repeated frame data for frame " << frame_number << "\n";
305 delete _frames[index];
306 }
307
308 _frames[index] = frame_data;
309 _computed_elapsed_frames = false;
310}
311
312/**
313 * Computes the frame numbers returned by get_elapsed_frames(). This is non-
314 * const, but only updates cached values, so may safely be called from a const
315 * method.
316 */
317void PStatThreadData::
318compute_elapsed_frames() {
319 if (_frames.empty()) {
320 // No frames in the data at all.
321 _got_elapsed_frames = false;
322
323 } else {
324 _now_i = _frames.size() - 1;
325 while (_now_i > 0 && _frames[_now_i] == nullptr) {
326 _now_i--;
327 }
328 if (_now_i < 0) {
329 // No frames have any real data.
330 _got_elapsed_frames = false;
331
332 } else {
333 nassertv(_frames[_now_i] != nullptr);
334
335 double now = _frames[_now_i]->get_end();
336 double then = now - pstats_average_time;
337
338 int old_i = _now_i;
339 _then_i = _now_i;
340
341 while (old_i >= 0) {
342 const PStatFrameData *frame = _frames[old_i];
343 if (frame != nullptr) {
344 if (frame->get_start() > then) {
345 _then_i = old_i;
346 } else {
347 break;
348 }
349 }
350 old_i--;
351 }
352
353 nassertv(_then_i >= 0);
354 nassertv(_frames[_then_i] != nullptr);
355 _got_elapsed_frames = true;
356
357 _now_i += _first_frame_number;
358 _then_i += _first_frame_number;
359 }
360 }
361
362 _computed_elapsed_frames = true;
363}
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.
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.