|
@@ -24,6 +24,8 @@
|
|
|
#include "config_pstatclient.h"
|
|
#include "config_pstatclient.h"
|
|
|
#include "pStatProperties.h"
|
|
#include "pStatProperties.h"
|
|
|
#include "cmath.h"
|
|
#include "cmath.h"
|
|
|
|
|
+#include "conditionVarWin32Impl.h"
|
|
|
|
|
+#include "conditionVarPosixImpl.h"
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
#include <algorithm>
|
|
|
|
|
|
|
@@ -32,6 +34,15 @@
|
|
|
#include <windows.h>
|
|
#include <windows.h>
|
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
|
|
+static PStatCollector _cswitch_pcollector("Context Switches");
|
|
|
|
|
+static PStatCollector _cswitch_sleep_pcollector("Context Switches:Sleep");
|
|
|
|
|
+static PStatCollector _cswitch_yield_pcollector("Context Switches:Yields");
|
|
|
|
|
+static PStatCollector _cswitch_cvar_pcollector("Context Switches:Condition Variable");
|
|
|
|
|
+static PStatCollector _cswitch_involuntary_pcollector("Context Switches:Involuntary");
|
|
|
|
|
+static PStatCollector _wait_sleep_pcollector("Wait:Sleep");
|
|
|
|
|
+static PStatCollector _wait_yield_pcollector("Wait:Yield");
|
|
|
|
|
+static PStatCollector _wait_cvar_pcollector("Wait:Condition Variable");
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
*
|
|
*
|
|
|
*/
|
|
*/
|
|
@@ -124,6 +135,106 @@ client_connect(std::string hostname, int port) {
|
|
|
MutexDebug::increment_pstats();
|
|
MutexDebug::increment_pstats();
|
|
|
#endif // DEBUG_THREADS
|
|
#endif // DEBUG_THREADS
|
|
|
|
|
|
|
|
|
|
+ if (pstats_thread_profiling) {
|
|
|
|
|
+ // Replace the condition variable wait function with one that does PStats
|
|
|
|
|
+ // statistics.
|
|
|
|
|
+ _thread_profiling = true;
|
|
|
|
|
+
|
|
|
|
|
+ Thread::_sleep_func = [] (double seconds) {
|
|
|
|
|
+ Thread *current_thread = Thread::get_current_thread();
|
|
|
|
|
+ int thread_index = current_thread->get_pstats_index();
|
|
|
|
|
+ if (thread_index >= 0) {
|
|
|
|
|
+ PStatClient *client = PStatClient::get_global_pstats();
|
|
|
|
|
+ double start = client->get_real_time();
|
|
|
|
|
+ ThreadImpl::sleep(seconds);
|
|
|
|
|
+ double stop = client->get_real_time();
|
|
|
|
|
+ client->start_stop(_wait_sleep_pcollector.get_index(), thread_index, start, stop);
|
|
|
|
|
+ client->add_level(_cswitch_sleep_pcollector.get_index(), thread_index, 1);
|
|
|
|
|
+ }
|
|
|
|
|
+ else {
|
|
|
|
|
+ ThreadImpl::sleep(seconds);
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ Thread::_yield_func = [] () {
|
|
|
|
|
+ Thread *current_thread = Thread::get_current_thread();
|
|
|
|
|
+ int thread_index = current_thread->get_pstats_index();
|
|
|
|
|
+ if (thread_index >= 0) {
|
|
|
|
|
+ PStatClient *client = PStatClient::get_global_pstats();
|
|
|
|
|
+ double start = client->get_real_time();
|
|
|
|
|
+ ThreadImpl::yield();
|
|
|
|
|
+ double stop = client->get_real_time();
|
|
|
|
|
+ client->start_stop(_wait_yield_pcollector.get_index(), thread_index, start, stop);
|
|
|
|
|
+ client->add_level(_cswitch_yield_pcollector.get_index(), thread_index, 1);
|
|
|
|
|
+ }
|
|
|
|
|
+ else {
|
|
|
|
|
+ ThreadImpl::yield();
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+#ifdef _WIN32
|
|
|
|
|
+ ConditionVarWin32Impl::_wait_func =
|
|
|
|
|
+ [] (PCONDITION_VARIABLE cvar, PSRWLOCK lock, DWORD time, ULONG flags) {
|
|
|
|
|
+ Thread *current_thread = Thread::get_current_thread();
|
|
|
|
|
+ int thread_index = current_thread->get_pstats_index();
|
|
|
|
|
+ BOOL result;
|
|
|
|
|
+ if (thread_index >= 0) {
|
|
|
|
|
+ PStatClient *client = PStatClient::get_global_pstats();
|
|
|
|
|
+ double start = client->get_real_time();
|
|
|
|
|
+ result = SleepConditionVariableSRW(cvar, lock, time, flags);
|
|
|
|
|
+ double stop = client->get_real_time();
|
|
|
|
|
+ client->start_stop(_wait_cvar_pcollector.get_index(), thread_index, start, stop);
|
|
|
|
|
+ client->add_level(_cswitch_cvar_pcollector.get_index(), thread_index, 1);
|
|
|
|
|
+ }
|
|
|
|
|
+ else {
|
|
|
|
|
+ result = SleepConditionVariableSRW(cvar, lock, time, flags);
|
|
|
|
|
+ }
|
|
|
|
|
+ return result;
|
|
|
|
|
+ };
|
|
|
|
|
+#endif
|
|
|
|
|
+
|
|
|
|
|
+#ifdef HAVE_POSIX_THREADS
|
|
|
|
|
+ ConditionVarPosixImpl::_wait_func =
|
|
|
|
|
+ [] (pthread_cond_t *cvar, pthread_mutex_t *lock) {
|
|
|
|
|
+ Thread *current_thread = Thread::get_current_thread();
|
|
|
|
|
+ int thread_index = current_thread->get_pstats_index();
|
|
|
|
|
+ int result;
|
|
|
|
|
+ if (thread_index >= 0) {
|
|
|
|
|
+ PStatClient *client = PStatClient::get_global_pstats();
|
|
|
|
|
+ double start = client->get_real_time();
|
|
|
|
|
+ result = pthread_cond_wait(cvar, lock);
|
|
|
|
|
+ double stop = client->get_real_time();
|
|
|
|
|
+ client->start_stop(_wait_cvar_pcollector.get_index(), thread_index, start, stop);
|
|
|
|
|
+ client->add_level(_cswitch_cvar_pcollector.get_index(), thread_index, 1);
|
|
|
|
|
+ }
|
|
|
|
|
+ else {
|
|
|
|
|
+ result = pthread_cond_wait(cvar, lock);
|
|
|
|
|
+ }
|
|
|
|
|
+ return result;
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ ConditionVarPosixImpl::_timedwait_func =
|
|
|
|
|
+ [] (pthread_cond_t *cvar, pthread_mutex_t *lock,
|
|
|
|
|
+ const struct timespec *ts) {
|
|
|
|
|
+ Thread *current_thread = Thread::get_current_thread();
|
|
|
|
|
+ int thread_index = current_thread->get_pstats_index();
|
|
|
|
|
+ int result;
|
|
|
|
|
+ if (thread_index >= 0) {
|
|
|
|
|
+ PStatClient *client = PStatClient::get_global_pstats();
|
|
|
|
|
+ double start = client->get_real_time();
|
|
|
|
|
+ result = pthread_cond_timedwait(cvar, lock, ts);
|
|
|
|
|
+ double stop = client->get_real_time();
|
|
|
|
|
+ client->start_stop(_wait_cvar_pcollector.get_index(), thread_index, start, stop);
|
|
|
|
|
+ client->add_level(_cswitch_cvar_pcollector.get_index(), thread_index, 1);
|
|
|
|
|
+ }
|
|
|
|
|
+ else {
|
|
|
|
|
+ result = pthread_cond_timedwait(cvar, lock, ts);
|
|
|
|
|
+ }
|
|
|
|
|
+ return result;
|
|
|
|
|
+ };
|
|
|
|
|
+#endif
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
// Wait for the server hello.
|
|
// Wait for the server hello.
|
|
|
while (!_got_udp_port) {
|
|
while (!_got_udp_port) {
|
|
|
transmit_control_data();
|
|
transmit_control_data();
|
|
@@ -137,6 +248,23 @@ client_connect(std::string hostname, int port) {
|
|
|
*/
|
|
*/
|
|
|
void PStatClientImpl::
|
|
void PStatClientImpl::
|
|
|
client_disconnect() {
|
|
client_disconnect() {
|
|
|
|
|
+ if (_thread_profiling) {
|
|
|
|
|
+ // Switch the functions back to what they were.
|
|
|
|
|
+ Thread::_sleep_func = &ThreadImpl::sleep;
|
|
|
|
|
+ Thread::_yield_func = &ThreadImpl::yield;
|
|
|
|
|
+
|
|
|
|
|
+#ifdef _WIN32
|
|
|
|
|
+ ConditionVarWin32Impl::_wait_func = &SleepConditionVariableSRW;
|
|
|
|
|
+#endif
|
|
|
|
|
+
|
|
|
|
|
+#ifdef HAVE_POSIX_THREADS
|
|
|
|
|
+ ConditionVarPosixImpl::_wait_func = &pthread_cond_wait;
|
|
|
|
|
+ ConditionVarPosixImpl::_timedwait_func = &pthread_cond_timedwait;
|
|
|
|
|
+#endif
|
|
|
|
|
+
|
|
|
|
|
+ _thread_profiling = false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
if (_is_connected) {
|
|
if (_is_connected) {
|
|
|
#ifdef DEBUG_THREADS
|
|
#ifdef DEBUG_THREADS
|
|
|
MutexDebug::decrement_pstats();
|
|
MutexDebug::decrement_pstats();
|
|
@@ -207,6 +335,37 @@ new_frame(int thread_index, int frame_number) {
|
|
|
if (frame_number == -1) {
|
|
if (frame_number == -1) {
|
|
|
frame_number = pthread->_frame_number;
|
|
frame_number = pthread->_frame_number;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ // Record the number of context switches on this thread.
|
|
|
|
|
+ if (_thread_profiling) {
|
|
|
|
|
+ size_t total, involuntary;
|
|
|
|
|
+ PT(Thread) thread = pthread->_thread.lock();
|
|
|
|
|
+ if (thread != nullptr && thread->get_context_switches(total, involuntary)) {
|
|
|
|
|
+ size_t total_this_frame = total - pthread->_context_switches;
|
|
|
|
|
+ pthread->_context_switches = total;
|
|
|
|
|
+ frame_data.add_level(_cswitch_pcollector.get_index(), total_this_frame);
|
|
|
|
|
+
|
|
|
|
|
+ if (involuntary != 0) {
|
|
|
|
|
+ size_t involuntary_this_frame = involuntary - pthread->_involuntary_context_switches;
|
|
|
|
|
+ pthread->_involuntary_context_switches = involuntary;
|
|
|
|
|
+ frame_data.add_level(_cswitch_involuntary_pcollector.get_index(), involuntary_this_frame);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ _client->clear_level(_cswitch_sleep_pcollector.get_index(), thread_index);
|
|
|
|
|
+ _client->clear_level(_cswitch_yield_pcollector.get_index(), thread_index);
|
|
|
|
|
+ _client->clear_level(_cswitch_cvar_pcollector.get_index(), thread_index);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ else if (_thread_profiling) {
|
|
|
|
|
+ // Record the initial number of context switches.
|
|
|
|
|
+ PT(Thread) thread = pthread->_thread.lock();
|
|
|
|
|
+ if (thread != nullptr) {
|
|
|
|
|
+ thread->get_context_switches(pthread->_context_switches,
|
|
|
|
|
+ pthread->_involuntary_context_switches);
|
|
|
|
|
+ }
|
|
|
|
|
+ _client->clear_level(_cswitch_sleep_pcollector.get_index(), thread_index);
|
|
|
|
|
+ _client->clear_level(_cswitch_yield_pcollector.get_index(), thread_index);
|
|
|
|
|
+ _client->clear_level(_cswitch_cvar_pcollector.get_index(), thread_index);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
pthread->_frame_data.clear();
|
|
pthread->_frame_data.clear();
|