Panda3D
|
00001 // Filename: pStatClient.cxx 00002 // Created by: drose (09Jul00) 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 "pStatClient.h" 00016 00017 #ifdef DO_PSTATS 00018 // This file only defines anything interesting if DO_PSTATS is 00019 // defined. 00020 00021 #include "pStatClientImpl.h" 00022 #include "pStatClientControlMessage.h" 00023 #include "pStatServerControlMessage.h" 00024 #include "pStatCollector.h" 00025 #include "pStatThread.h" 00026 #include "config_pstats.h" 00027 #include "pStatProperties.h" 00028 #include "thread.h" 00029 #include "clockObject.h" 00030 #include "neverFreeMemory.h" 00031 00032 PStatCollector PStatClient::_heap_total_size_pcollector("System memory:Heap"); 00033 PStatCollector PStatClient::_heap_overhead_size_pcollector("System memory:Heap:Overhead"); 00034 PStatCollector PStatClient::_heap_single_size_pcollector("System memory:Heap:Single"); 00035 PStatCollector PStatClient::_heap_single_other_size_pcollector("System memory:Heap:Single:Other"); 00036 PStatCollector PStatClient::_heap_array_size_pcollector("System memory:Heap:Array"); 00037 PStatCollector PStatClient::_heap_array_other_size_pcollector("System memory:Heap:Array:Other"); 00038 PStatCollector PStatClient::_heap_external_size_pcollector("System memory:Heap:External"); 00039 PStatCollector PStatClient::_mmap_size_pcollector("System memory:MMap"); 00040 00041 PStatCollector PStatClient::_mmap_nf_unused_size_pcollector("System memory:MMap:NeverFree:Unused"); 00042 PStatCollector PStatClient::_mmap_dc_active_other_size_pcollector("System memory:MMap:NeverFree:Active:Other"); 00043 PStatCollector PStatClient::_mmap_dc_inactive_other_size_pcollector("System memory:MMap:NeverFree:Inactive:Other"); 00044 PStatCollector PStatClient::_pstats_pcollector("*:PStats"); 00045 PStatCollector PStatClient::_clock_wait_pcollector("Wait:Clock Wait:Sleep"); 00046 PStatCollector PStatClient::_clock_busy_wait_pcollector("Wait:Clock Wait:Spin"); 00047 PStatCollector PStatClient::_thread_block_pcollector("Wait:Thread block"); 00048 00049 PStatClient *PStatClient::_global_pstats = NULL; 00050 00051 00052 // This class is used to report memory usage per TypeHandle. We 00053 // create one of these for each TypeHandle in the system. 00054 class TypeHandleCollector { 00055 public: 00056 PStatCollector _mem_class[TypeHandle::MC_limit]; 00057 }; 00058 typedef pvector<TypeHandleCollector> TypeHandleCols; 00059 static TypeHandleCols type_handle_cols; 00060 00061 00062 //////////////////////////////////////////////////////////////////// 00063 // Function: PStatClient::PerThreadData::Constructor 00064 // Access: Public 00065 // Description: 00066 //////////////////////////////////////////////////////////////////// 00067 PStatClient::PerThreadData:: 00068 PerThreadData() { 00069 _has_level = false; 00070 _level = 0.0; 00071 _nested_count = 0; 00072 } 00073 00074 //////////////////////////////////////////////////////////////////// 00075 // Function: PStatClient::Constructor 00076 // Access: Public 00077 // Description: 00078 //////////////////////////////////////////////////////////////////// 00079 PStatClient:: 00080 PStatClient() : 00081 _lock("PStatClient::_lock"), 00082 _impl(NULL) 00083 { 00084 _collectors = NULL; 00085 _collectors_size = 0; 00086 _num_collectors = 0; 00087 00088 _threads = NULL; 00089 _threads_size = 0; 00090 _num_threads = 0; 00091 00092 // We always have a collector at index 0 named "Frame". This tracks 00093 // the total frame time and is the root of all other collectors. We 00094 // have to make this one by hand since it's the root. 00095 Collector *collector = new Collector(0, "Frame"); 00096 //collector->_def = new PStatCollectorDef(0, "Frame"); 00097 //collector->_def->_parent_index = 0; 00098 //collector->_def->_suggested_color.set(0.5, 0.5, 0.5); 00099 add_collector(collector); 00100 00101 // The main thread is always at index 0. 00102 make_thread(Thread::get_main_thread()); 00103 } 00104 00105 //////////////////////////////////////////////////////////////////// 00106 // Function: PStatClient::Destructor 00107 // Access: Public 00108 // Description: 00109 //////////////////////////////////////////////////////////////////// 00110 PStatClient:: 00111 ~PStatClient() { 00112 disconnect(); 00113 } 00114 00115 //////////////////////////////////////////////////////////////////// 00116 // Function: PStatClient::get_collector 00117 // Access: Published 00118 // Description: Returns the nth collector. 00119 //////////////////////////////////////////////////////////////////// 00120 PStatCollector PStatClient:: 00121 get_collector(int index) const { 00122 nassertr(index >= 0 && index < AtomicAdjust::get(_num_collectors), PStatCollector()); 00123 return PStatCollector((PStatClient *)this, index); 00124 } 00125 00126 //////////////////////////////////////////////////////////////////// 00127 // Function: PStatClient::get_collector_name 00128 // Access: Published 00129 // Description: Returns the name of the indicated collector. 00130 //////////////////////////////////////////////////////////////////// 00131 string PStatClient:: 00132 get_collector_name(int index) const { 00133 nassertr(index >= 0 && index < AtomicAdjust::get(_num_collectors), string()); 00134 00135 return get_collector_ptr(index)->get_name(); 00136 } 00137 00138 //////////////////////////////////////////////////////////////////// 00139 // Function: PStatClient::get_collector_fullname 00140 // Access: Published 00141 // Description: Returns the "full name" of the indicated collector. 00142 // This will be the concatenation of all of the 00143 // collector's parents' names (except Frame) and the 00144 // collector's own name. 00145 //////////////////////////////////////////////////////////////////// 00146 string PStatClient:: 00147 get_collector_fullname(int index) const { 00148 nassertr(index >= 0 && index < AtomicAdjust::get(_num_collectors), string()); 00149 00150 Collector *collector = get_collector_ptr(index); 00151 int parent_index = collector->get_parent_index(); 00152 if (parent_index == 0) { 00153 return collector->get_name(); 00154 } else { 00155 return get_collector_fullname(parent_index) + ":" + 00156 collector->get_name(); 00157 } 00158 } 00159 00160 //////////////////////////////////////////////////////////////////// 00161 // Function: PStatClient::get_thread 00162 // Access: Published 00163 // Description: Returns the nth thread. 00164 //////////////////////////////////////////////////////////////////// 00165 PStatThread PStatClient:: 00166 get_thread(int index) const { 00167 ReMutexHolder holder(_lock); 00168 nassertr(index >= 0 && index < _num_threads, PStatThread()); 00169 return PStatThread((PStatClient *)this, index); 00170 } 00171 00172 //////////////////////////////////////////////////////////////////// 00173 // Function: PStatClient::get_main_thread 00174 // Access: Published 00175 // Description: Returns a handle to the client's Main thread. This 00176 // is the thread that started the application. 00177 //////////////////////////////////////////////////////////////////// 00178 PStatThread PStatClient:: 00179 get_main_thread() const { 00180 return PStatThread((PStatClient *)this, 0); 00181 } 00182 00183 00184 //////////////////////////////////////////////////////////////////// 00185 // Function: PStatClient::get_current_thread 00186 // Access: Published 00187 // Description: Returns a handle to the currently-executing thread. 00188 // This is the thread that PStatCollectors will be 00189 // counted in if they do not specify otherwise. 00190 //////////////////////////////////////////////////////////////////// 00191 PStatThread PStatClient:: 00192 get_current_thread() const { 00193 if (!client_is_connected()) { 00194 // No need to make the relatively expensive call to 00195 // Thread::get_current_thread() if we're not even connected. 00196 return get_main_thread(); 00197 } 00198 return PStatThread(Thread::get_current_thread(), (PStatClient *)this); 00199 } 00200 00201 //////////////////////////////////////////////////////////////////// 00202 // Function: PStatClient::main_tick 00203 // Access: Published, Static 00204 // Description: A convenience function to call new_frame() on the 00205 // global PStatClient's main thread, and any other 00206 // threads with a sync_name of "Main". 00207 //////////////////////////////////////////////////////////////////// 00208 void PStatClient:: 00209 main_tick() { 00210 // We have code here to report the memory usage. We can't put this 00211 // code inside the MemoryUsage class, where it fits a little better, 00212 // simply because MemoryUsage is a very low-level class that doesn't 00213 // know about PStatClient. 00214 00215 #ifdef DO_MEMORY_USAGE 00216 if (is_connected()) { 00217 _heap_total_size_pcollector.set_level(MemoryUsage::get_total_size()); 00218 _heap_overhead_size_pcollector.set_level(MemoryUsage::get_panda_heap_overhead()); 00219 _heap_single_size_pcollector.set_level(MemoryUsage::get_panda_heap_single_size()); 00220 _heap_array_size_pcollector.set_level(MemoryUsage::get_panda_heap_array_size()); 00221 _heap_external_size_pcollector.set_level(MemoryUsage::get_external_size()); 00222 00223 00224 _mmap_size_pcollector.set_level(MemoryUsage::get_panda_mmap_size()); 00225 00226 TypeRegistry *type_reg = TypeRegistry::ptr(); 00227 int num_typehandles = type_reg->get_num_typehandles(); 00228 00229 while ((int)type_handle_cols.size() < num_typehandles) { 00230 type_handle_cols.push_back(TypeHandleCollector()); 00231 } 00232 00233 size_t single_total_usage = 0; 00234 size_t array_total_usage = 0; 00235 size_t dc_active_total_usage = 0; 00236 size_t dc_inactive_total_usage = 0; 00237 int i; 00238 for (i = 0; i < num_typehandles; ++i) { 00239 TypeHandle type = type_reg->get_typehandle(i); 00240 for (int mi = 0; mi < (int)TypeHandle::MC_limit; ++mi) { 00241 TypeHandle::MemoryClass mc = (TypeHandle::MemoryClass)mi; 00242 size_t usage = type.get_memory_usage(mc); 00243 00244 switch (mc) { 00245 case TypeHandle::MC_singleton: 00246 single_total_usage += usage; 00247 break; 00248 00249 case TypeHandle::MC_array: 00250 array_total_usage += usage; 00251 break; 00252 00253 case TypeHandle::MC_deleted_chain_active: 00254 dc_active_total_usage += usage; 00255 break; 00256 00257 case TypeHandle::MC_deleted_chain_inactive: 00258 dc_inactive_total_usage += usage; 00259 break; 00260 00261 case TypeHandle::MC_limit: 00262 // Not used. 00263 break; 00264 } 00265 } 00266 } 00267 size_t min_usage = (single_total_usage + array_total_usage + dc_active_total_usage + dc_inactive_total_usage) / 1024; 00268 if (!pstats_mem_other) { 00269 min_usage = 0; 00270 } 00271 size_t single_other_usage = single_total_usage; 00272 size_t array_other_usage = array_total_usage; 00273 size_t dc_active_other_usage = dc_active_total_usage; 00274 size_t dc_inactive_other_usage = dc_inactive_total_usage; 00275 00276 for (i = 0; i < num_typehandles; ++i) { 00277 TypeHandle type = type_reg->get_typehandle(i); 00278 for (int mi = 0; mi < (int)TypeHandle::MC_limit; ++mi) { 00279 TypeHandle::MemoryClass mc = (TypeHandle::MemoryClass)mi; 00280 PStatCollector &col = type_handle_cols[i]._mem_class[mi]; 00281 size_t usage = type.get_memory_usage(mc); 00282 if (usage > min_usage || col.is_valid()) { 00283 // We have some memory usage on this TypeHandle. See if we 00284 // have a collector for it. 00285 if (!col.is_valid()) { 00286 const char *category = ""; 00287 switch (mc) { 00288 case TypeHandle::MC_singleton: 00289 category = "Heap:Single"; 00290 break; 00291 00292 case TypeHandle::MC_array: 00293 category = "Heap:Array"; 00294 break; 00295 00296 case TypeHandle::MC_deleted_chain_active: 00297 category = "MMap:NeverFree:Active"; 00298 break; 00299 00300 case TypeHandle::MC_deleted_chain_inactive: 00301 category = "MMap:NeverFree:Inactive"; 00302 break; 00303 00304 case TypeHandle::MC_limit: 00305 // Not used. 00306 break; 00307 } 00308 ostringstream strm; 00309 strm << "System memory:" << category << ":" << type; 00310 col = PStatCollector(strm.str()); 00311 } 00312 col.set_level(usage); 00313 00314 switch (mc) { 00315 case TypeHandle::MC_singleton: 00316 single_other_usage -= usage; 00317 break; 00318 00319 case TypeHandle::MC_array: 00320 array_other_usage -= usage; 00321 break; 00322 00323 case TypeHandle::MC_deleted_chain_active: 00324 dc_active_other_usage -= usage; 00325 break; 00326 00327 case TypeHandle::MC_deleted_chain_inactive: 00328 dc_inactive_other_usage -= usage; 00329 break; 00330 00331 case TypeHandle::MC_limit: 00332 // Not used. 00333 break; 00334 } 00335 } 00336 } 00337 } 00338 00339 _mmap_nf_unused_size_pcollector.set_level(NeverFreeMemory::get_total_unused()); 00340 00341 // The remaining amount--all collectors smaller than 0.1% of the 00342 // total--go into "other". 00343 _heap_single_other_size_pcollector.set_level(single_other_usage); 00344 _heap_array_other_size_pcollector.set_level(array_other_usage); 00345 _mmap_dc_active_other_size_pcollector.set_level(dc_active_other_usage); 00346 _mmap_dc_inactive_other_size_pcollector.set_level(dc_inactive_other_usage); 00347 } 00348 #endif // DO_MEMORY_USAGE 00349 00350 get_global_pstats()->client_main_tick(); 00351 } 00352 00353 //////////////////////////////////////////////////////////////////// 00354 // Function: PStatClient::thread_tick 00355 // Access: Published, Static 00356 // Description: A convenience function to call new_frame() on any 00357 // threads with the indicated sync_name 00358 //////////////////////////////////////////////////////////////////// 00359 void PStatClient:: 00360 thread_tick(const string &sync_name) { 00361 get_global_pstats()->client_thread_tick(sync_name); 00362 } 00363 00364 //////////////////////////////////////////////////////////////////// 00365 // Function: PStatClient::client_main_tick 00366 // Access: Published 00367 // Description: A convenience function to call new_frame() on the 00368 // given PStatClient's main thread, and any other 00369 // threads with a sync_name of "Main". 00370 //////////////////////////////////////////////////////////////////// 00371 void PStatClient:: 00372 client_main_tick() { 00373 ReMutexHolder holder(_lock); 00374 if (has_impl()) { 00375 if (!_impl->client_is_connected()) { 00376 client_disconnect(); 00377 return; 00378 } 00379 00380 _impl->client_main_tick(); 00381 00382 MultiThingsByName::const_iterator ni = 00383 _threads_by_sync_name.find("Main"); 00384 if (ni != _threads_by_sync_name.end()) { 00385 const vector_int &indices = (*ni).second; 00386 for (vector_int::const_iterator vi = indices.begin(); 00387 vi != indices.end(); 00388 ++vi) { 00389 _impl->new_frame(*vi); 00390 } 00391 } 00392 } 00393 } 00394 00395 //////////////////////////////////////////////////////////////////// 00396 // Function: PStatClient::client_thread_tick 00397 // Access: Published 00398 // Description: A convenience function to call new_frame() on all of 00399 // the threads with the indicated sync name. 00400 //////////////////////////////////////////////////////////////////// 00401 void PStatClient:: 00402 client_thread_tick(const string &sync_name) { 00403 ReMutexHolder holder(_lock); 00404 00405 if (has_impl()) { 00406 MultiThingsByName::const_iterator ni = 00407 _threads_by_sync_name.find(sync_name); 00408 if (ni != _threads_by_sync_name.end()) { 00409 const vector_int &indices = (*ni).second; 00410 for (vector_int::const_iterator vi = indices.begin(); 00411 vi != indices.end(); 00412 ++vi) { 00413 _impl->new_frame(*vi); 00414 } 00415 } 00416 } 00417 } 00418 00419 //////////////////////////////////////////////////////////////////// 00420 // Function: PStatClient::client_disconnect 00421 // Access: Published 00422 // Description: The nonstatic implementation of disconnect(). 00423 //////////////////////////////////////////////////////////////////// 00424 void PStatClient:: 00425 client_disconnect() { 00426 ReMutexHolder holder(_lock); 00427 if (has_impl()) { 00428 _impl->client_disconnect(); 00429 delete _impl; 00430 _impl = NULL; 00431 } 00432 00433 ThreadPointer *threads = (ThreadPointer *)_threads; 00434 for (int ti = 0; ti < _num_threads; ++ti) { 00435 InternalThread *thread = threads[ti]; 00436 thread->_frame_number = 0; 00437 thread->_is_active = false; 00438 thread->_next_packet = 0.0; 00439 thread->_frame_data.clear(); 00440 } 00441 00442 CollectorPointer *collectors = (CollectorPointer *)_collectors; 00443 for (int ci = 0; ci < _num_collectors; ++ci) { 00444 Collector *collector = collectors[ci]; 00445 PerThread::iterator ii; 00446 for (ii = collector->_per_thread.begin(); 00447 ii != collector->_per_thread.end(); 00448 ++ii) { 00449 (*ii)._nested_count = 0; 00450 } 00451 } 00452 } 00453 00454 //////////////////////////////////////////////////////////////////// 00455 // Function: PStatClient::get_global_pstats 00456 // Access: Published, Static 00457 // Description: Returns a pointer to the global PStatClient object. 00458 // It's legal to declare your own PStatClient locally, 00459 // but it's also convenient to have a global one that 00460 // everyone can register with. This is the global one. 00461 //////////////////////////////////////////////////////////////////// 00462 PStatClient *PStatClient:: 00463 get_global_pstats() { 00464 if (_global_pstats == (PStatClient *)NULL) { 00465 _global_pstats = new PStatClient; 00466 00467 ClockObject::_start_clock_wait = start_clock_wait; 00468 ClockObject::_start_clock_busy_wait = start_clock_busy_wait; 00469 ClockObject::_stop_clock_wait = stop_clock_wait; 00470 } 00471 return _global_pstats; 00472 } 00473 00474 //////////////////////////////////////////////////////////////////// 00475 // Function: PStatClient::make_collector_with_relname 00476 // Access: Private 00477 // Description: Returns a PStatCollector suitable for measuring 00478 // categories with the indicated name. This is normally 00479 // called by a PStatCollector constructor. 00480 // 00481 // The name may contain colons; if it does, it specifies 00482 // a relative path to the client indicated by the parent 00483 // index. 00484 //////////////////////////////////////////////////////////////////// 00485 PStatCollector PStatClient:: 00486 make_collector_with_relname(int parent_index, string relname) { 00487 ReMutexHolder holder(_lock); 00488 00489 if (relname.empty()) { 00490 relname = "Unnamed"; 00491 } 00492 00493 // Skip any colons at the beginning of the name. 00494 size_t start = 0; 00495 while (start < relname.size() && relname[start] == ':') { 00496 start++; 00497 } 00498 00499 // If the name contains a colon (after the initial colon), it means 00500 // we are making a nested collector. 00501 size_t colon = relname.find(':', start); 00502 while (colon != string::npos) { 00503 string parent_name = relname.substr(start, colon - start); 00504 PStatCollector parent_collector = 00505 make_collector_with_name(parent_index, parent_name); 00506 parent_index = parent_collector._index; 00507 relname = relname.substr(colon + 1); 00508 start = 0; 00509 colon = relname.find(':'); 00510 } 00511 00512 string name = relname.substr(start); 00513 return make_collector_with_name(parent_index, name); 00514 } 00515 00516 //////////////////////////////////////////////////////////////////// 00517 // Function: PStatClient::make_collector_with_name 00518 // Access: Private 00519 // Description: Returns a PStatCollector suitable for measuring 00520 // categories with the indicated name. This is normally 00521 // called by a PStatCollector constructor. 00522 // 00523 // The name should not contain colons. 00524 //////////////////////////////////////////////////////////////////// 00525 PStatCollector PStatClient:: 00526 make_collector_with_name(int parent_index, const string &name) { 00527 ReMutexHolder holder(_lock); 00528 00529 nassertr(parent_index >= 0 && parent_index < _num_collectors, 00530 PStatCollector()); 00531 00532 Collector *parent = get_collector_ptr(parent_index); 00533 00534 // A special case: if we asked for a child the same name as its 00535 // parent, we really meant the parent. That is, "Frame:Frame" is 00536 // really the same collector as "Frame". 00537 if (parent->get_name() == name) { 00538 return PStatCollector(this, parent_index); 00539 } 00540 00541 ThingsByName::const_iterator ni = parent->_children.find(name); 00542 00543 if (ni != parent->_children.end()) { 00544 // We already had a collector by this name; return it. 00545 int index = (*ni).second; 00546 nassertr(index >= 0 && index < _num_collectors, PStatCollector()); 00547 return PStatCollector(this, (*ni).second); 00548 } 00549 00550 // Create a new collector for this name. 00551 int new_index = _num_collectors; 00552 parent->_children.insert(ThingsByName::value_type(name, new_index)); 00553 00554 Collector *collector = new Collector(parent_index, name); 00555 // collector->_def = new PStatCollectorDef(new_index, name); 00556 // collector->_def->set_parent(*_collectors[parent_index]._def); 00557 // initialize_collector_def(this, collector->_def); 00558 00559 // We need one PerThreadData for each thread. 00560 while ((int)collector->_per_thread.size() < _num_threads) { 00561 collector->_per_thread.push_back(PerThreadData()); 00562 } 00563 add_collector(collector); 00564 00565 return PStatCollector(this, new_index); 00566 } 00567 00568 //////////////////////////////////////////////////////////////////// 00569 // Function: PStatClient::do_get_current_thread 00570 // Access: Private 00571 // Description: Similar to get_current_thread, but does not grab the 00572 // lock. 00573 //////////////////////////////////////////////////////////////////// 00574 PStatThread PStatClient:: 00575 do_get_current_thread() const { 00576 Thread *thread = Thread::get_current_thread(); 00577 int thread_index = thread->get_pstats_index(); 00578 if (thread_index != -1) { 00579 return PStatThread((PStatClient *)this, thread_index); 00580 } 00581 00582 // This is the first time we have encountered this current Thread. 00583 // Make a new PStatThread object for it. 00584 return ((PStatClient *)this)->do_make_thread(thread); 00585 } 00586 00587 //////////////////////////////////////////////////////////////////// 00588 // Function: PStatClient::make_thread 00589 // Access: Private 00590 // Description: Returns a PStatThread for the indicated Panda Thread 00591 // object. This is normally called by a PStatThread 00592 // constructor. 00593 //////////////////////////////////////////////////////////////////// 00594 PStatThread PStatClient:: 00595 make_thread(Thread *thread) { 00596 ReMutexHolder holder(_lock); 00597 return do_make_thread(thread); 00598 } 00599 00600 //////////////////////////////////////////////////////////////////// 00601 // Function: PStatClient::do_make_thread 00602 // Access: Private 00603 // Description: As above, but assumes the lock is already held. 00604 //////////////////////////////////////////////////////////////////// 00605 PStatThread PStatClient:: 00606 do_make_thread(Thread *thread) { 00607 int thread_index = thread->get_pstats_index(); 00608 if (thread_index != -1) { 00609 return PStatThread((PStatClient *)this, thread_index); 00610 } 00611 00612 MultiThingsByName::const_iterator ni = 00613 _threads_by_name.find(thread->get_name()); 00614 00615 if (ni != _threads_by_name.end()) { 00616 // We have seen a thread with this name before. Can we re-use any 00617 // of them? 00618 const vector_int &indices = (*ni).second; 00619 for (vector_int::const_iterator vi = indices.begin(); 00620 vi != indices.end(); 00621 ++vi) { 00622 int index = (*vi); 00623 nassertr(index >= 0 && index < _num_threads, PStatThread()); 00624 ThreadPointer *threads = (ThreadPointer *)_threads; 00625 if (threads[index]->_thread.was_deleted() && 00626 threads[index]->_sync_name == thread->get_sync_name()) { 00627 // Yes, re-use this one. 00628 threads[index]->_thread = thread; 00629 thread->set_pstats_index(index); 00630 thread->set_pstats_callback(this); 00631 return PStatThread(this, index); 00632 } 00633 } 00634 } 00635 00636 // Create a new PStatsThread for this thread pointer. 00637 int new_index = _num_threads; 00638 thread->set_pstats_index(new_index); 00639 thread->set_pstats_callback(this); 00640 _threads_by_name[thread->get_name()].push_back(new_index); 00641 _threads_by_sync_name[thread->get_sync_name()].push_back(new_index); 00642 00643 InternalThread *pthread = new InternalThread(thread); 00644 add_thread(pthread); 00645 00646 // We need an additional PerThreadData for this thread in all of the 00647 // collectors. 00648 CollectorPointer *collectors = (CollectorPointer *)_collectors; 00649 for (int ci = 0; ci < _num_collectors; ++ci) { 00650 Collector *collector = collectors[ci]; 00651 collector->_per_thread.push_back(PerThreadData()); 00652 nassertr((int)collector->_per_thread.size() == _num_threads, PStatThread()); 00653 } 00654 00655 return PStatThread(this, new_index); 00656 } 00657 00658 //////////////////////////////////////////////////////////////////// 00659 // Function: PStatClient::is_active 00660 // Access: Private 00661 // Description: Returns true if the indicated collector/thread 00662 // combination is active, and we are transmitting stats 00663 // data, or false otherwise. 00664 // 00665 // Normally you would not use this interface directly; 00666 // instead, call PStatCollector::is_active(). 00667 //////////////////////////////////////////////////////////////////// 00668 bool PStatClient:: 00669 is_active(int collector_index, int thread_index) const { 00670 nassertr(collector_index >= 0 && collector_index < AtomicAdjust::get(_num_collectors), false); 00671 nassertr(thread_index >= 0 && thread_index < AtomicAdjust::get(_num_threads), false); 00672 00673 return (client_is_connected() && 00674 get_collector_ptr(collector_index)->is_active() && 00675 get_thread_ptr(thread_index)->_is_active); 00676 } 00677 00678 //////////////////////////////////////////////////////////////////// 00679 // Function: PStatClient::is_started 00680 // Access: Private 00681 // Description: Returns true if the indicated collector/thread 00682 // combination has been started, or false otherwise. 00683 // 00684 // Normally you would not use this interface directly; 00685 // instead, call PStatCollector::is_started(). 00686 //////////////////////////////////////////////////////////////////// 00687 bool PStatClient:: 00688 is_started(int collector_index, int thread_index) const { 00689 nassertr(collector_index >= 0 && collector_index < AtomicAdjust::get(_num_collectors), false); 00690 nassertr(thread_index >= 0 && thread_index < AtomicAdjust::get(_num_threads), false); 00691 00692 Collector *collector = get_collector_ptr(collector_index); 00693 InternalThread *thread = get_thread_ptr(thread_index); 00694 00695 if (client_is_connected() && collector->is_active() && thread->_is_active) { 00696 LightMutexHolder holder(thread->_thread_lock); 00697 if (collector->_per_thread[thread_index]._nested_count == 0) { 00698 // Not started. 00699 return false; 00700 } 00701 // Started. 00702 return true; 00703 } 00704 00705 // Not even connected. 00706 return false; 00707 } 00708 00709 //////////////////////////////////////////////////////////////////// 00710 // Function: PStatClient::start 00711 // Access: Private 00712 // Description: Marks the indicated collector index as started. 00713 // Normally you would not use this interface directly; 00714 // instead, call PStatCollector::start(). 00715 //////////////////////////////////////////////////////////////////// 00716 void PStatClient:: 00717 start(int collector_index, int thread_index) { 00718 #ifdef _DEBUG 00719 nassertv(collector_index >= 0 && collector_index < AtomicAdjust::get(_num_collectors)); 00720 nassertv(thread_index >= 0 && thread_index < AtomicAdjust::get(_num_threads)); 00721 #endif 00722 00723 Collector *collector = get_collector_ptr(collector_index); 00724 InternalThread *thread = get_thread_ptr(thread_index); 00725 00726 if (client_is_connected() && collector->is_active() && thread->_is_active) { 00727 LightMutexHolder holder(thread->_thread_lock); 00728 if (collector->_per_thread[thread_index]._nested_count == 0) { 00729 // This collector wasn't already started in this thread; record 00730 // a new data point. 00731 if (thread->_thread_active) { 00732 thread->_frame_data.add_start(collector_index, get_real_time()); 00733 } 00734 } 00735 collector->_per_thread[thread_index]._nested_count++; 00736 } 00737 } 00738 00739 //////////////////////////////////////////////////////////////////// 00740 // Function: PStatClient::start 00741 // Access: Private 00742 // Description: Marks the indicated collector index as started. 00743 // Normally you would not use this interface directly; 00744 // instead, call PStatCollector::start(). 00745 //////////////////////////////////////////////////////////////////// 00746 void PStatClient:: 00747 start(int collector_index, int thread_index, double as_of) { 00748 #ifdef _DEBUG 00749 nassertv(collector_index >= 0 && collector_index < AtomicAdjust::get(_num_collectors)); 00750 nassertv(thread_index >= 0 && thread_index < AtomicAdjust::get(_num_threads)); 00751 #endif 00752 00753 Collector *collector = get_collector_ptr(collector_index); 00754 InternalThread *thread = get_thread_ptr(thread_index); 00755 00756 if (client_is_connected() && collector->is_active() && thread->_is_active) { 00757 LightMutexHolder holder(thread->_thread_lock); 00758 if (collector->_per_thread[thread_index]._nested_count == 0) { 00759 // This collector wasn't already started in this thread; record 00760 // a new data point. 00761 if (thread->_thread_active) { 00762 thread->_frame_data.add_start(collector_index, as_of); 00763 } 00764 } 00765 collector->_per_thread[thread_index]._nested_count++; 00766 } 00767 } 00768 00769 //////////////////////////////////////////////////////////////////// 00770 // Function: PStatClient::stop 00771 // Access: Private 00772 // Description: Marks the indicated collector index as stopped. 00773 // Normally you would not use this interface directly; 00774 // instead, call PStatCollector::stop(). 00775 //////////////////////////////////////////////////////////////////// 00776 void PStatClient:: 00777 stop(int collector_index, int thread_index) { 00778 #ifdef _DEBUG 00779 nassertv(collector_index >= 0 && collector_index < AtomicAdjust::get(_num_collectors)); 00780 nassertv(thread_index >= 0 && thread_index < AtomicAdjust::get(_num_threads)); 00781 #endif 00782 00783 Collector *collector = get_collector_ptr(collector_index); 00784 InternalThread *thread = get_thread_ptr(thread_index); 00785 00786 if (client_is_connected() && collector->is_active() && thread->_is_active) { 00787 LightMutexHolder holder(thread->_thread_lock); 00788 if (collector->_per_thread[thread_index]._nested_count == 0) { 00789 if (pstats_cat.is_debug()) { 00790 pstats_cat.debug() 00791 << "Collector " << get_collector_fullname(collector_index) 00792 << " was already stopped in thread " << get_thread_name(thread_index) 00793 << "!\n"; 00794 } 00795 return; 00796 } 00797 00798 collector->_per_thread[thread_index]._nested_count--; 00799 00800 if (collector->_per_thread[thread_index]._nested_count == 0) { 00801 // This collector has now been completely stopped; record a new 00802 // data point. 00803 if (thread->_thread_active) { 00804 thread->_frame_data.add_stop(collector_index, get_real_time()); 00805 } 00806 } 00807 } 00808 } 00809 00810 //////////////////////////////////////////////////////////////////// 00811 // Function: PStatClient::stop 00812 // Access: Private 00813 // Description: Marks the indicated collector index as stopped. 00814 // Normally you would not use this interface directly; 00815 // instead, call PStatCollector::stop(). 00816 //////////////////////////////////////////////////////////////////// 00817 void PStatClient:: 00818 stop(int collector_index, int thread_index, double as_of) { 00819 #ifdef _DEBUG 00820 nassertv(collector_index >= 0 && collector_index < AtomicAdjust::get(_num_collectors)); 00821 nassertv(thread_index >= 0 && thread_index < AtomicAdjust::get(_num_threads)); 00822 #endif 00823 00824 Collector *collector = get_collector_ptr(collector_index); 00825 InternalThread *thread = get_thread_ptr(thread_index); 00826 00827 if (client_is_connected() && collector->is_active() && thread->_is_active) { 00828 LightMutexHolder holder(thread->_thread_lock); 00829 if (collector->_per_thread[thread_index]._nested_count == 0) { 00830 if (pstats_cat.is_debug()) { 00831 pstats_cat.debug() 00832 << "Collector " << get_collector_fullname(collector_index) 00833 << " was already stopped in thread " << get_thread_name(thread_index) 00834 << "!\n"; 00835 } 00836 return; 00837 } 00838 00839 collector->_per_thread[thread_index]._nested_count--; 00840 00841 if (collector->_per_thread[thread_index]._nested_count == 0) { 00842 // This collector has now been completely stopped; record a new 00843 // data point. 00844 thread->_frame_data.add_stop(collector_index, as_of); 00845 } 00846 } 00847 } 00848 00849 //////////////////////////////////////////////////////////////////// 00850 // Function: PStatClient::clear_level 00851 // Access: Private 00852 // Description: Removes the level value from the indicated collector. 00853 // The collector will no longer be reported as having 00854 // any particular level value. 00855 // 00856 // Normally you would not use this interface directly; 00857 // instead, call PStatCollector::clear_level(). 00858 //////////////////////////////////////////////////////////////////// 00859 void PStatClient:: 00860 clear_level(int collector_index, int thread_index) { 00861 #ifdef _DEBUG 00862 nassertv(collector_index >= 0 && collector_index < AtomicAdjust::get(_num_collectors)); 00863 nassertv(thread_index >= 0 && thread_index < AtomicAdjust::get(_num_threads)); 00864 #endif 00865 00866 Collector *collector = get_collector_ptr(collector_index); 00867 InternalThread *thread = get_thread_ptr(thread_index); 00868 LightMutexHolder holder(thread->_thread_lock); 00869 00870 collector->_per_thread[thread_index]._has_level = true; 00871 collector->_per_thread[thread_index]._level = 0.0; 00872 } 00873 00874 //////////////////////////////////////////////////////////////////// 00875 // Function: PStatClient::set_level 00876 // Access: Private 00877 // Description: Sets the level value for the indicated collector to 00878 // the given amount. 00879 // 00880 // Normally you would not use this interface directly; 00881 // instead, call PStatCollector::set_level(). 00882 //////////////////////////////////////////////////////////////////// 00883 void PStatClient:: 00884 set_level(int collector_index, int thread_index, double level) { 00885 #ifdef _DEBUG 00886 nassertv(collector_index >= 0 && collector_index < AtomicAdjust::get(_num_collectors)); 00887 nassertv(thread_index >= 0 && thread_index < AtomicAdjust::get(_num_threads)); 00888 #endif 00889 00890 Collector *collector = get_collector_ptr(collector_index); 00891 InternalThread *thread = get_thread_ptr(thread_index); 00892 00893 // We don't want to condition this on whether the client is already 00894 // connected or the collector is already active, since we might 00895 // connect the client later, and we will want to have an accurate 00896 // value at that time. 00897 LightMutexHolder holder(thread->_thread_lock); 00898 00899 level *= collector->get_def(this, collector_index)->_factor; 00900 00901 collector->_per_thread[thread_index]._has_level = true; 00902 collector->_per_thread[thread_index]._level = level; 00903 } 00904 00905 //////////////////////////////////////////////////////////////////// 00906 // Function: PStatClient::add_level 00907 // Access: Private 00908 // Description: Adds the given value (which may be negative) to the 00909 // current value for the given collector. If the 00910 // collector does not already have a level value, it is 00911 // initialized to 0. 00912 // 00913 // Normally you would not use this interface directly; 00914 // instead, call PStatCollector::add_level(). 00915 //////////////////////////////////////////////////////////////////// 00916 void PStatClient:: 00917 add_level(int collector_index, int thread_index, double increment) { 00918 #ifdef _DEBUG 00919 nassertv(collector_index >= 0 && collector_index < AtomicAdjust::get(_num_collectors)); 00920 nassertv(thread_index >= 0 && thread_index < AtomicAdjust::get(_num_threads)); 00921 #endif 00922 00923 Collector *collector = get_collector_ptr(collector_index); 00924 InternalThread *thread = get_thread_ptr(thread_index); 00925 LightMutexHolder holder(thread->_thread_lock); 00926 00927 increment *= collector->get_def(this, collector_index)->_factor; 00928 00929 collector->_per_thread[thread_index]._has_level = true; 00930 collector->_per_thread[thread_index]._level += increment; 00931 } 00932 00933 //////////////////////////////////////////////////////////////////// 00934 // Function: PStatClient::get_level 00935 // Access: Private 00936 // Description: Returns the current level value of the given collector. 00937 // 00938 // Normally you would not use this interface directly; 00939 // instead, call PStatCollector::get_level(). 00940 //////////////////////////////////////////////////////////////////// 00941 double PStatClient:: 00942 get_level(int collector_index, int thread_index) const { 00943 #ifdef _DEBUG 00944 nassertr(collector_index >= 0 && collector_index < AtomicAdjust::get(_num_collectors), 0.0f); 00945 nassertr(thread_index >= 0 && thread_index < AtomicAdjust::get(_num_threads), 0.0f); 00946 #endif 00947 00948 Collector *collector = get_collector_ptr(collector_index); 00949 InternalThread *thread = get_thread_ptr(thread_index); 00950 LightMutexHolder holder(thread->_thread_lock); 00951 00952 double factor = collector->get_def(this, collector_index)->_factor; 00953 00954 return collector->_per_thread[thread_index]._level / factor; 00955 } 00956 00957 //////////////////////////////////////////////////////////////////// 00958 // Function: PStatClient::start_clock_wait 00959 // Access: Private, Static 00960 // Description: This function is added as a hook into ClockObject, so 00961 // that we may time the delay for 00962 // ClockObject::wait_until(), used for certain special 00963 // clock modes. 00964 // 00965 // This callback is a hack around the fact that we can't 00966 // let the ClockObject directly create a PStatCollector, 00967 // because the pstatclient module depends on putil. 00968 //////////////////////////////////////////////////////////////////// 00969 void PStatClient:: 00970 start_clock_wait() { 00971 _clock_wait_pcollector.start(); 00972 } 00973 00974 //////////////////////////////////////////////////////////////////// 00975 // Function: PStatClient::start_clock_busy_wait 00976 // Access: Private, Static 00977 // Description: This function is added as a hook into ClockObject, so 00978 // that we may time the delay for 00979 // ClockObject::wait_until(), used for certain special 00980 // clock modes. 00981 // 00982 // This callback is a hack around the fact that we can't 00983 // let the ClockObject directly create a PStatCollector, 00984 // because the pstatclient module depends on putil. 00985 //////////////////////////////////////////////////////////////////// 00986 void PStatClient:: 00987 start_clock_busy_wait() { 00988 _clock_wait_pcollector.stop(); 00989 _clock_busy_wait_pcollector.start(); 00990 } 00991 00992 //////////////////////////////////////////////////////////////////// 00993 // Function: PStatClient::stop_clock_wait 00994 // Access: Private, Static 00995 // Description: This function is added as a hook into ClockObject, so 00996 // that we may time the delay for 00997 // ClockObject::wait_until(), used for certain special 00998 // clock modes. 00999 // 01000 // This callback is a hack around the fact that we can't 01001 // let the ClockObject directly create a PStatCollector, 01002 // because the pstatclient module depends on putil. 01003 //////////////////////////////////////////////////////////////////// 01004 void PStatClient:: 01005 stop_clock_wait() { 01006 _clock_busy_wait_pcollector.stop(); 01007 } 01008 01009 //////////////////////////////////////////////////////////////////// 01010 // Function: PStatClient::add_collector 01011 // Access: Private 01012 // Description: Adds a new Collector entry to the _collectors array, 01013 // in a thread-safe manner. Assumes _lock is already 01014 // held. 01015 //////////////////////////////////////////////////////////////////// 01016 void PStatClient:: 01017 add_collector(PStatClient::Collector *collector) { 01018 if (_num_collectors >= _collectors_size) { 01019 // We need to grow the array. We have to be careful here, because 01020 // there might be clients accessing the array right now who are 01021 // not protected by the lock. 01022 int new_collectors_size = (_collectors_size == 0) ? 128 : _collectors_size * 2; 01023 CollectorPointer *new_collectors = new CollectorPointer[new_collectors_size]; 01024 memcpy(new_collectors, _collectors, _num_collectors * sizeof(CollectorPointer)); 01025 AtomicAdjust::set_ptr(_collectors, new_collectors); 01026 AtomicAdjust::set(_collectors_size, new_collectors_size); 01027 01028 // Now, we still have the old array, which we allow to leak. We 01029 // should delete it, but there might be a thread out there that's 01030 // still trying to access it, so we can't safely delete it; and it 01031 // doesn't really matter much, since it's not a big leak. (We 01032 // will only reallocate the array so many times in an application, 01033 // and then no more.) 01034 01035 new_collectors[_num_collectors] = collector; 01036 AtomicAdjust::inc(_num_collectors); 01037 01038 } else { 01039 CollectorPointer *collectors = (CollectorPointer *)_collectors; 01040 collectors[_num_collectors] = collector; 01041 AtomicAdjust::inc(_num_collectors); 01042 } 01043 } 01044 01045 //////////////////////////////////////////////////////////////////// 01046 // Function: PStatClient::add_thread 01047 // Access: Private 01048 // Description: Adds a new InternalThread entry to the _threads 01049 // array, in a thread-safe manner. Assumes _lock is 01050 // already held. 01051 //////////////////////////////////////////////////////////////////// 01052 void PStatClient:: 01053 add_thread(PStatClient::InternalThread *thread) { 01054 if (_num_threads >= _threads_size) { 01055 // We need to grow the array. We have to be careful here, because 01056 // there might be clients accessing the array right now who are 01057 // not protected by the lock. 01058 int new_threads_size = (_threads_size == 0) ? 128 : _threads_size * 2; 01059 ThreadPointer *new_threads = new ThreadPointer[new_threads_size]; 01060 memcpy(new_threads, _threads, _num_threads * sizeof(ThreadPointer)); 01061 // We assume that assignment to a pointer and to an int are each 01062 // atomic. 01063 AtomicAdjust::set_ptr(_threads, new_threads); 01064 AtomicAdjust::set(_threads_size, new_threads_size); 01065 01066 // Now, we still have the old array, which we allow to leak. We 01067 // should delete it, but there might be a thread out there that's 01068 // still trying to access it, so we can't safely delete it; and it 01069 // doesn't really matter much, since it's not a big leak. (We 01070 // will only reallocate the array so many times in an application, 01071 // and then no more.) 01072 01073 new_threads[_num_threads] = thread; 01074 AtomicAdjust::inc(_num_threads); 01075 01076 } else { 01077 ThreadPointer *threads = (ThreadPointer *)_threads; 01078 threads[_num_threads] = thread; 01079 AtomicAdjust::inc(_num_threads); 01080 } 01081 } 01082 01083 //////////////////////////////////////////////////////////////////// 01084 // Function: PStatClient::deactivate_hook 01085 // Access: Public, Virtual 01086 // Description: Called when the thread is deactivated (swapped for 01087 // another running thread). This is intended to provide 01088 // a callback hook for PStats to assign time to 01089 // individual threads properly, particularly in the 01090 // SIMPLE_THREADS case. 01091 //////////////////////////////////////////////////////////////////// 01092 void PStatClient:: 01093 deactivate_hook(Thread *thread) { 01094 // We shouldn't use a mutex here, because this code is only called 01095 // during the SIMPLE_THREADS case, so a mutex isn't necessary; and 01096 // because we are called during a context switch, so a mutex might 01097 // be dangerous. 01098 if (_impl == NULL) { 01099 return; 01100 } 01101 int thread_index = thread->get_pstats_index(); 01102 InternalThread *ithread = get_thread_ptr(thread_index); 01103 01104 if (ithread->_thread_active) { 01105 // Start _thread_block_pcollector, by hand, being careful not to 01106 // grab any mutexes while we do it. 01107 double now = _impl->get_real_time(); 01108 ithread->_frame_data.add_start(_thread_block_pcollector.get_index(), now); 01109 ithread->_thread_active = false; 01110 } 01111 } 01112 01113 //////////////////////////////////////////////////////////////////// 01114 // Function: PStatClient::activate_hook 01115 // Access: Public, Virtual 01116 // Description: Called when the thread is activated (resumes 01117 // execution). This is intended to provide a callback 01118 // hook for PStats to assign time to individual threads 01119 // properly, particularly in the SIMPLE_THREADS case. 01120 //////////////////////////////////////////////////////////////////// 01121 void PStatClient:: 01122 activate_hook(Thread *thread) { 01123 // We shouldn't use a mutex here, because this code is only called 01124 // during the SIMPLE_THREADS case, so a mutex isn't necessary; and 01125 // because we are called during a context switch, so a mutex might 01126 // be dangerous. 01127 if (_impl == NULL) { 01128 return; 01129 } 01130 01131 InternalThread *ithread = get_thread_ptr(thread->get_pstats_index()); 01132 01133 if (!ithread->_thread_active) { 01134 double now = _impl->get_real_time(); 01135 ithread->_frame_data.add_stop(_thread_block_pcollector.get_index(), now); 01136 ithread->_thread_active = true; 01137 } 01138 } 01139 01140 //////////////////////////////////////////////////////////////////// 01141 // Function: PStatClient::Collector::make_def 01142 // Access: Private 01143 // Description: Creates the new PStatCollectorDef for this collector. 01144 //////////////////////////////////////////////////////////////////// 01145 void PStatClient::Collector:: 01146 make_def(const PStatClient *client, int this_index) { 01147 ReMutexHolder holder(client->_lock); 01148 if (_def == (PStatCollectorDef *)NULL) { 01149 _def = new PStatCollectorDef(this_index, _name); 01150 if (_parent_index != this_index) { 01151 const PStatCollectorDef *parent_def = 01152 client->get_collector_def(_parent_index); 01153 _def->set_parent(*parent_def); 01154 } 01155 initialize_collector_def(client, _def); 01156 } 01157 } 01158 01159 //////////////////////////////////////////////////////////////////// 01160 // Function: PStatClient::Collector::make_def 01161 // Access: Private 01162 // Description: Creates the new PStatCollectorDef for this collector. 01163 //////////////////////////////////////////////////////////////////// 01164 PStatClient::InternalThread:: 01165 InternalThread(Thread *thread) : 01166 _thread(thread), 01167 _name(thread->get_name()), 01168 _sync_name(thread->get_sync_name()), 01169 _is_active(false), 01170 _frame_number(0), 01171 _next_packet(0.0), 01172 _thread_active(true), 01173 _thread_lock(string("PStatClient::InternalThread ") + thread->get_name()) 01174 { 01175 } 01176 01177 #endif // DO_PSTATS