Panda3D
 All Classes Functions Variables Enumerations
pStatClient.cxx
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
 All Classes Functions Variables Enumerations