00001 // Filename: pStatClientData.cxx 00002 // Created by: drose (11Jul00) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "pStatClientData.h" 00016 #include "pStatReader.h" 00017 00018 #include "pStatCollectorDef.h" 00019 00020 PStatCollectorDef PStatClientData::_null_collector(-1, "Unknown"); 00021 00022 00023 00024 //////////////////////////////////////////////////////////////////// 00025 // Function: PStatClientData::Constructor 00026 // Access: Public 00027 // Description: 00028 //////////////////////////////////////////////////////////////////// 00029 PStatClientData:: 00030 PStatClientData(PStatReader *reader) : 00031 _reader(reader) 00032 { 00033 _is_alive = true; 00034 } 00035 00036 //////////////////////////////////////////////////////////////////// 00037 // Function: PStatClientData::Destructor 00038 // Access: Public 00039 // Description: 00040 //////////////////////////////////////////////////////////////////// 00041 PStatClientData:: 00042 ~PStatClientData() { 00043 Collectors::const_iterator ci; 00044 for (ci = _collectors.begin(); ci != _collectors.end(); ++ci) { 00045 delete (*ci)._def; 00046 } 00047 } 00048 00049 //////////////////////////////////////////////////////////////////// 00050 // Function: PStatClientData::is_alive 00051 // Access: Public 00052 // Description: Returns true if the data is actively getting filled 00053 // by a connected client, or false if the client has 00054 // terminated. 00055 //////////////////////////////////////////////////////////////////// 00056 bool PStatClientData:: 00057 is_alive() const { 00058 return _is_alive; 00059 } 00060 00061 //////////////////////////////////////////////////////////////////// 00062 // Function: PStatClientData::close 00063 // Access: Public 00064 // Description: Closes the client connection if it is open. 00065 //////////////////////////////////////////////////////////////////// 00066 void PStatClientData:: 00067 close() { 00068 if (_is_alive && _reader != (PStatReader *)NULL) { 00069 _reader->close(); 00070 _reader = (PStatReader *)NULL; 00071 _is_alive = false; 00072 } 00073 } 00074 00075 //////////////////////////////////////////////////////////////////// 00076 // Function: PStatClientData::get_num_collectors 00077 // Access: Public 00078 // Description: Returns the total number of collectors the Data 00079 // knows about. 00080 //////////////////////////////////////////////////////////////////// 00081 int PStatClientData:: 00082 get_num_collectors() const { 00083 return _collectors.size(); 00084 } 00085 00086 //////////////////////////////////////////////////////////////////// 00087 // Function: PStatClientData::has_collector 00088 // Access: Public 00089 // Description: Returns true if the indicated collector has been 00090 // defined by the client already, false otherwise. It 00091 // is possible for the client to start streaming data 00092 // before all of the collectors have been defined. 00093 //////////////////////////////////////////////////////////////////// 00094 bool PStatClientData:: 00095 has_collector(int index) const { 00096 return (index >= 0 && index < (int)_collectors.size() && 00097 _collectors[index]._def != (PStatCollectorDef *)NULL); 00098 } 00099 00100 //////////////////////////////////////////////////////////////////// 00101 // Function: PStatClientData::get_collector_def 00102 // Access: Public 00103 // Description: Returns the nth collector definition. 00104 //////////////////////////////////////////////////////////////////// 00105 const PStatCollectorDef &PStatClientData:: 00106 get_collector_def(int index) const { 00107 if (!has_collector(index)) { 00108 return _null_collector; 00109 } 00110 return *_collectors[index]._def; 00111 } 00112 00113 //////////////////////////////////////////////////////////////////// 00114 // Function: PStatClientData::get_collector_name 00115 // Access: Public 00116 // Description: Returns the name of the indicated collector. 00117 //////////////////////////////////////////////////////////////////// 00118 string PStatClientData:: 00119 get_collector_name(int index) const { 00120 if (!has_collector(index)) { 00121 return "Unknown"; 00122 } 00123 const PStatCollectorDef *def = _collectors[index]._def; 00124 return def->_name; 00125 } 00126 00127 //////////////////////////////////////////////////////////////////// 00128 // Function: PStatClientData::get_collector_fullname 00129 // Access: Public 00130 // Description: Returns the "full name" of the indicated collector. 00131 // This will be the concatenation of all of the 00132 // collector's parents' names (except Frame) and the 00133 // collector's own name. 00134 //////////////////////////////////////////////////////////////////// 00135 string PStatClientData:: 00136 get_collector_fullname(int index) const { 00137 if (!has_collector(index)) { 00138 return "Unknown"; 00139 } 00140 00141 const PStatCollectorDef *def = _collectors[index]._def; 00142 if (def->_parent_index == 0) { 00143 return def->_name; 00144 } else { 00145 return get_collector_fullname(def->_parent_index) + ":" + def->_name; 00146 } 00147 } 00148 00149 //////////////////////////////////////////////////////////////////// 00150 // Function: PStatClientData::set_collector_has_level 00151 // Access: Public 00152 // Description: Indicates whether the given collector has level data 00153 // (and consequently, whether it should appear on the 00154 // Levels menu). 00155 // 00156 // The return value is true if anything changed, false 00157 // otherwise. 00158 //////////////////////////////////////////////////////////////////// 00159 bool PStatClientData:: 00160 set_collector_has_level(int index, int thread_index, bool flag) { 00161 bool any_changed = false; 00162 slot_collector(index); 00163 nassertr(index >= 0 && index < (int)_collectors.size(), false); 00164 00165 if (_collectors[index]._is_level.get_bit(thread_index) != flag) { 00166 any_changed = true; 00167 _collectors[index]._is_level.set_bit_to(thread_index, flag); 00168 } 00169 00170 // Turning this on for a given collector also implicitly turns all 00171 // of its ancestors. 00172 if (flag) { 00173 PStatCollectorDef *def = _collectors[index]._def; 00174 if (def != (PStatCollectorDef *)NULL && def->_parent_index != 0) { 00175 if (set_collector_has_level(def->_parent_index, thread_index, flag)) { 00176 any_changed = true; 00177 } 00178 } 00179 } 00180 00181 return any_changed; 00182 } 00183 00184 00185 //////////////////////////////////////////////////////////////////// 00186 // Function: PStatClientData::get_collector_has_level 00187 // Access: Public 00188 // Description: Returns whether the given collector has level data 00189 // (and consequently, whether it should appear on the 00190 // Levels menu). 00191 //////////////////////////////////////////////////////////////////// 00192 bool PStatClientData:: 00193 get_collector_has_level(int index, int thread_index) const { 00194 return (index >= 0 && index < (int)_collectors.size() && 00195 _collectors[index]._is_level.get_bit(thread_index)); 00196 } 00197 00198 //////////////////////////////////////////////////////////////////// 00199 // Function: PStatClientData::get_num_toplevel_collectors 00200 // Access: Public 00201 // Description: Returns the total number of collectors that are 00202 // toplevel collectors. These are the collectors that 00203 // are the children of "Frame", which is collector 0. 00204 //////////////////////////////////////////////////////////////////// 00205 int PStatClientData:: 00206 get_num_toplevel_collectors() const { 00207 return _toplevel_collectors.size(); 00208 } 00209 00210 //////////////////////////////////////////////////////////////////// 00211 // Function: PStatClientData::get_toplevel_collector 00212 // Access: Public 00213 // Description: Returns the collector index of the nth toplevel 00214 // collector. Use this function to iterate through the 00215 // n toplevel collectors indicated by 00216 // get_num_toplevel_collectors(). 00217 //////////////////////////////////////////////////////////////////// 00218 int PStatClientData:: 00219 get_toplevel_collector(int n) const { 00220 nassertr(n >= 0 && n < (int)_toplevel_collectors.size(), 0); 00221 return _toplevel_collectors[n]; 00222 } 00223 00224 //////////////////////////////////////////////////////////////////// 00225 // Function: PStatClientData::get_num_threads 00226 // Access: Public 00227 // Description: Returns the total number of threads the Data 00228 // knows about. 00229 //////////////////////////////////////////////////////////////////// 00230 int PStatClientData:: 00231 get_num_threads() const { 00232 return _threads.size(); 00233 } 00234 00235 //////////////////////////////////////////////////////////////////// 00236 // Function: PStatClientData::has_thread 00237 // Access: Public 00238 // Description: Returns true if the indicated thread has been 00239 // defined by the client already, false otherwise. It 00240 // is possible for the client to start streaming data 00241 // before all of the threads have been defined. 00242 //////////////////////////////////////////////////////////////////// 00243 bool PStatClientData:: 00244 has_thread(int index) const { 00245 return (index >= 0 && index < (int)_threads.size() && 00246 !_threads[index]._name.empty()); 00247 } 00248 00249 //////////////////////////////////////////////////////////////////// 00250 // Function: PStatClientData::get_thread_name 00251 // Access: Public 00252 // Description: Returns the name of the indicated thread. 00253 //////////////////////////////////////////////////////////////////// 00254 string PStatClientData:: 00255 get_thread_name(int index) const { 00256 if (!has_thread(index)) { 00257 return "Unknown"; 00258 } 00259 return _threads[index]._name; 00260 } 00261 00262 //////////////////////////////////////////////////////////////////// 00263 // Function: PStatClientData::get_thread_data 00264 // Access: Public 00265 // Description: Returns the data associated with the indicated 00266 // thread. This will create a thread definition if it 00267 // does not already exist. 00268 //////////////////////////////////////////////////////////////////// 00269 const PStatThreadData *PStatClientData:: 00270 get_thread_data(int index) const { 00271 ((PStatClientData *)this)->define_thread(index); 00272 nassertr(index >= 0 && index < (int)_threads.size(), NULL); 00273 return _threads[index]._data; 00274 } 00275 00276 //////////////////////////////////////////////////////////////////// 00277 // Function: PStatClientData::get_child_distance 00278 // Access: Public 00279 // Description: Returns the number of Collectors between the 00280 // indicated parent and the child Collector in the 00281 // relationship graph. If child is the same as parent, 00282 // returns zero. If child is an immediate child of 00283 // parent, returns 1. If child is a grandchild of 00284 // parent, returns 2, and so on. If child is not a 00285 // descendant of parent at all, returns -1. 00286 //////////////////////////////////////////////////////////////////// 00287 int PStatClientData:: 00288 get_child_distance(int parent, int child) const { 00289 if (parent == child) { 00290 return 0; 00291 } 00292 if (!has_collector(child) || child == 0) { 00293 return -1; 00294 } 00295 int dist = get_child_distance(parent, get_collector_def(child)._parent_index); 00296 if (dist == -1) { 00297 return -1; 00298 } else { 00299 return dist + 1; 00300 } 00301 } 00302 00303 //////////////////////////////////////////////////////////////////// 00304 // Function: PStatClientData::add_collector 00305 // Access: Public 00306 // Description: Adds a new collector definition to the dataset. 00307 // Presumably this is information just arrived from the 00308 // client. 00309 // 00310 // The pointer will become owned by the PStatClientData 00311 // object and will be freed on destruction. 00312 //////////////////////////////////////////////////////////////////// 00313 void PStatClientData:: 00314 add_collector(PStatCollectorDef *def) { 00315 slot_collector(def->_index); 00316 nassertv(def->_index >= 0 && def->_index < (int)_collectors.size()); 00317 00318 if (_collectors[def->_index]._def != (PStatCollectorDef *)NULL) { 00319 // Free the old definition, if any. 00320 delete _collectors[def->_index]._def; 00321 } 00322 00323 _collectors[def->_index]._def = def; 00324 update_toplevel_collectors(); 00325 00326 // If we already had the _is_level flag set, it should be 00327 // immediately applied to all ancestors. 00328 const BitArray &is_level = _collectors[def->_index]._is_level; 00329 int max_threads = is_level.get_num_bits(); 00330 for (int thread_index = 0; thread_index < max_threads; ++thread_index) { 00331 if (is_level.get_bit(thread_index)) { 00332 set_collector_has_level(def->_parent_index, thread_index, true); 00333 } 00334 } 00335 } 00336 00337 //////////////////////////////////////////////////////////////////// 00338 // Function: PStatClientData::define_thread 00339 // Access: Public 00340 // Description: Adds a new thread definition to the dataset. 00341 // Presumably this is information just arrived from the 00342 // client. 00343 //////////////////////////////////////////////////////////////////// 00344 void PStatClientData:: 00345 define_thread(int thread_index, const string &name) { 00346 // A sanity check on the index number. 00347 nassertv(thread_index < 1000); 00348 00349 // Make sure we have enough slots allocated. 00350 while ((int)_threads.size() <= thread_index) { 00351 _threads.push_back(Thread()); 00352 } 00353 00354 if (!name.empty()) { 00355 _threads[thread_index]._name = name; 00356 } 00357 00358 if (_threads[thread_index]._data.is_null()) { 00359 _threads[thread_index]._data = new PStatThreadData(this); 00360 } 00361 } 00362 00363 00364 //////////////////////////////////////////////////////////////////// 00365 // Function: PStatClientData::record_new_frame 00366 // Access: Public 00367 // Description: Makes room for and stores a new frame's worth of 00368 // data associated with some particular thread (which 00369 // may or may not have already been defined). 00370 // 00371 // The pointer will become owned by the PStatThreadData 00372 // object and will be freed on destruction. 00373 //////////////////////////////////////////////////////////////////// 00374 void PStatClientData:: 00375 record_new_frame(int thread_index, int frame_number, 00376 PStatFrameData *frame_data) { 00377 define_thread(thread_index); 00378 nassertv(thread_index >= 0 && thread_index < (int)_threads.size()); 00379 _threads[thread_index]._data->record_new_frame(frame_number, frame_data); 00380 } 00381 00382 //////////////////////////////////////////////////////////////////// 00383 // Function: PStatClientData::slot_collector 00384 // Access: Private 00385 // Description: Makes sure there is an entry in the array for a 00386 // collector with the given index number. 00387 //////////////////////////////////////////////////////////////////// 00388 void PStatClientData:: 00389 slot_collector(int collector_index) { 00390 // A sanity check on the index number. 00391 nassertv(collector_index < 100000); 00392 00393 while ((int)_collectors.size() <= collector_index) { 00394 Collector collector; 00395 collector._def = (PStatCollectorDef *)NULL; 00396 _collectors.push_back(collector); 00397 } 00398 } 00399 00400 //////////////////////////////////////////////////////////////////// 00401 // Function: PStatClientData::update_toplevel_collectors 00402 // Access: Private 00403 // Description: Rebuilds the list of toplevel collectors. 00404 //////////////////////////////////////////////////////////////////// 00405 void PStatClientData:: 00406 update_toplevel_collectors() { 00407 _toplevel_collectors.clear(); 00408 00409 Collectors::const_iterator ci; 00410 for (ci = _collectors.begin(); ci != _collectors.end(); ++ci) { 00411 PStatCollectorDef *def = (*ci)._def; 00412 if (def != (PStatCollectorDef *)NULL && def->_parent_index == 0) { 00413 _toplevel_collectors.push_back(def->_index); 00414 } 00415 } 00416 }