00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "pStatClient.h"
00020
00021 #ifdef DO_PSTATS
00022
00023
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
00050
00051
00052
00053 PStatClient::PerThreadData::
00054 PerThreadData() {
00055 _has_level = false;
00056 _level = 0.0;
00057 _nested_count = 0;
00058 }
00059
00060
00061
00062
00063
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
00076
00077
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
00085 make_thread("Main");
00086
00087 _client_name = get_pstats_name();
00088 _max_rate = get_pstats_max_rate();
00089 }
00090
00091
00092
00093
00094
00095
00096 PStatClient::
00097 ~PStatClient() {
00098 disconnect();
00099 }
00100
00101
00102
00103
00104
00105
00106
00107 int PStatClient::
00108 get_num_collectors() const {
00109 return _collectors.size();
00110 }
00111
00112
00113
00114
00115
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
00125
00126
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
00140
00141
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
00153
00154
00155
00156
00157
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
00173
00174
00175
00176
00177 int PStatClient::
00178 get_num_threads() const {
00179 return _threads.size();
00180 }
00181
00182
00183
00184
00185
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
00195
00196
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
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217 const ClockObject &PStatClient::
00218 get_clock() const {
00219 return _clock;
00220 }
00221
00222
00223
00224
00225
00226
00227
00228
00229 PStatThread PStatClient::
00230 get_main_thread() const {
00231 return PStatThread((PStatClient *)this, 0);
00232 }
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245 PStatCollector PStatClient::
00246 make_collector_with_relname(int parent_index, string relname) {
00247 if (relname.empty()) {
00248 relname = "Unnamed";
00249 }
00250
00251
00252 size_t start = 0;
00253 while (start < relname.size() && relname[start] == ':') {
00254 start++;
00255 }
00256
00257
00258
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
00276
00277
00278
00279
00280
00281
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
00291
00292
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
00301 int index = (*ni).second;
00302 nassertr(index >= 0 && index < (int)_collectors.size(), PStatCollector());
00303 return PStatCollector(this, (*ni).second);
00304 }
00305
00306
00307 int new_index = _collectors.size();
00308 parent._children.insert(ThingsByName::value_type(name, new_index));
00309
00310
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
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
00328
00329
00330
00331
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
00340 int index = (*ni).second;
00341 nassertr(index >= 0 && index < (int)_threads.size(), PStatThread());
00342 return PStatThread(this, (*ni).second);
00343 }
00344
00345
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
00358
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
00370
00371
00372
00373
00374 void PStatClient::
00375 main_tick() {
00376
00377
00378
00379
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
00398
00399
00400
00401
00402 void PStatClient::
00403 client_main_tick() {
00404 _clock.tick();
00405 get_main_thread().new_frame();
00406 }
00407
00408
00409
00410
00411
00412
00413
00414
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
00426
00427
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
00455
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
00470
00471
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
00511
00512
00513
00514 bool PStatClient::
00515 client_is_connected() const {
00516 return _is_connected;
00517 }
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527 void PStatClient::
00528 client_resume_after_pause() {
00529
00530
00531
00532
00533 double frame_time = _clock.get_frame_time();
00534 _clock.set_real_time(frame_time);
00535 }
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
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
00559
00560
00561
00562
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
00575
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
00585
00586
00587
00588
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
00601
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
00610
00611
00612
00613
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
00636
00637 _threads[thread_index]._frame_data.add_stop(collector_index,
00638 _clock.get_real_time());
00639 }
00640 }
00641 }
00642
00643
00644
00645
00646
00647
00648
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
00671
00672 _threads[thread_index]._frame_data.add_stop(collector_index, as_of);
00673 }
00674 }
00675 }
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
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
00697
00698
00699
00700
00701
00702
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
00715
00716
00717
00718
00719
00720
00721
00722
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
00735
00736
00737
00738
00739
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
00749
00750
00751
00752
00753
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
00762
00763 if (thread_index == 0) {
00764 transmit_control_data();
00765 }
00766
00767
00768
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
00781 stop(0, thread_index, frame_start);
00782
00783
00784
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
00802
00803
00804
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
00812
00813
00814
00815 float now = _clock.get_real_time();
00816 if (now >= _threads[thread_index]._next_packet) {
00817
00818
00819 float packet_delay = 1.0 / _max_rate;
00820
00821
00822 NetDatagram datagram;
00823
00824
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
00838
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
00852
00853
00854
00855
00856 void PStatClient::
00857 transmit_control_data() {
00858
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
00883
00884
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
00901
00902
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
00922
00923
00924
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
00946
00947
00948
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
00971
00972
00973
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
00995
00996
00997
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