Panda3D
 All Classes Functions Variables Enumerations
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 }
string get_thread_name(int index) const
Returns the name of the indicated thread.
bool get_bit(int index) const
Returns true if the nth bit is set, false if it is cleared.
Definition: bitArray.I:207
void add_collector(PStatCollectorDef *def)
Adds a new collector definition to the dataset.
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...
string get_collector_name(int index) const
Returns the name of the indicated collector.
void close()
Closes the client connection if it is open.
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_num_collectors() const
Returns the total number of collectors the Data knows about.
string get_collector_fullname(int index) const
Returns the &quot;full name&quot; of the indicated collector.
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...
bool has_collector(int index) const
Returns true if the indicated collector has been defined by the client already, false otherwise...
bool has_thread(int index) const
Returns true if the indicated thread has been defined by the client already, false otherwise...
A dynamic array with an unlimited number of bits.
Definition: bitArray.h:42
This is the class that does all the work for handling communications from a single Panda client...
Definition: pStatReader.h:44
const PStatCollectorDef & get_collector_def(int index) const
Returns the nth collector definition.
bool is_alive() const
Returns true if the data is actively getting filled by a connected client, or false if the client has...
Contains the raw timing and level data for a single frame.
A collection of FrameData structures for recently-received frames within a particular thread...
int get_toplevel_collector(int index) const
Returns the collector index of the nth toplevel collector.
const PStatThreadData * get_thread_data(int index) const
Returns the data associated with 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...
int get_num_bits() const
Returns the current number of possibly different bits in this array.
Definition: bitArray.I:194
int get_num_toplevel_collectors() const
Returns the total number of collectors that are toplevel collectors.
int get_num_threads() const
Returns the total number of threads the Data knows about.
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.
void close()
This will be called by the PStatClientData in response to its close() call.
Definition: pStatReader.cxx:69