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  */
71 get_num_collectors() const {
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  */
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  */
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  */
185 get_toplevel_collector(int n) const {
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  */
194 get_num_threads() const {
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  */
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 }
A dynamic array with an unlimited number of bits.
Definition: bitArray.h:40
size_t get_num_bits() const
Returns the current number of possibly different bits in this array.
Definition: bitArray.I:89
bool get_bit(int index) const
Returns true if the nth bit is set, false if it is cleared.
Definition: bitArray.I:99
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...
std::string get_collector_fullname(int index) const
Returns the "full name" of the indicated collector.
bool has_thread(int index) const
Returns true if the indicated thread has been defined by the client already, false otherwise.
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...
const PStatCollectorDef & get_collector_def(int index) const
Returns the nth collector definition.
int get_num_threads() const
Returns the total number of threads the Data knows about.
bool is_alive() const
Returns true if the data is actively getting filled by a connected client, or false if the client has...
const PStatThreadData * get_thread_data(int index) const
Returns the data associated with the indicated thread.
void close()
Closes the client connection if it is open.
std::string get_thread_name(int index) const
Returns the name of the indicated thread.
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...
int get_num_toplevel_collectors() const
Returns the total number of collectors that are toplevel collectors.
int get_num_collectors() const
Returns the total number of collectors the Data knows about.
void define_thread(int thread_index, const std::string &name=std::string())
Adds a new thread definition to the dataset.
bool has_collector(int index) const
Returns true if the indicated collector has been defined by the client already, false otherwise.
int get_toplevel_collector(int index) const
Returns the collector index of the nth toplevel collector.
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...
void add_collector(PStatCollectorDef *def)
Adds a new collector definition to the dataset.
std::string get_collector_name(int index) const
Returns the name of the indicated collector.
Defines the details about the Collectors: the name, the suggested color, etc.
Contains the raw timing and level data for a single frame.
This is the class that does all the work for handling communications from a single Panda client.
Definition: pStatReader.h:41
void close()
This will be called by the PStatClientData in response to its close() call.
Definition: pStatReader.cxx:61
A collection of FrameData structures for recently-received frames within a particular thread.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.