Panda3D
pStatClientData.cxx
1 // Filename: pStatClientData.cxx
2 // Created by: drose (11Jul00)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "pStatClientData.h"
16 #include "pStatReader.h"
17 
18 #include "pStatCollectorDef.h"
19 
20 PStatCollectorDef PStatClientData::_null_collector(-1, "Unknown");
21 
22 
23 
24 ////////////////////////////////////////////////////////////////////
25 // Function: PStatClientData::Constructor
26 // Access: Public
27 // Description:
28 ////////////////////////////////////////////////////////////////////
29 PStatClientData::
30 PStatClientData(PStatReader *reader) :
31  _reader(reader)
32 {
33  _is_alive = true;
34 }
35 
36 ////////////////////////////////////////////////////////////////////
37 // Function: PStatClientData::Destructor
38 // Access: Public
39 // Description:
40 ////////////////////////////////////////////////////////////////////
41 PStatClientData::
42 ~PStatClientData() {
43  Collectors::const_iterator ci;
44  for (ci = _collectors.begin(); ci != _collectors.end(); ++ci) {
45  delete (*ci)._def;
46  }
47 }
48 
49 ////////////////////////////////////////////////////////////////////
50 // Function: PStatClientData::is_alive
51 // Access: Public
52 // Description: Returns true if the data is actively getting filled
53 // by a connected client, or false if the client has
54 // terminated.
55 ////////////////////////////////////////////////////////////////////
57 is_alive() const {
58  return _is_alive;
59 }
60 
61 ////////////////////////////////////////////////////////////////////
62 // Function: PStatClientData::close
63 // Access: Public
64 // Description: Closes the client connection if it is open.
65 ////////////////////////////////////////////////////////////////////
67 close() {
68  if (_is_alive && _reader != (PStatReader *)NULL) {
69  _reader->close();
70  _reader = (PStatReader *)NULL;
71  _is_alive = false;
72  }
73 }
74 
75 ////////////////////////////////////////////////////////////////////
76 // Function: PStatClientData::get_num_collectors
77 // Access: Public
78 // Description: Returns the total number of collectors the Data
79 // knows about.
80 ////////////////////////////////////////////////////////////////////
83  return _collectors.size();
84 }
85 
86 ////////////////////////////////////////////////////////////////////
87 // Function: PStatClientData::has_collector
88 // Access: Public
89 // Description: Returns true if the indicated collector has been
90 // defined by the client already, false otherwise. It
91 // is possible for the client to start streaming data
92 // before all of the collectors have been defined.
93 ////////////////////////////////////////////////////////////////////
95 has_collector(int index) const {
96  return (index >= 0 && index < (int)_collectors.size() &&
97  _collectors[index]._def != (PStatCollectorDef *)NULL);
98 }
99 
100 ////////////////////////////////////////////////////////////////////
101 // Function: PStatClientData::get_collector_def
102 // Access: Public
103 // Description: Returns the nth collector definition.
104 ////////////////////////////////////////////////////////////////////
106 get_collector_def(int index) const {
107  if (!has_collector(index)) {
108  return _null_collector;
109  }
110  return *_collectors[index]._def;
111 }
112 
113 ////////////////////////////////////////////////////////////////////
114 // Function: PStatClientData::get_collector_name
115 // Access: Public
116 // Description: Returns the name of the indicated collector.
117 ////////////////////////////////////////////////////////////////////
118 string PStatClientData::
119 get_collector_name(int index) const {
120  if (!has_collector(index)) {
121  return "Unknown";
122  }
123  const PStatCollectorDef *def = _collectors[index]._def;
124  return def->_name;
125 }
126 
127 ////////////////////////////////////////////////////////////////////
128 // Function: PStatClientData::get_collector_fullname
129 // Access: Public
130 // Description: Returns the "full name" of the indicated collector.
131 // This will be the concatenation of all of the
132 // collector's parents' names (except Frame) and the
133 // collector's own name.
134 ////////////////////////////////////////////////////////////////////
135 string PStatClientData::
136 get_collector_fullname(int index) const {
137  if (!has_collector(index)) {
138  return "Unknown";
139  }
140 
141  const PStatCollectorDef *def = _collectors[index]._def;
142  if (def->_parent_index == 0) {
143  return def->_name;
144  } else {
145  return get_collector_fullname(def->_parent_index) + ":" + def->_name;
146  }
147 }
148 
149 ////////////////////////////////////////////////////////////////////
150 // Function: PStatClientData::set_collector_has_level
151 // Access: Public
152 // Description: Indicates whether the given collector has level data
153 // (and consequently, whether it should appear on the
154 // Levels menu).
155 //
156 // The return value is true if anything changed, false
157 // otherwise.
158 ////////////////////////////////////////////////////////////////////
160 set_collector_has_level(int index, int thread_index, bool flag) {
161  bool any_changed = false;
162  slot_collector(index);
163  nassertr(index >= 0 && index < (int)_collectors.size(), false);
164 
165  if (_collectors[index]._is_level.get_bit(thread_index) != flag) {
166  any_changed = true;
167  _collectors[index]._is_level.set_bit_to(thread_index, flag);
168  }
169 
170  // Turning this on for a given collector also implicitly turns all
171  // of its ancestors.
172  if (flag) {
173  PStatCollectorDef *def = _collectors[index]._def;
174  if (def != (PStatCollectorDef *)NULL && def->_parent_index != 0) {
175  if (set_collector_has_level(def->_parent_index, thread_index, flag)) {
176  any_changed = true;
177  }
178  }
179  }
180 
181  return any_changed;
182 }
183 
184 
185 ////////////////////////////////////////////////////////////////////
186 // Function: PStatClientData::get_collector_has_level
187 // Access: Public
188 // Description: Returns whether the given collector has level data
189 // (and consequently, whether it should appear on the
190 // Levels menu).
191 ////////////////////////////////////////////////////////////////////
193 get_collector_has_level(int index, int thread_index) const {
194  return (index >= 0 && index < (int)_collectors.size() &&
195  _collectors[index]._is_level.get_bit(thread_index));
196 }
197 
198 ////////////////////////////////////////////////////////////////////
199 // Function: PStatClientData::get_num_toplevel_collectors
200 // Access: Public
201 // Description: Returns the total number of collectors that are
202 // toplevel collectors. These are the collectors that
203 // are the children of "Frame", which is collector 0.
204 ////////////////////////////////////////////////////////////////////
207  return _toplevel_collectors.size();
208 }
209 
210 ////////////////////////////////////////////////////////////////////
211 // Function: PStatClientData::get_toplevel_collector
212 // Access: Public
213 // Description: Returns the collector index of the nth toplevel
214 // collector. Use this function to iterate through the
215 // n toplevel collectors indicated by
216 // get_num_toplevel_collectors().
217 ////////////////////////////////////////////////////////////////////
220  nassertr(n >= 0 && n < (int)_toplevel_collectors.size(), 0);
221  return _toplevel_collectors[n];
222 }
223 
224 ////////////////////////////////////////////////////////////////////
225 // Function: PStatClientData::get_num_threads
226 // Access: Public
227 // Description: Returns the total number of threads the Data
228 // knows about.
229 ////////////////////////////////////////////////////////////////////
232  return _threads.size();
233 }
234 
235 ////////////////////////////////////////////////////////////////////
236 // Function: PStatClientData::has_thread
237 // Access: Public
238 // Description: Returns true if the indicated thread has been
239 // defined by the client already, false otherwise. It
240 // is possible for the client to start streaming data
241 // before all of the threads have been defined.
242 ////////////////////////////////////////////////////////////////////
244 has_thread(int index) const {
245  return (index >= 0 && index < (int)_threads.size() &&
246  !_threads[index]._name.empty());
247 }
248 
249 ////////////////////////////////////////////////////////////////////
250 // Function: PStatClientData::get_thread_name
251 // Access: Public
252 // Description: Returns the name of the indicated thread.
253 ////////////////////////////////////////////////////////////////////
254 string PStatClientData::
255 get_thread_name(int index) const {
256  if (!has_thread(index)) {
257  return "Unknown";
258  }
259  return _threads[index]._name;
260 }
261 
262 ////////////////////////////////////////////////////////////////////
263 // Function: PStatClientData::get_thread_data
264 // Access: Public
265 // Description: Returns the data associated with the indicated
266 // thread. This will create a thread definition if it
267 // does not already exist.
268 ////////////////////////////////////////////////////////////////////
270 get_thread_data(int index) const {
271  ((PStatClientData *)this)->define_thread(index);
272  nassertr(index >= 0 && index < (int)_threads.size(), NULL);
273  return _threads[index]._data;
274 }
275 
276 ////////////////////////////////////////////////////////////////////
277 // Function: PStatClientData::get_child_distance
278 // Access: Public
279 // Description: Returns the number of Collectors between the
280 // indicated parent and the child Collector in the
281 // relationship graph. If child is the same as parent,
282 // returns zero. If child is an immediate child of
283 // parent, returns 1. If child is a grandchild of
284 // parent, returns 2, and so on. If child is not a
285 // descendant of parent at all, returns -1.
286 ////////////////////////////////////////////////////////////////////
288 get_child_distance(int parent, int child) const {
289  if (parent == child) {
290  return 0;
291  }
292  if (!has_collector(child) || child == 0) {
293  return -1;
294  }
295  int dist = get_child_distance(parent, get_collector_def(child)._parent_index);
296  if (dist == -1) {
297  return -1;
298  } else {
299  return dist + 1;
300  }
301 }
302 
303 ////////////////////////////////////////////////////////////////////
304 // Function: PStatClientData::add_collector
305 // Access: Public
306 // Description: Adds a new collector definition to the dataset.
307 // Presumably this is information just arrived from the
308 // client.
309 //
310 // The pointer will become owned by the PStatClientData
311 // object and will be freed on destruction.
312 ////////////////////////////////////////////////////////////////////
315  slot_collector(def->_index);
316  nassertv(def->_index >= 0 && def->_index < (int)_collectors.size());
317 
318  if (_collectors[def->_index]._def != (PStatCollectorDef *)NULL) {
319  // Free the old definition, if any.
320  delete _collectors[def->_index]._def;
321  }
322 
323  _collectors[def->_index]._def = def;
324  update_toplevel_collectors();
325 
326  // If we already had the _is_level flag set, it should be
327  // immediately applied to all ancestors.
328  const BitArray &is_level = _collectors[def->_index]._is_level;
329  int max_threads = is_level.get_num_bits();
330  for (int thread_index = 0; thread_index < max_threads; ++thread_index) {
331  if (is_level.get_bit(thread_index)) {
332  set_collector_has_level(def->_parent_index, thread_index, true);
333  }
334  }
335 }
336 
337 ////////////////////////////////////////////////////////////////////
338 // Function: PStatClientData::define_thread
339 // Access: Public
340 // Description: Adds a new thread definition to the dataset.
341 // Presumably this is information just arrived from the
342 // client.
343 ////////////////////////////////////////////////////////////////////
345 define_thread(int thread_index, const string &name) {
346  // A sanity check on the index number.
347  nassertv(thread_index < 1000);
348 
349  // Make sure we have enough slots allocated.
350  while ((int)_threads.size() <= thread_index) {
351  _threads.push_back(Thread());
352  }
353 
354  if (!name.empty()) {
355  _threads[thread_index]._name = name;
356  }
357 
358  if (_threads[thread_index]._data.is_null()) {
359  _threads[thread_index]._data = new PStatThreadData(this);
360  }
361 }
362 
363 
364 ////////////////////////////////////////////////////////////////////
365 // Function: PStatClientData::record_new_frame
366 // Access: Public
367 // Description: Makes room for and stores a new frame's worth of
368 // data associated with some particular thread (which
369 // may or may not have already been defined).
370 //
371 // The pointer will become owned by the PStatThreadData
372 // object and will be freed on destruction.
373 ////////////////////////////////////////////////////////////////////
375 record_new_frame(int thread_index, int frame_number,
376  PStatFrameData *frame_data) {
377  define_thread(thread_index);
378  nassertv(thread_index >= 0 && thread_index < (int)_threads.size());
379  _threads[thread_index]._data->record_new_frame(frame_number, frame_data);
380 }
381 
382 ////////////////////////////////////////////////////////////////////
383 // Function: PStatClientData::slot_collector
384 // Access: Private
385 // Description: Makes sure there is an entry in the array for a
386 // collector with the given index number.
387 ////////////////////////////////////////////////////////////////////
388 void PStatClientData::
389 slot_collector(int collector_index) {
390  // A sanity check on the index number.
391  nassertv(collector_index < 100000);
392 
393  while ((int)_collectors.size() <= collector_index) {
394  Collector collector;
395  collector._def = (PStatCollectorDef *)NULL;
396  _collectors.push_back(collector);
397  }
398 }
399 
400 ////////////////////////////////////////////////////////////////////
401 // Function: PStatClientData::update_toplevel_collectors
402 // Access: Private
403 // Description: Rebuilds the list of toplevel collectors.
404 ////////////////////////////////////////////////////////////////////
405 void PStatClientData::
406 update_toplevel_collectors() {
407  _toplevel_collectors.clear();
408 
409  Collectors::const_iterator ci;
410  for (ci = _collectors.begin(); ci != _collectors.end(); ++ci) {
411  PStatCollectorDef *def = (*ci)._def;
412  if (def != (PStatCollectorDef *)NULL && def->_parent_index == 0) {
413  _toplevel_collectors.push_back(def->_index);
414  }
415  }
416 }
void add_collector(PStatCollectorDef *def)
Adds a new collector definition to the dataset.
int get_num_bits() const
Returns the current number of possibly different bits in this array.
Definition: bitArray.I:194
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:207
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...
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.
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&#39;s worth of data associated with some particular thread (which m...
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:42
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:44
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...
const PStatThreadData * get_thread_data(int index) const
Returns the data associated with the indicated thread.
Defines the details about the Collectors: the name, the suggested color, etc.
void define_thread(int thread_index, const string &name=string())
Adds a new thread definition to the dataset.
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:69
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...