Pthread -> std::thread (2/7) - Remove pthread in Profilers
Use std::thread and thread_local instead of pthread specific calls. Differential Revision: https://code.wildfiregames.com/D1916 This was SVN commit r22608.
This commit is contained in:
parent
accd72b3c1
commit
9ece3e7088
@ -463,7 +463,7 @@ static long get_memory_alloc_count()
|
||||
// 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 @@ static void *malloc_hook(size_t size, const void* UNUSED(caller))
|
||||
|
||||
// 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<std::mutex> 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<std::mutex> 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:
|
||||
|
@ -39,6 +39,8 @@ CProfiler2 g_Profiler2;
|
||||
// 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 @@ static void* MgCallback(mg_event event, struct mg_connection *conn, const struct
|
||||
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 @@ void CProfiler2::Shutdown()
|
||||
// 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 @@ void CProfiler2::RecordGPURegionLeave(const char* id)
|
||||
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<std::mutex> lock(m_Mutex);
|
||||
m_Threads.push_back(storage);
|
||||
m_Threads.push_back(std::unique_ptr<ThreadStorage>(storage));
|
||||
}
|
||||
|
||||
void CProfiler2::RemoveThreadStorage(ThreadStorage* storage)
|
||||
{
|
||||
std::lock_guard<std::mutex> 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<ThreadStorage>& s) { return s.get() == storage; }));
|
||||
}
|
||||
|
||||
CProfiler2::ThreadStorage::ThreadStorage(CProfiler2& profiler, const std::string& name) :
|
||||
@ -727,11 +708,13 @@ void CProfiler2::ConstructJSONOverview(std::ostream& stream)
|
||||
std::lock_guard<std::mutex> lock(m_Mutex);
|
||||
|
||||
stream << "{\"threads\":[";
|
||||
for (size_t i = 0; i < m_Threads.size(); ++i)
|
||||
bool first_time = true;
|
||||
for (std::unique_ptr<ThreadStorage>& 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 @@ const char* CProfiler2::ConstructJSONResponse(std::ostream& stream, const std::s
|
||||
|
||||
std::lock_guard<std::mutex> 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<ThreadStorage>& 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 @@ void CProfiler2::SaveToFile()
|
||||
std::ofstream stream(OsString(path).c_str(), std::ofstream::out | std::ofstream::trunc);
|
||||
ENSURE(stream.good());
|
||||
|
||||
std::vector<ThreadStorage*> threads;
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> 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<ThreadStorage>& 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";
|
||||
}
|
||||
|
@ -78,6 +78,9 @@
|
||||
#ifndef INCLUDED_PROFILER2
|
||||
#define INCLUDED_PROFILER2
|
||||
|
||||
#include <map>
|
||||
#include <thread>
|
||||
|
||||
#include "lib/timer.h"
|
||||
#include "ps/ThreadUtil.h"
|
||||
|
||||
@ -436,13 +439,10 @@ public:
|
||||
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 @@ private:
|
||||
|
||||
mg_context* m_MgContext;
|
||||
|
||||
pthread_key_t m_TLS;
|
||||
|
||||
CProfiler2GPU* m_GPU;
|
||||
|
||||
std::mutex m_Mutex;
|
||||
std::vector<ThreadStorage*> m_Threads; // thread-safe; protected by m_Mutex
|
||||
|
||||
static thread_local ThreadStorage* m_CurrentStorage;
|
||||
std::vector<std::unique_ptr<ThreadStorage>> m_Threads; // thread-safe; protected by m_Mutex
|
||||
};
|
||||
|
||||
extern CProfiler2 g_Profiler2;
|
||||
|
@ -37,7 +37,7 @@ class CProfiler2GPU_base
|
||||
|
||||
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 @@ protected:
|
||||
}
|
||||
|
||||
CProfiler2& m_Profiler;
|
||||
CProfiler2::ThreadStorage m_Storage;
|
||||
CProfiler2::ThreadStorage& m_Storage;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
Loading…
Reference in New Issue
Block a user