Made everything threadsafe.

This commit is contained in:
hiker 2017-08-02 08:34:43 +10:00
parent ea12c8f494
commit d800a8c0bc
2 changed files with 31 additions and 14 deletions

View File

@ -113,10 +113,6 @@ Profiler::Profiler()
m_time_between_sync = 0.0; m_time_between_sync = 0.0;
m_freeze_state = UNFROZEN; m_freeze_state = UNFROZEN;
// By limiting the number of threads that can be created, we avoid the
// problem that all access to m_all_event_data need to be locked
// (otherwise adding a thread to m_all_event_data can trigger a
// reallocate, which makes concurrent access invalid)
m_max_frames = int( UserConfigParams::m_profiler_buffer_duration m_max_frames = int( UserConfigParams::m_profiler_buffer_duration
* UserConfigParams::m_max_fps ); * UserConfigParams::m_max_fps );
m_current_frame = 0; m_current_frame = 0;
@ -124,7 +120,7 @@ Profiler::Profiler()
m_threads_used = 0; m_threads_used = 0;
const int MAX_THREADS = 10; const int MAX_THREADS = 10;
m_all_threads_data.resize(MAX_THREADS); m_all_threads_data.resize(MAX_THREADS);
m_thread_mapping.getData().resize(MAX_THREADS); m_thread_mapping.resize(MAX_THREADS);
m_gpu_times.resize(Q_LAST*m_max_frames); m_gpu_times.resize(Q_LAST*m_max_frames);
} // Profile } // Profile
@ -134,27 +130,28 @@ Profiler::~Profiler()
} // ~Profiler } // ~Profiler
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
/** Returns a unique index for a thread. If the calling thread is not yet in
* the mapping, it will assign a new unique id to this thread. This function
* is NOT thread-safe and must be called from a properly protected code
* section. */
int Profiler::getThreadID() int Profiler::getThreadID()
{ {
m_thread_mapping.lock();
pthread_t thread = pthread_self(); pthread_t thread = pthread_self();
int i = 0; int i = 0;
while(i < m_threads_used) while(i < m_threads_used)
{ {
if (memcmp( &m_thread_mapping.getData()[i], if (memcmp( &m_thread_mapping[i],
&thread, &thread,
sizeof(thread)) ==0 ) sizeof(thread)) ==0 )
{ {
m_thread_mapping.unlock();
return i; return i;
} }
i++; i++;
} // for i <m_threads_used } // for i <m_threads_used
assert(m_threads_used < (int)m_thread_mapping.getData().size()); assert(m_threads_used < (int)m_thread_mapping.size());
m_thread_mapping.getData()[m_threads_used] = thread; m_thread_mapping[m_threads_used] = thread;
m_threads_used++; m_threads_used++;
m_thread_mapping.unlock();
return m_threads_used - 1; return m_threads_used - 1;
} // getThreadID } // getThreadID
@ -168,6 +165,10 @@ void Profiler::pushCPUMarker(const char* name, const video::SColor& colour)
return; return;
double start = getTimeMilliseconds() - m_time_last_sync; double start = getTimeMilliseconds() - m_time_last_sync;
// We need to look before getting the thread id (since this might
// be a new thread which changes the structure).
m_lock.lock();
int thread_id = getThreadID(); int thread_id = getThreadID();
ThreadData &td = m_all_threads_data[thread_id]; ThreadData &td = m_all_threads_data[thread_id];
@ -182,8 +183,8 @@ void Profiler::pushCPUMarker(const char* name, const video::SColor& colour)
ed.setStart(m_current_frame, start, td.m_event_stack.size()); ed.setStart(m_current_frame, start, td.m_event_stack.size());
td.m_all_event_data[name] = ed; td.m_all_event_data[name] = ed;
} }
td.m_event_stack.push_back(name); td.m_event_stack.push_back(name);
m_lock.unlock();
} // pushCPUMarker } // pushCPUMarker
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -194,6 +195,7 @@ void Profiler::popCPUMarker()
if(m_freeze_state == FROZEN || m_freeze_state == WAITING_FOR_UNFREEZE) if(m_freeze_state == FROZEN || m_freeze_state == WAITING_FOR_UNFREEZE)
return; return;
m_lock.lock();
int thread_id = getThreadID(); int thread_id = getThreadID();
ThreadData &td = m_all_threads_data[thread_id]; ThreadData &td = m_all_threads_data[thread_id];
@ -204,6 +206,7 @@ void Profiler::popCPUMarker()
getTimeMilliseconds() - m_time_last_sync); getTimeMilliseconds() - m_time_last_sync);
td.m_event_stack.pop_back(); td.m_event_stack.pop_back();
m_lock.unlock();
} // popCPUMarker } // popCPUMarker
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -222,6 +225,7 @@ void Profiler::synchronizeFrame()
// which would yield different results // which would yield different results
double now = getTimeMilliseconds(); double now = getTimeMilliseconds();
m_lock.lock();
// Set index to next frame // Set index to next frame
int next_frame = m_current_frame+1; int next_frame = m_current_frame+1;
if (next_frame >= m_max_frames) if (next_frame >= m_max_frames)
@ -257,6 +261,8 @@ void Profiler::synchronizeFrame()
m_freeze_state = FROZEN; m_freeze_state = FROZEN;
else if(m_freeze_state == WAITING_FOR_UNFREEZE) else if(m_freeze_state == WAITING_FOR_UNFREEZE)
m_freeze_state = UNFROZEN; m_freeze_state = UNFROZEN;
m_lock.unlock();
} // synchronizeFrame } // synchronizeFrame
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -269,8 +275,10 @@ void Profiler::draw()
// Current frame points to the frame in which currently data is // Current frame points to the frame in which currently data is
// being accumulated. Draw the previous (i.e. complete) frame. // being accumulated. Draw the previous (i.e. complete) frame.
m_lock.lock();
int indx = m_current_frame - 1; int indx = m_current_frame - 1;
if (indx < 0) indx = m_max_frames - 1; if (indx < 0) indx = m_max_frames - 1;
m_lock.unlock();
drawBackground(); drawBackground();
@ -492,6 +500,7 @@ void Profiler::drawBackground()
*/ */
void Profiler::writeToFile() void Profiler::writeToFile()
{ {
m_lock.lock();
std::string base_name = std::string base_name =
file_manager->getUserConfigFile(file_manager->getStdoutName()); file_manager->getUserConfigFile(file_manager->getStdoutName());
// First CPU data // First CPU data
@ -551,4 +560,6 @@ void Profiler::writeToFile()
start = (start + 1) % m_max_frames; start = (start + 1) % m_max_frames;
} }
f.close(); f.close();
m_lock.unlock();
} // writeFile } // writeFile

View File

@ -219,7 +219,7 @@ private:
std::vector< ThreadData> m_all_threads_data; std::vector< ThreadData> m_all_threads_data;
/** A mapping of thread_t pointers to a unique integer (starting from 0).*/ /** A mapping of thread_t pointers to a unique integer (starting from 0).*/
Synchronised< std::vector<pthread_t> > m_thread_mapping; std::vector<pthread_t> m_thread_mapping;
/** Buffer for the GPU times (in ms). */ /** Buffer for the GPU times (in ms). */
std::vector<int> m_gpu_times; std::vector<int> m_gpu_times;
@ -230,6 +230,12 @@ private:
/** Index of the current frame in the buffer. */ /** Index of the current frame in the buffer. */
int m_current_frame; int m_current_frame;
/** We don't need the bool, but easiest way to get a lock for the whole
* instance (since we need to avoid that a synch is done which changes
* the current frame while another threaded uses this variable, or
* while a new thread is added. */
Synchronised<bool> m_lock;
/** True if the circular buffer has wrapped around. */ /** True if the circular buffer has wrapped around. */
bool m_has_wrapped_around; bool m_has_wrapped_around;