Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

panda/src/pstatclient/pStatClient.cxx

Go to the documentation of this file.
00001 // Filename: pStatClient.cxx
00002 // Created by:  drose (09Jul00)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
00008 //
00009 // All use of this software is subject to the terms of the Panda 3d
00010 // Software license.  You should have received a copy of this license
00011 // along with this source code; you will also find a current copy of
00012 // the license at http://www.panda3d.org/license.txt .
00013 //
00014 // To contact the maintainers of this program write to
00015 // panda3d@yahoogroups.com .
00016 //
00017 ////////////////////////////////////////////////////////////////////
00018 
00019 #include "pStatClient.h"
00020 
00021 #ifdef DO_PSTATS
00022 // This file only defines anything interesting if DO_PSTATS is
00023 // defined.
00024 
00025 #include "pStatClientControlMessage.h"
00026 #include "pStatServerControlMessage.h"
00027 #include "pStatCollector.h"
00028 #include "pStatThread.h"
00029 #include "config_pstats.h"
00030 #include "pStatProperties.h"
00031 
00032 #include <algorithm>
00033 
00034 #ifdef WIN32_VC
00035 #define WINDOWS_LEAN_AND_MEAN
00036 #include <windows.h>
00037 #undef WINDOWS_LEAN_AND_MEAN
00038 #endif
00039 
00040 PStatClient *PStatClient::_global_pstats = NULL;
00041 
00042 #ifndef CPPPARSER
00043 PStatCollector _total_size_pcollector("Memory usage");
00044 PStatCollector _cpp_size_pcollector("Memory usage:C++");
00045 PStatCollector _interpreter_size_pcollector("Memory usage:Interpreter");
00046 #endif
00047 
00048 ////////////////////////////////////////////////////////////////////
00049 //     Function: PStatClient::PerThreadData::Constructor
00050 //       Access: Public
00051 //  Description:
00052 ////////////////////////////////////////////////////////////////////
00053 PStatClient::PerThreadData::
00054 PerThreadData() {
00055   _has_level = false;
00056   _level = 0.0;
00057   _nested_count = 0;
00058 }
00059 
00060 ////////////////////////////////////////////////////////////////////
00061 //     Function: PStatClient::Constructor
00062 //       Access: Public
00063 //  Description:
00064 ////////////////////////////////////////////////////////////////////
00065 PStatClient::
00066 PStatClient() :
00067   _reader(this, 0),
00068   _writer(this, pstats_threaded_write ? 1 : 0)
00069 {
00070   _is_connected = false;
00071   _got_udp_port = false;
00072   _collectors_reported = 0;
00073   _threads_reported = 0;
00074 
00075   // We always have a collector at index 0 named "Frame".  This tracks
00076   // the total frame time and is the root of all other collectors.  We
00077   // have to make this one by hand since it's the root.
00078   Collector collector;
00079   collector._def = new PStatCollectorDef(0, "Frame");
00080   collector._def->_parent_index = 0;
00081   collector._def->_suggested_color.set(0.5, 0.5, 0.5);
00082   _collectors.push_back(collector);
00083 
00084   // We also always have a thread at index 0 named "Main".
00085   make_thread("Main");
00086 
00087   _client_name = get_pstats_name();
00088   _max_rate = get_pstats_max_rate();
00089 }
00090 
00091 ////////////////////////////////////////////////////////////////////
00092 //     Function: PStatClient::Destructor
00093 //       Access: Public
00094 //  Description:
00095 ////////////////////////////////////////////////////////////////////
00096 PStatClient::
00097 ~PStatClient() {
00098   disconnect();
00099 }
00100 
00101 ////////////////////////////////////////////////////////////////////
00102 //     Function: PStatClient::get_num_collectors
00103 //       Access: Public
00104 //  Description: Returns the total number of collectors the Client
00105 //               knows about.
00106 ////////////////////////////////////////////////////////////////////
00107 int PStatClient::
00108 get_num_collectors() const {
00109   return _collectors.size();
00110 }
00111 
00112 ////////////////////////////////////////////////////////////////////
00113 //     Function: PStatClient::get_collector
00114 //       Access: Public
00115 //  Description: Returns the nth collector.
00116 ////////////////////////////////////////////////////////////////////
00117 PStatCollector PStatClient::
00118 get_collector(int index) const {
00119   nassertr(index >= 0 && index < (int)_collectors.size(), PStatCollector());
00120   return PStatCollector((PStatClient *)this, index);
00121 }
00122 
00123 ////////////////////////////////////////////////////////////////////
00124 //     Function: PStatClient::get_collector_def
00125 //       Access: Public
00126 //  Description: Returns the definition body of the nth collector.
00127 ////////////////////////////////////////////////////////////////////
00128 const PStatCollectorDef &PStatClient::
00129 get_collector_def(int index) const {
00130 #ifndef NDEBUG
00131   static PStatCollectorDef bogus;
00132   nassertr(index >= 0 && index < (int)_collectors.size(), bogus);
00133 #endif
00134 
00135   return *_collectors[index]._def;
00136 }
00137 
00138 ////////////////////////////////////////////////////////////////////
00139 //     Function: PStatClient::get_collector_name
00140 //       Access: Public
00141 //  Description: Returns the name of the indicated collector.
00142 ////////////////////////////////////////////////////////////////////
00143 string PStatClient::
00144 get_collector_name(int index) const {
00145   nassertr(index >= 0 && index < (int)_collectors.size(), string());
00146 
00147   const PStatCollectorDef *def = _collectors[index]._def;
00148   return def->_name;
00149 }
00150 
00151 ////////////////////////////////////////////////////////////////////
00152 //     Function: PStatClient::get_collector_fullname
00153 //       Access: Public
00154 //  Description: Returns the "full name" of the indicated collector.
00155 //               This will be the concatenation of all of the
00156 //               collector's parents' names (except Frame) and the
00157 //               collector's own name.
00158 ////////////////////////////////////////////////////////////////////
00159 string PStatClient::
00160 get_collector_fullname(int index) const {
00161   nassertr(index >= 0 && index < (int)_collectors.size(), string());
00162 
00163   const PStatCollectorDef *def = _collectors[index]._def;
00164   if (def->_parent_index == 0) {
00165     return def->_name;
00166   } else {
00167     return get_collector_fullname(def->_parent_index) + ":" + def->_name;
00168   }
00169 }
00170 
00171 ////////////////////////////////////////////////////////////////////
00172 //     Function: PStatClient::get_num_threads
00173 //       Access: Public
00174 //  Description: Returns the total number of threads the Client
00175 //               knows about.
00176 ////////////////////////////////////////////////////////////////////
00177 int PStatClient::
00178 get_num_threads() const {
00179   return _threads.size();
00180 }
00181 
00182 ////////////////////////////////////////////////////////////////////
00183 //     Function: PStatClient::get_thread
00184 //       Access: Public
00185 //  Description: Returns the nth thread.
00186 ////////////////////////////////////////////////////////////////////
00187 PStatThread PStatClient::
00188 get_thread(int index) const {
00189   nassertr(index >= 0 && index < (int)_threads.size(), PStatThread());
00190   return PStatThread((PStatClient *)this, index);
00191 }
00192 
00193 ////////////////////////////////////////////////////////////////////
00194 //     Function: PStatClient::get_thread_name
00195 //       Access: Public
00196 //  Description: Returns the name of the indicated thread.
00197 ////////////////////////////////////////////////////////////////////
00198 string PStatClient::
00199 get_thread_name(int index) const {
00200   nassertr(index >= 0 && index < (int)_threads.size(), string());
00201   return _threads[index]._name;
00202 }
00203 
00204 ////////////////////////////////////////////////////////////////////
00205 //     Function: PStatClient::get_clock
00206 //       Access: Public
00207 //  Description: Returns a reference to the PStatClient's clock
00208 //               object.  It keeps its own clock, instead of using the
00209 //               global clock object, so the stats won't get mucked up
00210 //               if you put the global clock in non-real-time mode or
00211 //               something.
00212 //
00213 //               On second thought, it works better to use the global
00214 //               clock, so we don't lose a lot of time in the stats
00215 //               while we're waiting at the prompt.
00216 ////////////////////////////////////////////////////////////////////
00217 const ClockObject &PStatClient::
00218 get_clock() const {
00219   return _clock;
00220 }
00221 
00222 ////////////////////////////////////////////////////////////////////
00223 //     Function: PStatClient::get_main_thread
00224 //       Access: Public
00225 //  Description: Returns a handle to the client's "Main", or default,
00226 //               thread.  This is where collectors will be started and
00227 //               stopped if they don't specify otherwise.
00228 ////////////////////////////////////////////////////////////////////
00229 PStatThread PStatClient::
00230 get_main_thread() const {
00231   return PStatThread((PStatClient *)this, 0);
00232 }
00233 
00234 ////////////////////////////////////////////////////////////////////
00235 //     Function: PStatClient::make_collector_with_relname
00236 //       Access: Private
00237 //  Description: Returns a PStatCollector suitable for measuring
00238 //               categories with the indicated name.  This is normally
00239 //               called by a PStatCollector constructor.
00240 //
00241 //               The name may contain colons; if it does, it specifies
00242 //               a relative path to the client indicated by the parent
00243 //               index.
00244 ////////////////////////////////////////////////////////////////////
00245 PStatCollector PStatClient::
00246 make_collector_with_relname(int parent_index, string relname) {
00247   if (relname.empty()) {
00248     relname = "Unnamed";
00249   }
00250 
00251   // Skip any colons at the beginning of the name.
00252   size_t start = 0;
00253   while (start < relname.size() && relname[start] == ':') {
00254     start++;
00255   }
00256 
00257   // If the name contains a colon (after the initial colon), it means
00258   // we are making a nested collector.
00259   size_t colon = relname.find(':', start);
00260   while (colon != string::npos) {
00261     string parent_name = relname.substr(start, colon - start);
00262     PStatCollector parent_collector =
00263       make_collector_with_name(parent_index, parent_name);
00264     parent_index = parent_collector._index;
00265     relname = relname.substr(colon + 1);
00266     start = 0;
00267     colon = relname.find(':');
00268   }
00269 
00270   string name = relname.substr(start);
00271   return make_collector_with_name(parent_index, name);
00272 }
00273 
00274 ////////////////////////////////////////////////////////////////////
00275 //     Function: PStatClient::make_collector_with_name
00276 //       Access: Private
00277 //  Description: Returns a PStatCollector suitable for measuring
00278 //               categories with the indicated name.  This is normally
00279 //               called by a PStatCollector constructor.
00280 //
00281 //               The name should not contain colons.
00282 ////////////////////////////////////////////////////////////////////
00283 PStatCollector PStatClient::
00284 make_collector_with_name(int parent_index, const string &name) {
00285   nassertr(parent_index >= 0 && parent_index < (int)_collectors.size(),
00286            PStatCollector());
00287 
00288   Collector &parent = _collectors[parent_index];
00289 
00290   // A special case: if we asked for a child the same name as its
00291   // parent, we really meant the parent.  That is, "Frame:Frame" is
00292   // really the same collector as "Frame".
00293   if (parent._def->_name == name) {
00294     return PStatCollector(this, parent_index);
00295   }
00296 
00297   ThingsByName::const_iterator ni = parent._children.find(name);
00298 
00299   if (ni != parent._children.end()) {
00300     // We already had a collector by this name; return it.
00301     int index = (*ni).second;
00302     nassertr(index >= 0 && index < (int)_collectors.size(), PStatCollector());
00303     return PStatCollector(this, (*ni).second);
00304   }
00305 
00306   // Create a new collector for this name.
00307   int new_index = _collectors.size();
00308   parent._children.insert(ThingsByName::value_type(name, new_index));
00309 
00310   // Extending the vector invalidates the parent reference, above.
00311   _collectors.push_back(Collector());
00312   Collector &collector = _collectors.back();
00313   collector._def = new PStatCollectorDef(new_index, name);
00314 
00315   collector._def->set_parent(*_collectors[parent_index]._def);
00316   initialize_collector_def(this, collector._def);
00317 
00318   // We need one PerThreadData for each thread.
00319   while (collector._per_thread.size() < _threads.size()) {
00320     collector._per_thread.push_back(PerThreadData());
00321   }
00322 
00323   return PStatCollector(this, new_index);
00324 }
00325 
00326 ////////////////////////////////////////////////////////////////////
00327 //     Function: PStatClient::make_thread
00328 //       Access: Private
00329 //  Description: Returns a PStatThread with the indicated name
00330 //               suitable for grouping collectors.  This is normally
00331 //               called by a PStatThread constructor.
00332 ////////////////////////////////////////////////////////////////////
00333 PStatThread PStatClient::
00334 make_thread(const string &name) {
00335   ThingsByName::const_iterator ni =
00336     _threads_by_name.find(name);
00337 
00338   if (ni != _threads_by_name.end()) {
00339     // We already had a thread by this name; return it.
00340     int index = (*ni).second;
00341     nassertr(index >= 0 && index < (int)_threads.size(), PStatThread());
00342     return PStatThread(this, (*ni).second);
00343   }
00344 
00345   // Create a new thread for this name.
00346   int new_index = _threads.size();
00347   _threads_by_name.insert(ThingsByName::value_type(name, new_index));
00348 
00349   Thread thread;
00350   thread._name = name;
00351   thread._is_active = false;
00352   thread._next_packet = 0.0;
00353   thread._frame_number = 0;
00354 
00355   _threads.push_back(thread);
00356 
00357   // We need an additional PerThreadData for this thread in all of the
00358   // collectors.
00359   Collectors::iterator ci;
00360   for (ci = _collectors.begin(); ci != _collectors.end(); ++ci) {
00361     (*ci)._per_thread.push_back(PerThreadData());
00362     nassertr((*ci)._per_thread.size() == _threads.size(), PStatThread());
00363   }
00364 
00365   return PStatThread(this, new_index);
00366 }
00367 
00368 ////////////////////////////////////////////////////////////////////
00369 //     Function: PStatClient::main_tick
00370 //       Access: Public, Static
00371 //  Description: A convenience function to call new_frame() on the
00372 //               global PStatClient's main thread.
00373 ////////////////////////////////////////////////////////////////////
00374 void PStatClient::
00375 main_tick() {
00376   // We have code here to report the memory usage.  We can't put this
00377   // code inside the MemoryUsage class, where it fits a little better,
00378   // simply because MemoryUsage is a very low-level class that doesn't
00379   // know about PStatClient.
00380 
00381 #ifdef DO_MEMORY_USAGE
00382   if (MemoryUsage::has_total_size()) {
00383     _total_size_pcollector.set_level(MemoryUsage::get_total_size());
00384   }
00385   if (MemoryUsage::has_cpp_size()) {
00386     _cpp_size_pcollector.set_level(MemoryUsage::get_cpp_size());
00387   }
00388   if (MemoryUsage::has_interpreter_size()) {
00389     _interpreter_size_pcollector.set_level(MemoryUsage::get_interpreter_size());
00390   }
00391 #endif
00392 
00393   get_global_pstats()->client_main_tick();
00394 }  
00395 
00396 ////////////////////////////////////////////////////////////////////
00397 //     Function: PStatClient::main_tick
00398 //       Access: Public, Static
00399 //  Description: A convenience function to call new_frame() on the
00400 //               the given client's main thread.
00401 ////////////////////////////////////////////////////////////////////
00402 void PStatClient::
00403 client_main_tick() {
00404   _clock.tick();
00405   get_main_thread().new_frame();
00406 }
00407 
00408 ////////////////////////////////////////////////////////////////////
00409 //     Function: PStatClient::get_global_pstats
00410 //       Access: Public, Static
00411 //  Description: Returns a pointer to the global PStatClient object.
00412 //               It's legal to declare your own PStatClient locally,
00413 //               but it's also convenient to have a global one that
00414 //               everyone can register with.  This is the global one.
00415 ////////////////////////////////////////////////////////////////////
00416 PStatClient *PStatClient::
00417 get_global_pstats() {
00418   if (_global_pstats == (PStatClient *)NULL) {
00419     _global_pstats = new PStatClient;
00420   }
00421   return _global_pstats;
00422 }
00423 
00424 ////////////////////////////////////////////////////////////////////
00425 //     Function: PStatClient::client_connect
00426 //       Access: Private
00427 //  Description: The nonstatic implementation of connect().
00428 ////////////////////////////////////////////////////////////////////
00429 bool PStatClient::
00430 client_connect(string hostname, int port) {
00431   client_disconnect();
00432 
00433   if (hostname.empty()) {
00434     hostname = pstats_host;
00435   }
00436   if (port < 0) {
00437     port = pstats_port;
00438   }
00439 
00440   if (!_server.set_host(hostname, port)) {
00441     pstats_cat.error()
00442       << "Unknown host: " << hostname << "\n";
00443     return false;
00444   }
00445 
00446   _tcp_connection = open_TCP_client_connection(_server, 5000);
00447 
00448   if (_tcp_connection.is_null()) {
00449     pstats_cat.error()
00450       << "Couldn't connect to PStatServer at " << hostname << ":"
00451       << port << "\n";
00452     return false;
00453   }
00454   // Make sure we're not queuing up multiple TCP sockets--we expect
00455   // immediate writes of our TCP datagrams.
00456   _tcp_connection->set_collect_tcp(false);
00457 
00458   _reader.add_connection(_tcp_connection);
00459   _is_connected = true;
00460 
00461   _udp_connection = open_UDP_connection();
00462 
00463   send_hello();
00464 
00465   return _is_connected;
00466 }
00467 
00468 ////////////////////////////////////////////////////////////////////
00469 //     Function: PStatClient::client_disconnect
00470 //       Access: Private
00471 //  Description: The nonstatic implementation of disconnect().
00472 ////////////////////////////////////////////////////////////////////
00473 void PStatClient::
00474 client_disconnect() {
00475   if (_is_connected) {
00476     _reader.remove_connection(_tcp_connection);
00477     close_connection(_tcp_connection);
00478     close_connection(_udp_connection);
00479   }
00480 
00481   _tcp_connection.clear();
00482   _udp_connection.clear();
00483 
00484   _is_connected = false;
00485   _got_udp_port = false;
00486 
00487   _collectors_reported = 0;
00488   _threads_reported = 0;
00489 
00490   Threads::iterator ti;
00491   for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
00492     (*ti)._frame_number = 0;
00493     (*ti)._is_active = false;
00494     (*ti)._next_packet = 0.0;
00495     (*ti)._frame_data.clear();
00496   }
00497 
00498   Collectors::iterator ci;
00499   for (ci = _collectors.begin(); ci != _collectors.end(); ++ci) {
00500     PerThread::iterator ii;
00501     for (ii = (*ci)._per_thread.begin();
00502          ii != (*ci)._per_thread.end();
00503          ++ii) {
00504       (*ii)._nested_count = 0;
00505     }
00506   }
00507 }
00508 
00509 ////////////////////////////////////////////////////////////////////
00510 //     Function: PStatClient::client_is_connected
00511 //       Access: Public
00512 //  Description: The nonstatic implementation of is_connected().
00513 ////////////////////////////////////////////////////////////////////
00514 bool PStatClient::
00515 client_is_connected() const {
00516   return _is_connected;
00517 }
00518 
00519 ////////////////////////////////////////////////////////////////////
00520 //     Function: PStatClient::client_resume_after_pause
00521 //       Access: Published
00522 //  Description: Resumes the PStatClient after the simulation has been
00523 //               paused for a while.  This allows the stats to
00524 //               continue exactly where it left off, instead of
00525 //               leaving a big gap that would represent a chug.
00526 ////////////////////////////////////////////////////////////////////
00527 void PStatClient::
00528 client_resume_after_pause() {
00529   // Simply reset the clock to the beginning of the last frame.  This
00530   // may lose a frame, but on the other hand we won't skip a whole
00531   // slew of frames either.
00532 
00533   double frame_time = _clock.get_frame_time();
00534   _clock.set_real_time(frame_time);
00535 }
00536 
00537 ////////////////////////////////////////////////////////////////////
00538 //     Function: PStatClient::is_active
00539 //       Access: Private
00540 //  Description: Returns true if the indicated collector/thread
00541 //               combination is active, and we are transmitting stats
00542 //               data, or false otherwise.
00543 //
00544 //               Normally you would not use this interface directly;
00545 //               instead, call PStatCollector::is_active().
00546 ////////////////////////////////////////////////////////////////////
00547 bool PStatClient::
00548 is_active(int collector_index, int thread_index) const {
00549   nassertr(collector_index >= 0 && collector_index < (int)_collectors.size(), false);
00550   nassertr(thread_index >= 0 && thread_index < (int)_threads.size(), false);
00551 
00552   return (_is_connected &&
00553           _collectors[collector_index]._def->_is_active &&
00554           _threads[thread_index]._is_active);
00555 }
00556 
00557 ////////////////////////////////////////////////////////////////////
00558 //     Function: PStatClient::start
00559 //       Access: Private
00560 //  Description: Marks the indicated collector index as started.
00561 //               Normally you would not use this interface directly;
00562 //               instead, call PStatCollector::start().
00563 ////////////////////////////////////////////////////////////////////
00564 void PStatClient::
00565 start(int collector_index, int thread_index) {
00566 #ifdef _DEBUG
00567   nassertv(collector_index >= 0 && collector_index < (int)_collectors.size());
00568   nassertv(thread_index >= 0 && thread_index < (int)_threads.size());
00569 #endif
00570 
00571   if (_collectors[collector_index]._def->_is_active &&
00572       _threads[thread_index]._is_active) {
00573     if (_collectors[collector_index]._per_thread[thread_index]._nested_count == 0) {
00574       // This collector wasn't already started in this thread; record
00575       // a new data point.
00576       _threads[thread_index]._frame_data.add_start(collector_index, 
00577                                                    _clock.get_real_time());
00578     }
00579     _collectors[collector_index]._per_thread[thread_index]._nested_count++;
00580   }
00581 }
00582 
00583 ////////////////////////////////////////////////////////////////////
00584 //     Function: PStatClient::start
00585 //       Access: Private
00586 //  Description: Marks the indicated collector index as started.
00587 //               Normally you would not use this interface directly;
00588 //               instead, call PStatCollector::start().
00589 ////////////////////////////////////////////////////////////////////
00590 void PStatClient::
00591 start(int collector_index, int thread_index, float as_of) {
00592 #ifdef _DEBUG
00593   nassertv(collector_index >= 0 && collector_index < (int)_collectors.size());
00594   nassertv(thread_index >= 0 && thread_index < (int)_threads.size());
00595 #endif
00596 
00597   if (_collectors[collector_index]._def->_is_active &&
00598       _threads[thread_index]._is_active) {
00599     if (_collectors[collector_index]._per_thread[thread_index]._nested_count == 0) {
00600       // This collector wasn't already started in this thread; record
00601       // a new data point.
00602       _threads[thread_index]._frame_data.add_start(collector_index, as_of);
00603     }
00604     _collectors[collector_index]._per_thread[thread_index]._nested_count++;
00605   }
00606 }
00607 
00608 ////////////////////////////////////////////////////////////////////
00609 //     Function: PStatClient::stop
00610 //       Access: Private
00611 //  Description: Marks the indicated collector index as stopped.
00612 //               Normally you would not use this interface directly;
00613 //               instead, call PStatCollector::stop().
00614 ////////////////////////////////////////////////////////////////////
00615 void PStatClient::
00616 stop(int collector_index, int thread_index) {
00617 #ifdef _DEBUG
00618   nassertv(collector_index >= 0 && collector_index < (int)_collectors.size());
00619   nassertv(thread_index >= 0 && thread_index < (int)_threads.size());
00620 #endif
00621 
00622   if (_collectors[collector_index]._def->_is_active &&
00623       _threads[thread_index]._is_active) {
00624     if (_collectors[collector_index]._per_thread[thread_index]._nested_count == 0) {
00625       pstats_cat.warning()
00626         << "Collector " << get_collector_fullname(collector_index)
00627         << " was already stopped in thread " << get_thread_name(thread_index)
00628         << "!\n";
00629       return;
00630     }
00631 
00632     _collectors[collector_index]._per_thread[thread_index]._nested_count--;
00633 
00634     if (_collectors[collector_index]._per_thread[thread_index]._nested_count == 0) {
00635       // This collector has now been completely stopped; record a new
00636       // data point.
00637       _threads[thread_index]._frame_data.add_stop(collector_index,
00638                                                   _clock.get_real_time());
00639     }
00640   }
00641 }
00642 
00643 ////////////////////////////////////////////////////////////////////
00644 //     Function: PStatClient::stop
00645 //       Access: Private
00646 //  Description: Marks the indicated collector index as stopped.
00647 //               Normally you would not use this interface directly;
00648 //               instead, call PStatCollector::stop().
00649 ////////////////////////////////////////////////////////////////////
00650 void PStatClient::
00651 stop(int collector_index, int thread_index, float as_of) {
00652 #ifdef _DEBUG
00653   nassertv(collector_index >= 0 && collector_index < (int)_collectors.size());
00654   nassertv(thread_index >= 0 && thread_index < (int)_threads.size());
00655 #endif
00656 
00657   if (_collectors[collector_index]._def->_is_active &&
00658       _threads[thread_index]._is_active) {
00659     if (_collectors[collector_index]._per_thread[thread_index]._nested_count == 0) {
00660       pstats_cat.warning()
00661         << "Collector " << get_collector_fullname(collector_index)
00662         << " was already stopped in thread " << get_thread_name(thread_index)
00663         << "!\n";
00664       return;
00665     }
00666 
00667     _collectors[collector_index]._per_thread[thread_index]._nested_count--;
00668 
00669     if (_collectors[collector_index]._per_thread[thread_index]._nested_count == 0) {
00670       // This collector has now been completely stopped; record a new
00671       // data point.
00672       _threads[thread_index]._frame_data.add_stop(collector_index, as_of);
00673     }
00674   }
00675 }
00676 
00677 ////////////////////////////////////////////////////////////////////
00678 //     Function: PStatClient::clear_level
00679 //       Access: Private
00680 //  Description: Removes the level value from the indicated collector.
00681 //               The collector will no longer be reported as having
00682 //               any particular level value.
00683 //
00684 //               Normally you would not use this interface directly;
00685 //               instead, call PStatCollector::clear_level().
00686 ////////////////////////////////////////////////////////////////////
00687 void PStatClient::
00688 clear_level(int collector_index, int thread_index) {
00689   if (_collectors[collector_index]._def->_is_active) {
00690     _collectors[collector_index]._per_thread[thread_index]._has_level = false;
00691     _collectors[collector_index]._per_thread[thread_index]._level = 0.0;
00692   }
00693 }
00694 
00695 ////////////////////////////////////////////////////////////////////
00696 //     Function: PStatClient::set_level
00697 //       Access: Private
00698 //  Description: Sets the level value for the indicated collector to
00699 //               the given amount.
00700 //
00701 //               Normally you would not use this interface directly;
00702 //               instead, call PStatCollector::set_level().
00703 ////////////////////////////////////////////////////////////////////
00704 void PStatClient::
00705 set_level(int collector_index, int thread_index, float level) {
00706   if (_collectors[collector_index]._def->_is_active) {
00707     level *= _collectors[collector_index]._def->_factor;
00708     _collectors[collector_index]._per_thread[thread_index]._has_level = true;
00709     _collectors[collector_index]._per_thread[thread_index]._level = level;
00710   }
00711 }
00712 
00713 ////////////////////////////////////////////////////////////////////
00714 //     Function: PStatClient::add_level
00715 //       Access: Private
00716 //  Description: Adds the given value (which may be negative) to the
00717 //               current value for the given collector.  If the
00718 //               collector does not already have a level value, it is
00719 //               initialized to 0.
00720 //
00721 //               Normally you would not use this interface directly;
00722 //               instead, call PStatCollector::add_level().
00723 ////////////////////////////////////////////////////////////////////
00724 void PStatClient::
00725 add_level(int collector_index, int thread_index, float increment) {
00726   if (_collectors[collector_index]._def->_is_active) {
00727     increment *= _collectors[collector_index]._def->_factor;
00728     _collectors[collector_index]._per_thread[thread_index]._has_level = true;
00729     _collectors[collector_index]._per_thread[thread_index]._level += increment;
00730   }
00731 }
00732 
00733 ////////////////////////////////////////////////////////////////////
00734 //     Function: PStatClient::get_level
00735 //       Access: Private
00736 //  Description: Returns the current level value of the given collector.
00737 //
00738 //               Normally you would not use this interface directly;
00739 //               instead, call PStatCollector::get_level().
00740 ////////////////////////////////////////////////////////////////////
00741 float PStatClient::
00742 get_level(int collector_index, int thread_index) const {
00743   return _collectors[collector_index]._per_thread[thread_index]._level /
00744     _collectors[collector_index]._def->_factor;
00745 }
00746 
00747 ////////////////////////////////////////////////////////////////////
00748 //     Function: PStatClient::new_frame
00749 //       Access: Private
00750 //  Description: Called by the PStatThread interface at the beginning
00751 //               of every frame, for each thread.  This resets the
00752 //               clocks for the new frame and transmits the data for
00753 //               the previous frame.
00754 ////////////////////////////////////////////////////////////////////
00755 void PStatClient::
00756 new_frame(int thread_index) {
00757   nassertv(thread_index >= 0 && thread_index < (int)_threads.size());
00758 
00759   Thread &thread = _threads[thread_index];
00760 
00761   // If we're the main thread, we should exchange control packets with
00762   // the server.
00763   if (thread_index == 0) {
00764     transmit_control_data();
00765   }
00766 
00767   // If we've got the UDP port by the time the frame starts, it's
00768   // time to become active and start actually tracking data.
00769   if (_got_udp_port) {
00770     thread._is_active = true;
00771   }
00772 
00773   if (!thread._is_active) {
00774     return;
00775   }
00776 
00777   float frame_start = _clock.get_real_time();
00778 
00779   if (!thread._frame_data.is_empty()) {
00780     // Collector 0 is the whole frame.
00781     stop(0, thread_index, frame_start);
00782 
00783     // Fill up the level data for all the collectors who have level
00784     // data for this thread.
00785     int num_collectors = _collectors.size();
00786     for (int i = 0; i < num_collectors; i++) {
00787       const PerThreadData &ptd = _collectors[i]._per_thread[thread_index];
00788       if (ptd._has_level) {
00789         thread._frame_data.add_level(i, ptd._level);
00790       }
00791     }
00792     transmit_frame_data(thread_index);
00793   }
00794 
00795   thread._frame_data.clear();
00796   thread._frame_number++;
00797   start(0, thread_index, frame_start);
00798 }
00799 
00800 ////////////////////////////////////////////////////////////////////
00801 //     Function: PStatClient::transmit_frame_data
00802 //       Access: Private
00803 //  Description: Should be called once per frame per thread to
00804 //               transmit the latest data to the PStatServer.
00805 ////////////////////////////////////////////////////////////////////
00806 void PStatClient::
00807 transmit_frame_data(int thread_index) {
00808   nassertv(thread_index >= 0 && thread_index < (int)_threads.size());
00809   if (_is_connected && _threads[thread_index]._is_active) {
00810 
00811     // We don't want to send too many packets in a hurry and flood the
00812     // server.  Check that enough time has elapsed for us to send a
00813     // new packet.  If not, we'll drop this packet on the floor and
00814     // send a new one next time around.
00815     float now = _clock.get_real_time();
00816     if (now >= _threads[thread_index]._next_packet) {
00817       // We don't want to send more than _max_rate UDP-size packets
00818       // per second, per thread.
00819       float packet_delay = 1.0 / _max_rate;
00820 
00821       // Send new data.
00822       NetDatagram datagram;
00823       // We always start with a zero byte, to differentiate it from a
00824       // control message.
00825       datagram.add_uint8(0);
00826 
00827       datagram.add_uint16(thread_index);
00828       datagram.add_uint32(_threads[thread_index]._frame_number);
00829       _threads[thread_index]._frame_data.write_datagram(datagram);
00830 
00831       if (_writer.is_valid_for_udp(datagram)) {
00832         nassertv(_got_udp_port);
00833         _writer.send(datagram, _udp_connection, _server);
00834 
00835       } else {
00836         _writer.send(datagram, _tcp_connection);
00837         // If our packets are so large that we must ship them via TCP,
00838         // then artificially slow down the packet rate even further.
00839         int packet_ratio =
00840           (datagram.get_length() + maximum_udp_datagram - 1) /
00841           maximum_udp_datagram;
00842         packet_delay *= (float)packet_ratio;
00843       }
00844 
00845       _threads[thread_index]._next_packet = now + packet_delay;
00846     }
00847   }
00848 }
00849 
00850 ////////////////////////////////////////////////////////////////////
00851 //     Function: PStatClient::transmit_control_data
00852 //       Access: Private
00853 //  Description: Should be called once a frame to exchange control
00854 //               information with the server.
00855 ////////////////////////////////////////////////////////////////////
00856 void PStatClient::
00857 transmit_control_data() {
00858   // Check for new messages from the server.
00859   while (_is_connected && _reader.data_available()) {
00860     NetDatagram datagram;
00861 
00862     if (_reader.get_data(datagram)) {
00863       PStatServerControlMessage message;
00864       if (message.decode(datagram)) {
00865         handle_server_control_message(message);
00866 
00867       } else {
00868         pstats_cat.error()
00869           << "Got unexpected message from server.\n";
00870       }
00871     }
00872   }
00873 
00874   if (_is_connected) {
00875     report_new_collectors();
00876     report_new_threads();
00877   }
00878 }
00879 
00880 
00881 ////////////////////////////////////////////////////////////////////
00882 //     Function: PStatClient::get_hostname
00883 //       Access: Private
00884 //  Description: Returns the current machine's hostname.
00885 ////////////////////////////////////////////////////////////////////
00886 string PStatClient::
00887 get_hostname() {
00888   if (_hostname.empty()) {
00889     char temp_buff[1024];
00890     if (gethostname(temp_buff, 1024) == 0) {
00891       _hostname = temp_buff;
00892     } else {
00893       _hostname = "unknown";
00894     }
00895   }
00896   return _hostname;
00897 }
00898 
00899 ////////////////////////////////////////////////////////////////////
00900 //     Function: PStatClient::send_hello
00901 //       Access: Private
00902 //  Description: Sends the initial greeting message to the server.
00903 ////////////////////////////////////////////////////////////////////
00904 void PStatClient::
00905 send_hello() {
00906   nassertv(_is_connected);
00907 
00908   PStatClientControlMessage message;
00909   message._type = PStatClientControlMessage::T_hello;
00910   message._client_hostname = get_hostname();
00911   message._client_progname = _client_name;
00912   message._major_version = get_current_pstat_major_version();
00913   message._minor_version = get_current_pstat_minor_version();
00914 
00915   Datagram datagram;
00916   message.encode(datagram);
00917   _writer.send(datagram, _tcp_connection);
00918 }
00919 
00920 ////////////////////////////////////////////////////////////////////
00921 //     Function: PStatClient::report_new_collectors
00922 //       Access: Private
00923 //  Description: Sends over any information about new Collectors that
00924 //               the user code might have recently created.
00925 ////////////////////////////////////////////////////////////////////
00926 void PStatClient::
00927 report_new_collectors() {
00928   nassertv(_is_connected);
00929 
00930   if (_collectors_reported < (int)_collectors.size()) {
00931     PStatClientControlMessage message;
00932     message._type = PStatClientControlMessage::T_define_collectors;
00933     while (_collectors_reported < (int)_collectors.size()) {
00934       message._collectors.push_back(_collectors[_collectors_reported]._def);
00935       _collectors_reported++;
00936     }
00937 
00938     Datagram datagram;
00939     message.encode(datagram);
00940     _writer.send(datagram, _tcp_connection);
00941   }
00942 }
00943 
00944 ////////////////////////////////////////////////////////////////////
00945 //     Function: PStatClient::report_new_threads
00946 //       Access: Private
00947 //  Description: Sends over any information about new Threads that
00948 //               the user code might have recently created.
00949 ////////////////////////////////////////////////////////////////////
00950 void PStatClient::
00951 report_new_threads() {
00952   nassertv(_is_connected);
00953 
00954   if (_threads_reported < (int)_threads.size()) {
00955     PStatClientControlMessage message;
00956     message._type = PStatClientControlMessage::T_define_threads;
00957     message._first_thread_index = _threads_reported;
00958     while (_threads_reported < (int)_threads.size()) {
00959       message._names.push_back(_threads[_threads_reported]._name);
00960       _threads_reported++;
00961     }
00962 
00963     Datagram datagram;
00964     message.encode(datagram);
00965     _writer.send(datagram, _tcp_connection);
00966   }
00967 }
00968 
00969 ////////////////////////////////////////////////////////////////////
00970 //     Function: PStatClient::handle_server_control_message
00971 //       Access: Private
00972 //  Description: Called when a control message has been received by
00973 //               the server over the TCP connection.
00974 ////////////////////////////////////////////////////////////////////
00975 void PStatClient::
00976 handle_server_control_message(const PStatServerControlMessage &message) {
00977   switch (message._type) {
00978   case PStatServerControlMessage::T_hello:
00979     pstats_cat.info()
00980       << "Connected to " << message._server_progname << " on "
00981       << message._server_hostname << "\n";
00982 
00983     _server.set_port(message._udp_port);
00984     _got_udp_port = true;
00985     break;
00986 
00987   default:
00988     pstats_cat.error()
00989       << "Invalid control message received from server.\n";
00990   }
00991 }
00992 
00993 ////////////////////////////////////////////////////////////////////
00994 //     Function: PStatClient::connection_reset
00995 //       Access: Private, Virtual
00996 //  Description: Called by the internal net code when the connection
00997 //               has been lost.
00998 ////////////////////////////////////////////////////////////////////
00999 void PStatClient::
01000 connection_reset(const PT(Connection) &connection) {
01001   if (connection == _tcp_connection) {
01002     disconnect();
01003   } else {
01004     pstats_cat.warning()
01005       << "Ignoring spurious connection_reset() message\n";
01006   }
01007 }
01008 
01009 #endif // DO_PSTATS

Generated on Fri May 2 00:43:27 2003 for Panda by doxygen1.3