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 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 */
309void PStatThreadData::
310compute_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.