Panda3D
pStatClientData.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 pStatClientData.cxx
10  * @author drose
11  * @date 2000-07-11
12  */
13 
14 #include "pStatClientData.h"
15 #include "pStatReader.h"
16 
17 #include "pStatCollectorDef.h"
18 
19 using std::string;
20 
21 PStatCollectorDef PStatClientData::_null_collector(-1, "Unknown");
22 
23 
24 
25 /**
26  *
27  */
28 PStatClientData::
29 PStatClientData(PStatReader *reader) :
30  _reader(reader)
31 {
32  _is_alive = true;
33 }
34 
35 /**
36  *
37  */
38 PStatClientData::
39 ~PStatClientData() {
40  Collectors::const_iterator ci;
41  for (ci = _collectors.begin(); ci != _collectors.end(); ++ci) {
42  delete (*ci)._def;
43  }
44 }
45 
46 /**
47  * Returns true if the data is actively getting filled by a connected client,
48  * or false if the client has terminated.
49  */
51 is_alive() const {
52  return _is_alive;
53 }
54 
55 /**
56  * Closes the client connection if it is open.
57  */
59 close() {
60  if (_is_alive && _reader != nullptr) {
61  _reader->close();
62  _reader = nullptr;
63  _is_alive = false;
64  }
65 }
66 
67 /**
68  * Returns the total number of collectors the Data knows about.
69  */
72  return _collectors.size();
73 }
74 
75 /**
76  * Returns true if the indicated collector has been defined by the client
77  * already, false otherwise. It is possible for the client to start streaming
78  * data before all of the collectors have been defined.
79  */
81 has_collector(int index) const {
82  return (index >= 0 && index < (int)_collectors.size() &&
83  _collectors[index]._def != nullptr);
84 }
85 
86 /**
87  * Returns the nth collector definition.
88  */
90 get_collector_def(int index) const {
91  if (!has_collector(index)) {
92  return _null_collector;
93  }
94  return *_collectors[index]._def;
95 }
96 
97 /**
98  * Returns the name of the indicated collector.
99  */
100 string PStatClientData::
101 get_collector_name(int index) const {
102  if (!has_collector(index)) {
103  return "Unknown";
104  }
105  const PStatCollectorDef *def = _collectors[index]._def;
106  return def->_name;
107 }
108 
109 /**
110  * Returns the "full name" of the indicated collector. This will be the
111  * concatenation of all of the collector's parents' names (except Frame) and
112  * the collector's own name.
113  */
114 string PStatClientData::
115 get_collector_fullname(int index) const {
116  if (!has_collector(index)) {
117  return "Unknown";
118  }
119 
120  const PStatCollectorDef *def = _collectors[index]._def;
121  if (def->_parent_index == 0) {
122  return def->_name;
123  } else {
124  return get_collector_fullname(def->_parent_index) + ":" + def->_name;
125  }
126 }
127 
128 /**
129  * Indicates whether the given collector has level data (and consequently,
130  * whether it should appear on the Levels menu).
131  *
132  * The return value is true if anything changed, false otherwise.
133  */
135 set_collector_has_level(int index, int thread_index, bool flag) {
136  bool any_changed = false;
137  slot_collector(index);
138  nassertr(index >= 0 && index < (int)_collectors.size(), false);
139 
140  if (_collectors[index]._is_level.get_bit(thread_index) != flag) {
141  any_changed = true;
142  _collectors[index]._is_level.set_bit_to(thread_index, flag);
143  }
144 
145  // Turning this on for a given collector also implicitly turns all of its
146  // ancestors.
147  if (flag) {
148  PStatCollectorDef *def = _collectors[index]._def;
149  if (def != nullptr && def->_parent_index != 0) {
150  if (set_collector_has_level(def->_parent_index, thread_index, flag)) {
151  any_changed = true;
152  }
153  }
154  }
155 
156  return any_changed;
157 }
158 
159 
160 /**
161  * Returns whether the given collector has level data (and consequently,
162  * whether it should appear on the Levels menu).
163  */
165 get_collector_has_level(int index, int thread_index) const {
166  return (index >= 0 && index < (int)_collectors.size() &&
167  _collectors[index]._is_level.get_bit(thread_index));
168 }
169 
170 /**
171  * Returns the total number of collectors that are toplevel collectors. These
172  * are the collectors that are the children of "Frame", which is collector 0.
173  */
176  return _toplevel_collectors.size();
177 }
178 
179 /**
180  * Returns the collector index of the nth toplevel collector. Use this
181  * function to iterate through the n toplevel collectors indicated by
182  * get_num_toplevel_collectors().
183  */
186  nassertr(n >= 0 && n < (int)_toplevel_collectors.size(), 0);
187  return _toplevel_collectors[n];
188 }
189 
190 /**
191  * Returns the total number of threads the Data knows about.
192  */
195  return _threads.size();
196 }
197 
198 /**
199  * Returns true if the indicated thread has been defined by the client
200  * already, false otherwise. It is possible for the client to start streaming
201  * data before all of the threads have been defined.
202  */
204 has_thread(int index) const {
205  return (index >= 0 && index < (int)_threads.size() &&
206  !_threads[index]._name.empty());
207 }
208 
209 /**
210  * Returns the name of the indicated thread.
211  */
212 string PStatClientData::
213 get_thread_name(int index) const {
214  if (!has_thread(index)) {
215  return "Unknown";
216  }
217  return _threads[index]._name;
218 }
219 
220 /**
221  * Returns the data associated with the indicated thread. This will create a
222  * thread definition if it does not already exist.
223  */
225 get_thread_data(int index) const {
226  ((PStatClientData *)this)->define_thread(index);
227  nassertr(index >= 0 && index < (int)_threads.size(), nullptr);
228  return _threads[index]._data;
229 }
230 
231 /**
232  * Returns the number of Collectors between the indicated parent and the child
233  * Collector in the relationship graph. If child is the same as parent,
234  * returns zero. If child is an immediate child of parent, returns 1. If
235  * child is a grandchild of parent, returns 2, and so on. If child is not a
236  * descendant of parent at all, returns -1.
237  */
239 get_child_distance(int parent, int child) const {
240  if (parent == child) {
241  return 0;
242  }
243  if (!has_collector(child) || child == 0) {
244  return -1;
245  }
246  int dist = get_child_distance(parent, get_collector_def(child)._parent_index);
247  if (dist == -1) {
248  return -1;
249  } else {
250  return dist + 1;
251  }
252 }
253 
254 /**
255  * Adds a new collector definition to the dataset. Presumably this is
256  * information just arrived from the client.
257  *
258  * The pointer will become owned by the PStatClientData object and will be
259  * freed on destruction.
260  */
263  slot_collector(def->_index);
264  nassertv(def->_index >= 0 && def->_index < (int)_collectors.size());
265 
266  if (_collectors[def->_index]._def != nullptr) {
267  // Free the old definition, if any.
268  delete _collectors[def->_index]._def;
269  }
270 
271  _collectors[def->_index]._def = def;
272  update_toplevel_collectors();
273 
274  // If we already had the _is_level flag set, it should be immediately
275  // applied to all ancestors.
276  const BitArray &is_level = _collectors[def->_index]._is_level;
277  int max_threads = is_level.get_num_bits();
278  for (int thread_index = 0; thread_index < max_threads; ++thread_index) {
279  if (is_level.get_bit(thread_index)) {
280  set_collector_has_level(def->_parent_index, thread_index, true);
281  }
282  }
283 }
284 
285 /**
286  * Adds a new thread definition to the dataset. Presumably this is
287  * information just arrived from the client.
288  */
290 define_thread(int thread_index, const string &name) {
291  // A sanity check on the index number.
292  nassertv(thread_index < 1000);
293 
294  // Make sure we have enough slots allocated.
295  while ((int)_threads.size() <= thread_index) {
296  _threads.push_back(Thread());
297  }
298 
299  if (!name.empty()) {
300  _threads[thread_index]._name = name;
301  }
302 
303  if (_threads[thread_index]._data.is_null()) {
304  _threads[thread_index]._data = new PStatThreadData(this);
305  }
306 }
307 
308 
309 /**
310  * Makes room for and stores a new frame's worth of data associated with some
311  * particular thread (which may or may not have already been defined).
312  *
313  * The pointer will become owned by the PStatThreadData object and will be
314  * freed on destruction.
315  */
317 record_new_frame(int thread_index, int frame_number,
318  PStatFrameData *frame_data) {
319  define_thread(thread_index);
320  nassertv(thread_index >= 0 && thread_index < (int)_threads.size());
321  _threads[thread_index]._data->record_new_frame(frame_number, frame_data);
322 }
323 
324 /**
325  * Makes sure there is an entry in the array for a collector with the given
326  * index number.
327  */
328 void PStatClientData::
329 slot_collector(int collector_index) {
330  // A sanity check on the index number.
331  nassertv(collector_index < 100000);
332 
333  while ((int)_collectors.size() <= collector_index) {
334  Collector collector;
335  collector._def = nullptr;
336  _collectors.push_back(collector);
337  }
338 }
339 
340 /**
341  * Rebuilds the list of toplevel collectors.
342  */
343 void PStatClientData::
344 update_toplevel_collectors() {
345  _toplevel_collectors.clear();
346 
347  Collectors::const_iterator ci;
348  for (ci = _collectors.begin(); ci != _collectors.end(); ++ci) {
349  PStatCollectorDef *def = (*ci)._def;
350  if (def != nullptr && def->_parent_index == 0) {
351  _toplevel_collectors.push_back(def->_index);
352  }
353  }
354 }
void add_collector(PStatCollectorDef *def)
Adds a new collector definition to the dataset.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
int get_toplevel_collector(int index) const
Returns the collector index of the nth toplevel collector.
void close()
Closes the client connection if it is open.
bool get_bit(int index) const
Returns true if the nth bit is set, false if it is cleared.
Definition: bitArray.I:99
bool set_collector_has_level(int index, int thread_index, bool flag)
Indicates whether the given collector has level data (and consequently, whether it should appear on t...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
The data associated with a particular client, but not with any one particular frame or thread: the li...
int get_child_distance(int parent, int child) const
Returns the number of Collectors between the indicated parent and the child Collector in the relation...
const PStatCollectorDef & get_collector_def(int index) const
Returns the nth collector definition.
std::string get_collector_fullname(int index) const
Returns the "full name" of the indicated collector.
int get_num_threads() const
Returns the total number of threads the Data knows about.
void record_new_frame(int thread_index, int frame_number, PStatFrameData *frame_data)
Makes room for and stores a new frame's worth of data associated with some particular thread (which m...
std::string get_collector_name(int index) const
Returns the name of the indicated collector.
A dynamic array with an unlimited number of bits.
Definition: bitArray.h:39
bool has_collector(int index) const
Returns true if the indicated collector has been defined by the client already, false otherwise.
This is the class that does all the work for handling communications from a single Panda client.
Definition: pStatReader.h:41
bool is_alive() const
Returns true if the data is actively getting filled by a connected client, or false if the client has...
bool has_thread(int index) const
Returns true if the indicated thread has been defined by the client already, false otherwise.
Contains the raw timing and level data for a single frame.
int get_num_collectors() const
Returns the total number of collectors the Data knows about.
A collection of FrameData structures for recently-received frames within a particular thread.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
const PStatThreadData * get_thread_data(int index) const
Returns the data associated with the indicated thread.
void define_thread(int thread_index, const std::string &name=std::string())
Adds a new thread definition to the dataset.
size_t get_num_bits() const
Returns the current number of possibly different bits in this array.
Definition: bitArray.I:89
Defines the details about the Collectors: the name, the suggested color, etc.
int get_num_toplevel_collectors() const
Returns the total number of collectors that are toplevel collectors.
void close()
This will be called by the PStatClientData in response to its close() call.
Definition: pStatReader.cxx:61
std::string get_thread_name(int index) const
Returns the name of the indicated thread.
bool get_collector_has_level(int index, int thread_index) const
Returns whether the given collector has level data (and consequently, whether it should appear on the...