TracySystem.cpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. #if defined _MSC_VER || defined __CYGWIN__ || defined _WIN32
  2. # ifndef WIN32_LEAN_AND_MEAN
  3. # define WIN32_LEAN_AND_MEAN
  4. # endif
  5. # ifndef NOMINMAX
  6. # define NOMINMAX
  7. # endif
  8. #endif
  9. #ifdef _MSC_VER
  10. # pragma warning(disable:4996)
  11. #endif
  12. #if defined _WIN32 || defined __CYGWIN__
  13. # include <windows.h>
  14. #else
  15. # include <pthread.h>
  16. # include <string.h>
  17. # include <unistd.h>
  18. #endif
  19. #ifdef __linux__
  20. # ifdef __ANDROID__
  21. # include <sys/types.h>
  22. # else
  23. # include <sys/syscall.h>
  24. # endif
  25. # include <fcntl.h>
  26. #elif defined __FreeBSD__
  27. # include <sys/thr.h>
  28. #elif defined __NetBSD__ || defined __DragonFly__
  29. # include <sys/lwp.h>
  30. #endif
  31. #ifdef __MINGW32__
  32. # define __STDC_FORMAT_MACROS
  33. #endif
  34. #include <inttypes.h>
  35. #include <stdio.h>
  36. #include <stdlib.h>
  37. #include "TracySystem.hpp"
  38. #if defined _WIN32 || defined __CYGWIN__
  39. extern "C" typedef HRESULT (WINAPI *t_SetThreadDescription)( HANDLE, PCWSTR );
  40. extern "C" typedef HRESULT (WINAPI *t_GetThreadDescription)( HANDLE, PWSTR* );
  41. #endif
  42. #ifdef TRACY_ENABLE
  43. # include <atomic>
  44. # include "TracyAlloc.hpp"
  45. #endif
  46. namespace tracy
  47. {
  48. namespace detail
  49. {
  50. TRACY_API uint64_t GetThreadHandleImpl()
  51. {
  52. #if defined _WIN32 || defined __CYGWIN__
  53. static_assert( sizeof( decltype( GetCurrentThreadId() ) ) <= sizeof( uint64_t ), "Thread handle too big to fit in protocol" );
  54. return uint64_t( GetCurrentThreadId() );
  55. #elif defined __APPLE__
  56. uint64_t id;
  57. pthread_threadid_np( pthread_self(), &id );
  58. return id;
  59. #elif defined __ANDROID__
  60. return (uint64_t)gettid();
  61. #elif defined __linux__
  62. return (uint64_t)syscall( SYS_gettid );
  63. #elif defined __FreeBSD__
  64. long id;
  65. thr_self( &id );
  66. return id;
  67. #elif defined __NetBSD__
  68. return _lwp_self();
  69. #elif defined __DragonFly__
  70. return lwp_gettid();
  71. #elif defined __OpenBSD__
  72. return getthrid();
  73. #else
  74. static_assert( sizeof( decltype( pthread_self() ) ) <= sizeof( uint64_t ), "Thread handle too big to fit in protocol" );
  75. return uint64_t( pthread_self() );
  76. #endif
  77. }
  78. }
  79. #ifdef TRACY_ENABLE
  80. struct ThreadNameData
  81. {
  82. uint64_t id;
  83. const char* name;
  84. ThreadNameData* next;
  85. };
  86. std::atomic<ThreadNameData*>& GetThreadNameData();
  87. TRACY_API void InitRPMallocThread();
  88. #endif
  89. TRACY_API void SetThreadName( const char* name )
  90. {
  91. #if defined _WIN32 || defined __CYGWIN__
  92. static auto _SetThreadDescription = (t_SetThreadDescription)GetProcAddress( GetModuleHandleA( "kernel32.dll" ), "SetThreadDescription" );
  93. if( _SetThreadDescription )
  94. {
  95. wchar_t buf[256];
  96. mbstowcs( buf, name, 256 );
  97. _SetThreadDescription( GetCurrentThread(), buf );
  98. }
  99. else
  100. {
  101. # if defined _MSC_VER
  102. const DWORD MS_VC_EXCEPTION=0x406D1388;
  103. # pragma pack( push, 8 )
  104. struct THREADNAME_INFO
  105. {
  106. DWORD dwType;
  107. LPCSTR szName;
  108. DWORD dwThreadID;
  109. DWORD dwFlags;
  110. };
  111. # pragma pack(pop)
  112. DWORD ThreadId = GetCurrentThreadId();
  113. THREADNAME_INFO info;
  114. info.dwType = 0x1000;
  115. info.szName = name;
  116. info.dwThreadID = ThreadId;
  117. info.dwFlags = 0;
  118. __try
  119. {
  120. RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info );
  121. }
  122. __except(EXCEPTION_EXECUTE_HANDLER)
  123. {
  124. }
  125. # endif
  126. }
  127. #elif defined _GNU_SOURCE && !defined __EMSCRIPTEN__ && !defined __CYGWIN__
  128. {
  129. const auto sz = strlen( name );
  130. if( sz <= 15 )
  131. {
  132. pthread_setname_np( pthread_self(), name );
  133. }
  134. else
  135. {
  136. char buf[16];
  137. memcpy( buf, name, 15 );
  138. buf[15] = '\0';
  139. pthread_setname_np( pthread_self(), buf );
  140. }
  141. }
  142. #endif
  143. #ifdef TRACY_ENABLE
  144. {
  145. InitRPMallocThread();
  146. const auto sz = strlen( name );
  147. char* buf = (char*)tracy_malloc( sz+1 );
  148. memcpy( buf, name, sz );
  149. buf[sz] = '\0';
  150. auto data = (ThreadNameData*)tracy_malloc( sizeof( ThreadNameData ) );
  151. data->id = detail::GetThreadHandleImpl();
  152. data->name = buf;
  153. data->next = GetThreadNameData().load( std::memory_order_relaxed );
  154. while( !GetThreadNameData().compare_exchange_weak( data->next, data, std::memory_order_release, std::memory_order_relaxed ) ) {}
  155. }
  156. #endif
  157. }
  158. TRACY_API const char* GetThreadName( uint64_t id )
  159. {
  160. static char buf[256];
  161. #ifdef TRACY_ENABLE
  162. auto ptr = GetThreadNameData().load( std::memory_order_relaxed );
  163. while( ptr )
  164. {
  165. if( ptr->id == id )
  166. {
  167. return ptr->name;
  168. }
  169. ptr = ptr->next;
  170. }
  171. #else
  172. # if defined _WIN32 || defined __CYGWIN__
  173. static auto _GetThreadDescription = (t_GetThreadDescription)GetProcAddress( GetModuleHandleA( "kernel32.dll" ), "GetThreadDescription" );
  174. if( _GetThreadDescription )
  175. {
  176. auto hnd = OpenThread( THREAD_QUERY_LIMITED_INFORMATION, FALSE, (DWORD)id );
  177. if( hnd != 0 )
  178. {
  179. PWSTR tmp;
  180. _GetThreadDescription( hnd, &tmp );
  181. auto ret = wcstombs( buf, tmp, 256 );
  182. CloseHandle( hnd );
  183. if( ret != 0 )
  184. {
  185. return buf;
  186. }
  187. }
  188. }
  189. # elif defined __linux__
  190. int cs, fd;
  191. char path[32];
  192. # ifdef __ANDROID__
  193. int tid = gettid();
  194. # else
  195. int tid = (int) syscall( SYS_gettid );
  196. # endif
  197. snprintf( path, sizeof( path ), "/proc/self/task/%d/comm", tid );
  198. sprintf( buf, "%" PRIu64, id );
  199. # ifndef __ANDROID__
  200. pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, &cs );
  201. # endif
  202. if ( ( fd = open( path, O_RDONLY ) ) > 0) {
  203. int len = read( fd, buf, 255 );
  204. if( len > 0 )
  205. {
  206. buf[len] = 0;
  207. if( len > 1 && buf[len-1] == '\n' )
  208. {
  209. buf[len-1] = 0;
  210. }
  211. }
  212. close( fd );
  213. }
  214. # ifndef __ANDROID__
  215. pthread_setcancelstate( cs, 0 );
  216. # endif
  217. return buf;
  218. # endif
  219. #endif
  220. sprintf( buf, "%" PRIu64, id );
  221. return buf;
  222. }
  223. }
  224. #ifdef __cplusplus
  225. extern "C" {
  226. #endif
  227. TRACY_API void ___tracy_set_thread_name( const char* name ) { tracy::SetThreadName( name ); }
  228. #ifdef __cplusplus
  229. }
  230. #endif