Index: ps/trunk/source/ps/Profile.cpp =================================================================== --- ps/trunk/source/ps/Profile.cpp +++ ps/trunk/source/ps/Profile.cpp @@ -463,7 +463,7 @@ // http://www.gnu.org/software/libc/manual/html_node/Hooks-for-Malloc.html static intptr_t malloc_count = 0; static void *(*old_malloc_hook) (size_t, const void*); -static pthread_mutex_t alloc_hook_mutex = PTHREAD_MUTEX_INITIALIZER; +static std::mutex alloc_hook_mutex; static void *malloc_hook(size_t size, const void* UNUSED(caller)) { // This doesn't really work across threads. The hooks are global variables, and @@ -473,24 +473,22 @@ // Two threads may execute the hook simultaneously, so we need to do the // temporary unhooking in a thread-safe way, so for simplicity we just use a mutex. - pthread_mutex_lock(&alloc_hook_mutex); + std::lock_guard lock(alloc_hook_mutex); ++malloc_count; __malloc_hook = old_malloc_hook; void* result = malloc(size); old_malloc_hook = __malloc_hook; __malloc_hook = malloc_hook; - pthread_mutex_unlock(&alloc_hook_mutex); return result; } static void alloc_hook_initialize() { - pthread_mutex_lock(&alloc_hook_mutex); + std::lock_guard lock(alloc_hook_mutex); old_malloc_hook = __malloc_hook; __malloc_hook = malloc_hook; // (we don't want to bother hooking realloc and memalign, because if they allocate // new memory then they'll be caught by the malloc hook anyway) - pthread_mutex_unlock(&alloc_hook_mutex); } /* It would be nice to do: Index: ps/trunk/source/ps/Profiler2.h =================================================================== --- ps/trunk/source/ps/Profiler2.h +++ ps/trunk/source/ps/Profiler2.h @@ -78,6 +78,9 @@ #ifndef INCLUDED_PROFILER2 #define INCLUDED_PROFILER2 +#include +#include + #include "lib/timer.h" #include "ps/ThreadUtil.h" @@ -436,13 +439,10 @@ private: void InitialiseGPU(); - static void TLSDtor(void* data); - ThreadStorage& GetThreadStorage() { - ThreadStorage* storage = (ThreadStorage*)pthread_getspecific(m_TLS); - ASSERT(storage); - return *storage; + ENSURE(m_CurrentStorage); + return *m_CurrentStorage; } bool m_Initialised; @@ -451,12 +451,12 @@ mg_context* m_MgContext; - pthread_key_t m_TLS; - CProfiler2GPU* m_GPU; std::mutex m_Mutex; - std::vector m_Threads; // thread-safe; protected by m_Mutex + + static thread_local ThreadStorage* m_CurrentStorage; + std::vector> m_Threads; // thread-safe; protected by m_Mutex }; extern CProfiler2 g_Profiler2; Index: ps/trunk/source/ps/Profiler2.cpp =================================================================== --- ps/trunk/source/ps/Profiler2.cpp +++ ps/trunk/source/ps/Profiler2.cpp @@ -39,6 +39,8 @@ // A human-recognisable pattern (for debugging) followed by random bytes (for uniqueness) const u8 CProfiler2::RESYNC_MAGIC[8] = {0x11, 0x22, 0x33, 0x44, 0xf4, 0x93, 0xbe, 0x15}; +thread_local CProfiler2::ThreadStorage* CProfiler2::m_CurrentStorage = nullptr; + CProfiler2::CProfiler2() : m_Initialised(false), m_FrameNumber(0), m_MgContext(NULL), m_GPU(NULL) { @@ -148,8 +150,6 @@ void CProfiler2::Initialise() { ENSURE(!m_Initialised); - int err = pthread_key_create(&m_TLS, &CProfiler2::TLSDtor); - ENSURE(err == 0); m_Initialised = true; RegisterCurrentThread("main"); @@ -235,11 +235,6 @@ // the destructor is not called for the main thread // we have to call it manually to avoid memory leaks ENSURE(ThreadUtil::IsMainThread()); - void * dataptr = pthread_getspecific(m_TLS); - TLSDtor(dataptr); - - int err = pthread_key_delete(m_TLS); - ENSURE(err == 0); m_Initialised = false; } @@ -267,44 +262,30 @@ m_GPU->RegionLeave(id); } -/** - * Called by pthreads when a registered thread is destroyed. - */ -void CProfiler2::TLSDtor(void* data) -{ - ThreadStorage* storage = (ThreadStorage*)data; - - storage->GetProfiler().RemoveThreadStorage(storage); - - delete (ThreadStorage*)data; -} - void CProfiler2::RegisterCurrentThread(const std::string& name) { ENSURE(m_Initialised); - ENSURE(pthread_getspecific(m_TLS) == NULL); // mustn't register a thread more than once + // Must not register a thread more than once. + ENSURE(m_CurrentStorage == nullptr); - ThreadStorage* storage = new ThreadStorage(*this, name); - int err = pthread_setspecific(m_TLS, storage); - ENSURE(err == 0); + m_CurrentStorage = new ThreadStorage(*this, name); + AddThreadStorage(m_CurrentStorage); RecordSyncMarker(); RecordEvent("thread start"); - - AddThreadStorage(storage); } void CProfiler2::AddThreadStorage(ThreadStorage* storage) { std::lock_guard lock(m_Mutex); - m_Threads.push_back(storage); + m_Threads.push_back(std::unique_ptr(storage)); } void CProfiler2::RemoveThreadStorage(ThreadStorage* storage) { std::lock_guard lock(m_Mutex); - m_Threads.erase(std::find(m_Threads.begin(), m_Threads.end(), storage)); + m_Threads.erase(std::find_if(m_Threads.begin(), m_Threads.end(), [storage](const std::unique_ptr& s) { return s.get() == storage; })); } CProfiler2::ThreadStorage::ThreadStorage(CProfiler2& profiler, const std::string& name) : @@ -727,11 +708,13 @@ std::lock_guard lock(m_Mutex); stream << "{\"threads\":["; - for (size_t i = 0; i < m_Threads.size(); ++i) + bool first_time = true; + for (std::unique_ptr& storage : m_Threads) { - if (i != 0) + if (!first_time) stream << ","; - stream << "{\"name\":\"" << CStr(m_Threads[i]->GetName()).EscapeToPrintableASCII() << "\"}"; + stream << "{\"name\":\"" << CStr(storage->GetName()).EscapeToPrintableASCII() << "\"}"; + first_time = false; } stream << "]}"; } @@ -904,23 +887,17 @@ std::lock_guard lock(m_Mutex); // lock against changes to m_Threads or deletions of ThreadStorage - ThreadStorage* storage = NULL; - for (size_t i = 0; i < m_Threads.size(); ++i) - { - if (m_Threads[i]->GetName() == thread) - { - storage = m_Threads[i]; - break; - } - } + auto it = std::find_if(m_Threads.begin(), m_Threads.end(), [&thread](std::unique_ptr& storage) { + return storage->GetName() == thread; + }); - if (!storage) + if (it == m_Threads.end()) return "cannot find named thread"; stream << "{\"events\":[\n"; stream << "[\n"; - buffer = storage->GetBuffer(); + buffer = (*it)->GetBuffer(); } BufferVisitor_Dump visitor(stream); @@ -937,22 +914,17 @@ std::ofstream stream(OsString(path).c_str(), std::ofstream::out | std::ofstream::trunc); ENSURE(stream.good()); - std::vector threads; - - { - std::lock_guard lock(m_Mutex); - threads = m_Threads; - } - stream << "profileDataCB({\"threads\": [\n"; - for (size_t i = 0; i < threads.size(); ++i) + bool first_time = true; + for (std::unique_ptr& storage : m_Threads) { - if (i != 0) + if (!first_time) stream << ",\n"; - stream << "{\"name\":\"" << CStr(threads[i]->GetName()).EscapeToPrintableASCII() << "\",\n"; + stream << "{\"name\":\"" << CStr(storage->GetName()).EscapeToPrintableASCII() << "\",\n"; stream << "\"data\": "; - ConstructJSONResponse(stream, threads[i]->GetName()); + ConstructJSONResponse(stream, storage->GetName()); stream << "\n}"; + first_time = false; } stream << "\n]});\n"; } Index: ps/trunk/source/ps/Profiler2GPU.cpp =================================================================== --- ps/trunk/source/ps/Profiler2GPU.cpp +++ ps/trunk/source/ps/Profiler2GPU.cpp @@ -37,7 +37,7 @@ protected: CProfiler2GPU_base(CProfiler2& profiler, const char* name) : - m_Profiler(profiler), m_Storage(profiler, name) + m_Profiler(profiler), m_Storage(*new CProfiler2::ThreadStorage(profiler, name)) { m_Storage.RecordSyncMarker(m_Profiler.GetTime()); m_Storage.Record(CProfiler2::ITEM_EVENT, m_Profiler.GetTime(), "thread start"); @@ -51,7 +51,7 @@ } CProfiler2& m_Profiler; - CProfiler2::ThreadStorage m_Storage; + CProfiler2::ThreadStorage& m_Storage; }; //////////////////////////////////////////////////////////////////////////