15 #include "pStatClient.h" 21 #include "pStatClientImpl.h" 22 #include "pStatClientControlMessage.h" 23 #include "pStatServerControlMessage.h" 24 #include "pStatCollector.h" 25 #include "pStatThread.h" 26 #include "config_pstats.h" 27 #include "pStatProperties.h" 29 #include "clockObject.h" 30 #include "neverFreeMemory.h" 32 PStatCollector PStatClient::_heap_total_size_pcollector(
"System memory:Heap");
33 PStatCollector PStatClient::_heap_overhead_size_pcollector(
"System memory:Heap:Overhead");
34 PStatCollector PStatClient::_heap_single_size_pcollector(
"System memory:Heap:Single");
35 PStatCollector PStatClient::_heap_single_other_size_pcollector(
"System memory:Heap:Single:Other");
36 PStatCollector PStatClient::_heap_array_size_pcollector(
"System memory:Heap:Array");
37 PStatCollector PStatClient::_heap_array_other_size_pcollector(
"System memory:Heap:Array:Other");
38 PStatCollector PStatClient::_heap_external_size_pcollector(
"System memory:Heap:External");
39 PStatCollector PStatClient::_mmap_size_pcollector(
"System memory:MMap");
41 PStatCollector PStatClient::_mmap_nf_unused_size_pcollector(
"System memory:MMap:NeverFree:Unused");
42 PStatCollector PStatClient::_mmap_dc_active_other_size_pcollector(
"System memory:MMap:NeverFree:Active:Other");
43 PStatCollector PStatClient::_mmap_dc_inactive_other_size_pcollector(
"System memory:MMap:NeverFree:Inactive:Other");
45 PStatCollector PStatClient::_clock_wait_pcollector(
"Wait:Clock Wait:Sleep");
46 PStatCollector PStatClient::_clock_busy_wait_pcollector(
"Wait:Clock Wait:Spin");
47 PStatCollector PStatClient::_thread_block_pcollector(
"Wait:Thread block");
54 class TypeHandleCollector {
59 static TypeHandleCols type_handle_cols;
67 PStatClient::PerThreadData::
81 _lock(
"PStatClient::_lock"),
95 Collector *collector =
new Collector(0,
"Frame");
99 add_collector(collector);
121 get_collector(
int index)
const {
132 get_collector_name(
int index)
const {
135 return get_collector_ptr(index)->get_name();
147 get_collector_fullname(
int index)
const {
150 Collector *collector = get_collector_ptr(index);
151 int parent_index = collector->get_parent_index();
152 if (parent_index == 0) {
153 return collector->get_name();
155 return get_collector_fullname(parent_index) +
":" +
156 collector->get_name();
166 get_thread(
int index)
const {
168 nassertr(index >= 0 && index < _num_threads,
PStatThread());
179 get_main_thread()
const {
191 get_current_thread()
const {
192 if (!client_is_connected()) {
195 return get_main_thread();
214 #ifdef DO_MEMORY_USAGE 215 if (is_connected()) {
216 _heap_total_size_pcollector.set_level(MemoryUsage::get_total_size());
217 _heap_overhead_size_pcollector.set_level(MemoryUsage::get_panda_heap_overhead());
218 _heap_single_size_pcollector.set_level(MemoryUsage::get_panda_heap_single_size());
219 _heap_array_size_pcollector.set_level(MemoryUsage::get_panda_heap_array_size());
220 _heap_external_size_pcollector.set_level(MemoryUsage::get_external_size());
223 _mmap_size_pcollector.set_level(MemoryUsage::get_panda_mmap_size());
228 while ((
int)type_handle_cols.size() < num_typehandles) {
229 type_handle_cols.push_back(TypeHandleCollector());
232 size_t single_total_usage = 0;
233 size_t array_total_usage = 0;
234 size_t dc_active_total_usage = 0;
235 size_t dc_inactive_total_usage = 0;
237 for (i = 0; i < num_typehandles; ++i) {
239 for (
int mi = 0; mi < (int)TypeHandle::MC_limit; ++mi) {
240 TypeHandle::MemoryClass mc = (TypeHandle::MemoryClass)mi;
241 size_t usage = type.get_memory_usage(mc);
244 case TypeHandle::MC_singleton:
245 single_total_usage += usage;
248 case TypeHandle::MC_array:
249 array_total_usage += usage;
252 case TypeHandle::MC_deleted_chain_active:
253 dc_active_total_usage += usage;
256 case TypeHandle::MC_deleted_chain_inactive:
257 dc_inactive_total_usage += usage;
260 case TypeHandle::MC_limit:
266 size_t min_usage = (single_total_usage + array_total_usage + dc_active_total_usage + dc_inactive_total_usage) / 1024;
267 if (!pstats_mem_other) {
270 size_t single_other_usage = single_total_usage;
271 size_t array_other_usage = array_total_usage;
272 size_t dc_active_other_usage = dc_active_total_usage;
273 size_t dc_inactive_other_usage = dc_inactive_total_usage;
275 for (i = 0; i < num_typehandles; ++i) {
277 for (
int mi = 0; mi < (int)TypeHandle::MC_limit; ++mi) {
278 TypeHandle::MemoryClass mc = (TypeHandle::MemoryClass)mi;
280 size_t usage = type.get_memory_usage(mc);
281 if (usage > min_usage || col.is_valid()) {
284 if (!col.is_valid()) {
285 const char *category =
"";
287 case TypeHandle::MC_singleton:
288 category =
"Heap:Single";
291 case TypeHandle::MC_array:
292 category =
"Heap:Array";
295 case TypeHandle::MC_deleted_chain_active:
296 category =
"MMap:NeverFree:Active";
299 case TypeHandle::MC_deleted_chain_inactive:
300 category =
"MMap:NeverFree:Inactive";
303 case TypeHandle::MC_limit:
308 strm <<
"System memory:" << category <<
":" << type;
311 col.set_level(usage);
314 case TypeHandle::MC_singleton:
315 single_other_usage -= usage;
318 case TypeHandle::MC_array:
319 array_other_usage -= usage;
322 case TypeHandle::MC_deleted_chain_active:
323 dc_active_other_usage -= usage;
326 case TypeHandle::MC_deleted_chain_inactive:
327 dc_inactive_other_usage -= usage;
330 case TypeHandle::MC_limit:
342 _heap_single_other_size_pcollector.set_level(single_other_usage);
343 _heap_array_other_size_pcollector.set_level(array_other_usage);
344 _mmap_dc_active_other_size_pcollector.set_level(dc_active_other_usage);
345 _mmap_dc_inactive_other_size_pcollector.set_level(dc_inactive_other_usage);
347 #endif // DO_MEMORY_USAGE 349 get_global_pstats()->client_main_tick();
359 thread_tick(
const string &sync_name) {
360 get_global_pstats()->client_thread_tick(sync_name);
374 if (!_impl->client_is_connected()) {
379 _impl->client_main_tick();
381 MultiThingsByName::const_iterator ni =
382 _threads_by_sync_name.find(
"Main");
383 if (ni != _threads_by_sync_name.end()) {
384 const vector_int &indices = (*ni).second;
385 for (vector_int::const_iterator vi = indices.begin();
388 _impl->new_frame(*vi);
401 client_thread_tick(
const string &sync_name) {
405 MultiThingsByName::const_iterator ni =
406 _threads_by_sync_name.find(sync_name);
407 if (ni != _threads_by_sync_name.end()) {
408 const vector_int &indices = (*ni).second;
409 for (vector_int::const_iterator vi = indices.begin();
412 _impl->new_frame(*vi);
424 client_disconnect() {
427 _impl->client_disconnect();
432 ThreadPointer *threads = (ThreadPointer *)_threads;
433 for (
int ti = 0; ti < _num_threads; ++ti) {
434 InternalThread *thread = threads[ti];
435 thread->_frame_number = 0;
436 thread->_is_active =
false;
437 thread->_next_packet = 0.0;
438 thread->_frame_data.clear();
441 CollectorPointer *collectors = (CollectorPointer *)_collectors;
442 for (
int ci = 0; ci < _num_collectors; ++ci) {
443 Collector *collector = collectors[ci];
444 PerThread::iterator ii;
445 for (ii = collector->_per_thread.begin();
446 ii != collector->_per_thread.end();
448 (*ii)._nested_count = 0;
462 get_global_pstats() {
466 ClockObject::_start_clock_wait = start_clock_wait;
467 ClockObject::_start_clock_busy_wait = start_clock_busy_wait;
468 ClockObject::_stop_clock_wait = stop_clock_wait;
470 return _global_pstats;
485 make_collector_with_relname(
int parent_index,
string relname) {
488 if (relname.empty()) {
494 while (start < relname.size() && relname[start] ==
':') {
500 size_t colon = relname.find(
':', start);
501 while (colon != string::npos) {
502 string parent_name = relname.substr(start, colon - start);
504 make_collector_with_name(parent_index, parent_name);
505 parent_index = parent_collector._index;
506 relname = relname.substr(colon + 1);
508 colon = relname.find(
':');
511 string name = relname.substr(start);
512 return make_collector_with_name(parent_index, name);
525 make_collector_with_name(
int parent_index,
const string &name) {
528 nassertr(parent_index >= 0 && parent_index < _num_collectors,
531 Collector *parent = get_collector_ptr(parent_index);
536 if (parent->get_name() == name) {
540 ThingsByName::const_iterator ni = parent->_children.find(name);
542 if (ni != parent->_children.end()) {
544 int index = (*ni).second;
545 nassertr(index >= 0 && index < _num_collectors,
PStatCollector());
550 int new_index = _num_collectors;
551 parent->_children.insert(ThingsByName::value_type(name, new_index));
553 Collector *collector =
new Collector(parent_index, name);
559 while ((
int)collector->_per_thread.size() < _num_threads) {
560 collector->_per_thread.push_back(PerThreadData());
562 add_collector(collector);
574 do_get_current_thread()
const {
577 if (thread_index != -1) {
583 return ((
PStatClient *)
this)->do_make_thread(thread);
594 make_thread(
Thread *thread) {
596 return do_make_thread(thread);
605 do_make_thread(
Thread *thread) {
607 if (thread_index != -1) {
611 MultiThingsByName::const_iterator ni =
612 _threads_by_name.find(thread->get_name());
614 if (ni != _threads_by_name.end()) {
617 const vector_int &indices = (*ni).second;
618 for (vector_int::const_iterator vi = indices.begin();
622 nassertr(index >= 0 && index < _num_threads,
PStatThread());
623 ThreadPointer *threads = (ThreadPointer *)_threads;
624 if (threads[index]->_thread.was_deleted() &&
627 threads[index]->_thread = thread;
636 int new_index = _num_threads;
640 InternalThread *pthread =
new InternalThread(thread);
653 make_gpu_thread(
const string &name) {
655 int new_index = _num_threads;
657 InternalThread *pthread =
new InternalThread(name,
"GPU");
674 is_active(
int collector_index,
int thread_index)
const {
675 nassertr(collector_index >= 0 && collector_index <
AtomicAdjust::get(_num_collectors),
false);
676 nassertr(thread_index >= 0 && thread_index <
AtomicAdjust::get(_num_threads),
false);
678 return (client_is_connected() &&
679 get_collector_ptr(collector_index)->is_active() &&
680 get_thread_ptr(thread_index)->_is_active);
693 is_started(
int collector_index,
int thread_index)
const {
694 nassertr(collector_index >= 0 && collector_index <
AtomicAdjust::get(_num_collectors),
false);
695 nassertr(thread_index >= 0 && thread_index <
AtomicAdjust::get(_num_threads),
false);
697 Collector *collector = get_collector_ptr(collector_index);
698 InternalThread *thread = get_thread_ptr(thread_index);
700 if (client_is_connected() && collector->is_active() && thread->_is_active) {
702 if (collector->_per_thread[thread_index]._nested_count == 0) {
722 start(
int collector_index,
int thread_index) {
723 if (!client_is_connected()) {
728 nassertv(collector_index >= 0 && collector_index <
AtomicAdjust::get(_num_collectors));
732 Collector *collector = get_collector_ptr(collector_index);
733 InternalThread *thread = get_thread_ptr(thread_index);
735 if (collector->is_active() && thread->_is_active) {
737 if (collector->_per_thread[thread_index]._nested_count == 0) {
740 if (thread->_thread_active) {
741 thread->_frame_data.add_start(collector_index, get_real_time());
744 collector->_per_thread[thread_index]._nested_count++;
756 start(
int collector_index,
int thread_index,
double as_of) {
757 if (!client_is_connected()) {
762 nassertv(collector_index >= 0 && collector_index <
AtomicAdjust::get(_num_collectors));
766 Collector *collector = get_collector_ptr(collector_index);
767 InternalThread *thread = get_thread_ptr(thread_index);
769 if (collector->is_active() && thread->_is_active) {
771 if (collector->_per_thread[thread_index]._nested_count == 0) {
774 if (thread->_thread_active) {
775 thread->_frame_data.add_start(collector_index, as_of);
778 collector->_per_thread[thread_index]._nested_count++;
790 stop(
int collector_index,
int thread_index) {
791 if (!client_is_connected()) {
796 nassertv(collector_index >= 0 && collector_index <
AtomicAdjust::get(_num_collectors));
800 Collector *collector = get_collector_ptr(collector_index);
801 InternalThread *thread = get_thread_ptr(thread_index);
803 if (collector->is_active() && thread->_is_active) {
805 if (collector->_per_thread[thread_index]._nested_count == 0) {
806 if (pstats_cat.is_debug()) {
808 <<
"Collector " << get_collector_fullname(collector_index)
809 <<
" was already stopped in thread " << get_thread_name(thread_index)
815 collector->_per_thread[thread_index]._nested_count--;
817 if (collector->_per_thread[thread_index]._nested_count == 0) {
820 if (thread->_thread_active) {
821 thread->_frame_data.add_stop(collector_index, get_real_time());
835 stop(
int collector_index,
int thread_index,
double as_of) {
836 if (!client_is_connected()) {
841 nassertv(collector_index >= 0 && collector_index <
AtomicAdjust::get(_num_collectors));
845 Collector *collector = get_collector_ptr(collector_index);
846 InternalThread *thread = get_thread_ptr(thread_index);
848 if (collector->is_active() && thread->_is_active) {
850 if (collector->_per_thread[thread_index]._nested_count == 0) {
851 if (pstats_cat.is_debug()) {
853 <<
"Collector " << get_collector_fullname(collector_index)
854 <<
" was already stopped in thread " << get_thread_name(thread_index)
860 collector->_per_thread[thread_index]._nested_count--;
862 if (collector->_per_thread[thread_index]._nested_count == 0) {
865 thread->_frame_data.add_stop(collector_index, as_of);
881 clear_level(
int collector_index,
int thread_index) {
882 if (!client_is_connected()) {
887 nassertv(collector_index >= 0 && collector_index <
AtomicAdjust::get(_num_collectors));
891 Collector *collector = get_collector_ptr(collector_index);
892 InternalThread *thread = get_thread_ptr(thread_index);
895 collector->_per_thread[thread_index]._has_level =
true;
896 collector->_per_thread[thread_index]._level = 0.0;
909 set_level(
int collector_index,
int thread_index,
double level) {
910 if (!client_is_connected()) {
915 nassertv(collector_index >= 0 && collector_index <
AtomicAdjust::get(_num_collectors));
919 Collector *collector = get_collector_ptr(collector_index);
920 InternalThread *thread = get_thread_ptr(thread_index);
928 level *= collector->get_def(
this, collector_index)->_factor;
930 collector->_per_thread[thread_index]._has_level =
true;
931 collector->_per_thread[thread_index]._level = level;
946 add_level(
int collector_index,
int thread_index,
double increment) {
947 if (!client_is_connected()) {
952 nassertv(collector_index >= 0 && collector_index <
AtomicAdjust::get(_num_collectors));
956 Collector *collector = get_collector_ptr(collector_index);
957 InternalThread *thread = get_thread_ptr(thread_index);
960 increment *= collector->get_def(
this, collector_index)->_factor;
962 collector->_per_thread[thread_index]._has_level =
true;
963 collector->_per_thread[thread_index]._level += increment;
976 get_level(
int collector_index,
int thread_index)
const {
977 if (!client_is_connected()) {
982 nassertr(collector_index >= 0 && collector_index <
AtomicAdjust::get(_num_collectors), 0.0f);
983 nassertr(thread_index >= 0 && thread_index <
AtomicAdjust::get(_num_threads), 0.0f);
986 Collector *collector = get_collector_ptr(collector_index);
987 InternalThread *thread = get_thread_ptr(thread_index);
990 double factor = collector->get_def(
this, collector_index)->_factor;
992 return collector->_per_thread[thread_index]._level / factor;
1008 start_clock_wait() {
1009 _clock_wait_pcollector.start();
1025 start_clock_busy_wait() {
1026 _clock_wait_pcollector.stop();
1027 _clock_busy_wait_pcollector.start();
1044 _clock_busy_wait_pcollector.stop();
1055 add_collector(PStatClient::Collector *collector) {
1056 if (_num_collectors >= _collectors_size) {
1060 int new_collectors_size = (_collectors_size == 0) ? 128 : _collectors_size * 2;
1061 CollectorPointer *new_collectors =
new CollectorPointer[new_collectors_size];
1062 memcpy(new_collectors, _collectors, _num_collectors *
sizeof(CollectorPointer));
1073 new_collectors[_num_collectors] = collector;
1077 CollectorPointer *collectors = (CollectorPointer *)_collectors;
1078 collectors[_num_collectors] = collector;
1091 add_thread(PStatClient::InternalThread *thread) {
1092 _threads_by_name[thread->_name].push_back(_num_threads);
1093 _threads_by_sync_name[thread->_sync_name].push_back(_num_threads);
1095 if (_num_threads >= _threads_size) {
1099 int new_threads_size = (_threads_size == 0) ? 128 : _threads_size * 2;
1100 ThreadPointer *new_threads =
new ThreadPointer[new_threads_size];
1101 memcpy(new_threads, _threads, _num_threads *
sizeof(ThreadPointer));
1114 new_threads[_num_threads] = thread;
1117 ThreadPointer *threads = (ThreadPointer *)_threads;
1118 threads[_num_threads] = thread;
1125 CollectorPointer *collectors = (CollectorPointer *)_collectors;
1126 for (
int ci = 0; ci < _num_collectors; ++ci) {
1127 Collector *collector = collectors[ci];
1128 collector->_per_thread.push_back(PerThreadData());
1129 nassertv((
int)collector->_per_thread.size() == _num_threads);
1143 deactivate_hook(
Thread *thread) {
1148 if (_impl == NULL) {
1152 InternalThread *ithread = get_thread_ptr(thread_index);
1154 if (ithread->_thread_active) {
1157 double now = _impl->get_real_time();
1158 ithread->_frame_data.add_start(_thread_block_pcollector.get_index(), now);
1159 ithread->_thread_active =
false;
1172 activate_hook(
Thread *thread) {
1177 if (_impl == NULL) {
1183 if (!ithread->_thread_active) {
1184 double now = _impl->get_real_time();
1185 ithread->_frame_data.add_stop(_thread_block_pcollector.get_index(), now);
1186 ithread->_thread_active =
true;
1195 void PStatClient::Collector::
1196 make_def(
const PStatClient *client,
int this_index) {
1200 if (_parent_index != this_index) {
1202 client->get_collector_def(_parent_index);
1203 _def->set_parent(*parent_def);
1205 initialize_collector_def(client, _def);
1214 PStatClient::InternalThread::
1215 InternalThread(
Thread *thread) :
1217 _name(thread->get_name()),
1218 _sync_name(thread->get_sync_name()),
1222 _thread_active(true),
1223 _thread_lock(string(
"PStatClient::InternalThread ") + thread->get_name())
1232 PStatClient::InternalThread::
1233 InternalThread(
const string &name,
const string &sync_name) :
1236 _sync_name(sync_name),
1240 _thread_active(true),
1241 _thread_lock(string(
"PStatClient::InternalThread ") + name)
void set_pstats_index(int pstats_index)
Stores a PStats index to be associated with this thread.
TypeHandle get_typehandle(int n)
Returns the nth TypeHandle in the system.
int get_num_typehandles()
Returns the total number of unique TypeHandles in the system.
static void inc(Integer &var)
Atomically increments the indicated variable.
static size_t get_total_unused()
Returns the difference between get_total_alloc() and get_total_used().
static Thread * get_current_thread()
Returns a pointer to the currently-executing Thread object.
int get_pstats_index() const
Returns the PStats index associated with this thread, or -1 if no index has yet been associated with ...
This is our own Panda specialization on the default STL vector.
static Thread * get_main_thread()
Returns a pointer to the "main" Thread object–this is the Thread that started the whole process...
const string & get_sync_name() const
Returns the sync name of the thread.
A lightweight class that represents a single element that may be timed and/or counted via stats...
Similar to MutexHolder, but for a light mutex.
static Integer get(const Integer &var)
Atomically retrieves the snapshot value of the indicated variable.
void set_pstats_callback(PStatsCallback *pstats_callback)
Stores a PStats callback to be associated with this thread.
A lightweight class that represents a single thread of execution to PStats.
Similar to MutexHolder, but for a reentrant mutex.
static TypeRegistry * ptr()
Returns the pointer to the global TypeRegistry object.
The TypeRegistry class maintains all the assigned TypeHandles in a given system.
A thread; that is, a lightweight process.
static Pointer set_ptr(Pointer &var, Pointer new_value)
Atomically changes the indicated variable and returns the original value.
static Integer set(Integer &var, Integer new_value)
Atomically changes the indicated variable and returns the original value.
TypeHandle is the identifier used to differentiate C++ class types.
Defines the details about the Collectors: the name, the suggested color, etc.
Manages the communications to report statistics via a network connection to a remote PStatServer...