TestThreadCallstack.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Copyright (c) Electronic Arts Inc. All rights reserved.
  3. ///////////////////////////////////////////////////////////////////////////////
  4. #include "TestThread.h"
  5. #include <EATest/EATest.h>
  6. #include <eathread/eathread.h>
  7. #include <eathread/eathread_callstack.h>
  8. #include <eathread/eathread_callstack_context.h>
  9. #include <EASTL/fixed_vector.h>
  10. #include <EASTL/fixed_string.h>
  11. #include <EATest/EATest.h>
  12. #include <EAStdC/EAStopwatch.h>
  13. #include <EAStdC/EASprintf.h>
  14. #include <EASTL/set.h>
  15. #include <eathread/eathread_thread.h>
  16. #include <eathread/eathread_sync.h>
  17. #include <eathread/eathread_semaphore.h>
  18. #ifdef EA_PLATFORM_MICROSOFT
  19. EA_DISABLE_ALL_VC_WARNINGS()
  20. #include <Windows.h>
  21. EA_RESTORE_ALL_VC_WARNINGS()
  22. #endif
  23. struct CallstackTestInfo
  24. {
  25. eastl::fixed_vector<void*, 32> mAddressSet;
  26. };
  27. struct CallstackTestThreadContext
  28. {
  29. CallstackTestInfo* mCallstackTestInfo;
  30. int* mnErrorCount;
  31. EA::Thread::CallstackContext mCallstackContext;
  32. EA::Thread::Semaphore mThreadControlSema;
  33. EA::Thread::Semaphore mTestStartSema;
  34. };
  35. #define EACALLSTACK_TEST_FUNCTION_LINKAGE
  36. EA_NO_INLINE void TestCallstack01(CallstackTestInfo& callstackInfo, int& nErrorCount);
  37. EA_NO_INLINE void TestCallstack02(CallstackTestInfo& callstackInfo, int& nErrorCount);
  38. EA_NO_INLINE void TestCallstack03(CallstackTestInfo& callstackInfo, int& nErrorCount);
  39. EA_NO_INLINE void TestCallstack04(CallstackTestInfo& callstackInfo, int& nErrorCount);
  40. EA_NO_INLINE void TestCallstackWithContext02(CallstackTestThreadContext* context);
  41. EA_NO_INLINE void TestCallstackWithContext01(CallstackTestThreadContext* context);
  42. EA_NO_INLINE intptr_t TestCallstackContextThreadFunc(void* context);
  43. static void VerifyCallstack(CallstackTestInfo& callstackInfo, EA::Thread::CallstackContext* context, int& nErrorCount)
  44. {
  45. // We don't do a rigorous per entry ordered match because we've found that
  46. // compiler optimizations get in the way of testing that reliably.
  47. void* addressArray[24] = {};
  48. size_t addressCount = EA::Thread::GetCallstack(addressArray, EAArrayCount(addressArray), context);
  49. eastl_size_t matchCount = 0;
  50. for(eastl_size_t i = 0, iEnd = callstackInfo.mAddressSet.size(); i != iEnd; i++)
  51. {
  52. void* p = callstackInfo.mAddressSet[i];
  53. size_t j;
  54. for(j = 0; j < addressCount; j++)
  55. {
  56. if(abs((int)((intptr_t)addressArray[j] - (intptr_t)p)) < 512)
  57. {
  58. matchCount++;
  59. break;
  60. }
  61. }
  62. }
  63. if(matchCount != callstackInfo.mAddressSet.size())
  64. {
  65. eastl::fixed_string<char, 256> sExpectedCallstack;
  66. eastl::fixed_string<char, 256> sReportedCallstack;
  67. for(eastl_size_t i = 0; i < callstackInfo.mAddressSet.size(); i++)
  68. sExpectedCallstack.append_sprintf("%p ", callstackInfo.mAddressSet[i]);
  69. for(size_t i = 0; i < addressCount; i++)
  70. sReportedCallstack.append_sprintf("%p ", addressArray[i]);
  71. EATEST_VERIFY_F(matchCount == callstackInfo.mAddressSet.size(), "VerifyCallstack failure. Each member from the expected callstack should be present (+/- 512 bytes) in the reported callstack.\n Expected callstack %s\n Reported callstack %s", sExpectedCallstack.c_str(), sReportedCallstack.c_str());
  72. }
  73. EA::UnitTest::NonInlinableFunction();
  74. }
  75. EA_DISABLE_VC_WARNING(4740); // flow in or out of inline asm code suppresses global optimization
  76. EA_NO_INLINE EACALLSTACK_TEST_FUNCTION_LINKAGE void TestCallstackWithContext02(CallstackTestThreadContext* context)
  77. {
  78. int nErrorCount = 0;
  79. EA::UnitTest::NonInlinableFunction();
  80. EATEST_VERIFY(EA::Thread::GetCallstackContextSysThreadId(context->mCallstackContext, (intptr_t)EA::Thread::GetSysThreadId()));
  81. context->mnErrorCount += nErrorCount;
  82. context->mTestStartSema.Post();
  83. context->mThreadControlSema.Wait();
  84. }
  85. EA_NO_INLINE EACALLSTACK_TEST_FUNCTION_LINKAGE void TestCallstackWithContext01(CallstackTestThreadContext* context)
  86. {
  87. void* pAddress;
  88. EA::UnitTest::NonInlinableFunction();
  89. EAGetInstructionPointer(pAddress);
  90. context->mCallstackTestInfo->mAddressSet.push_back(pAddress);
  91. // calling out function through a conditionally set functor to help with optimizations from inlining this code
  92. TestCallstackWithContext02(context);
  93. }
  94. EA_NO_INLINE intptr_t TestCallstackContextThreadFunc(void* context)
  95. {
  96. CallstackTestThreadContext* threadContext = (CallstackTestThreadContext*)context;
  97. threadContext->mThreadControlSema.Wait();
  98. void* pAddress;
  99. EAGetInstructionPointer(pAddress);
  100. threadContext->mCallstackTestInfo->mAddressSet.push_back(pAddress);
  101. EA::UnitTest::NonInlinableFunction();
  102. TestCallstackWithContext01(threadContext);
  103. return 0;
  104. }
  105. EA_NO_INLINE EACALLSTACK_TEST_FUNCTION_LINKAGE void TestCallstack04(CallstackTestInfo& callstackInfo, int& nErrorCount)
  106. {
  107. void* pAddress;
  108. EAGetInstructionPointer(pAddress);
  109. callstackInfo.mAddressSet.push_back(pAddress);
  110. VerifyCallstack(callstackInfo, nullptr, nErrorCount);
  111. EA::UnitTest::NonInlinableFunction();
  112. }
  113. EA_NO_INLINE EACALLSTACK_TEST_FUNCTION_LINKAGE void TestCallstack03(CallstackTestInfo& callstackInfo, int& nErrorCount)
  114. {
  115. void* pAddress;
  116. EAGetInstructionPointer(pAddress);
  117. callstackInfo.mAddressSet.push_back(pAddress);
  118. VerifyCallstack(callstackInfo, nullptr, nErrorCount);
  119. TestCallstack04(callstackInfo, nErrorCount);
  120. EA::UnitTest::NonInlinableFunction();
  121. }
  122. EA_NO_INLINE EACALLSTACK_TEST_FUNCTION_LINKAGE void TestCallstack02(CallstackTestInfo& callstackInfo, int& nErrorCount)
  123. {
  124. void* pAddress;
  125. EAGetInstructionPointer(pAddress);
  126. callstackInfo.mAddressSet.push_back(pAddress);
  127. VerifyCallstack(callstackInfo, nullptr, nErrorCount);
  128. TestCallstack03(callstackInfo, nErrorCount);
  129. EA::UnitTest::NonInlinableFunction();
  130. }
  131. EA_NO_INLINE EACALLSTACK_TEST_FUNCTION_LINKAGE void TestCallstack01(CallstackTestInfo& callstackInfo, int& nErrorCount)
  132. {
  133. void* pAddress;
  134. EAGetInstructionPointer(pAddress);
  135. callstackInfo.mAddressSet.push_back(pAddress);
  136. VerifyCallstack(callstackInfo, nullptr, nErrorCount);
  137. TestCallstack02(callstackInfo, nErrorCount);
  138. EA::UnitTest::NonInlinableFunction();
  139. }
  140. EA_RESTORE_VC_WARNING();
  141. /// EATHREAD_GETCALLSTACK_RELIABLE
  142. ///
  143. /// Defined as 0 or 1
  144. /// Identifies whether we can rely on the results of GetCallstack for the purposes
  145. /// of this unit test.
  146. #if !defined(EATHREAD_GETCALLSTACK_RELIABLE)
  147. #if EATHREAD_GETCALLSTACK_SUPPORTED
  148. #if defined(EA_PLATFORM_WINRT) && defined(EA_PROCESSOR_X86) // WinRT-x86 does not provide usable callstacks so we avoid tracing them on this platform.
  149. #define EATHREAD_GETCALLSTACK_RELIABLE 0
  150. #else
  151. #define EATHREAD_GETCALLSTACK_RELIABLE 1
  152. #endif
  153. #else
  154. #define EATHREAD_GETCALLSTACK_RELIABLE 0
  155. #endif
  156. #endif
  157. static bool IsRoughlyEqualAddress(void* a, void* b)
  158. {
  159. static const uintptr_t kMaxBytesDist = 512;
  160. if ( ((uintptr_t)a -(uintptr_t)b) <= kMaxBytesDist)
  161. {
  162. return true;
  163. }
  164. else if (((uintptr_t)b - (uintptr_t)a) <= kMaxBytesDist)
  165. {
  166. return true;
  167. }
  168. else
  169. {
  170. return false;
  171. }
  172. }
  173. EA_NO_INLINE EACALLSTACK_TEST_FUNCTION_LINKAGE int TestRemoteThreadContextVsCallstack()
  174. {
  175. int nErrorCount(0);
  176. struct CallstackTestThread : public EA::Thread::IRunnable
  177. {
  178. EA::Thread::Thread mThread;
  179. EA::Thread::ThreadParameters mParameters;
  180. EA::Thread::Semaphore mEndSemaphore;
  181. EA::Thread::Semaphore mStartSemaphore;
  182. char mThreadName[16];
  183. uint64_t mCounter;
  184. volatile bool mbShouldRun;
  185. void* mAddressCallstackArray[64];
  186. CallstackTestThread() : mThread(), mParameters(), mEndSemaphore(0), mStartSemaphore(0), mCounter(0), mbShouldRun(true)
  187. {
  188. eastl::fill(eastl::begin(mAddressCallstackArray), eastl::end(mAddressCallstackArray), (void*)nullptr);
  189. }
  190. CallstackTestThread(const CallstackTestThread&) {}
  191. void operator=(const CallstackTestThread&) {}
  192. intptr_t Run(void*)
  193. {
  194. EA::Thread::GetCallstack(mAddressCallstackArray, EAArrayCount(mAddressCallstackArray));
  195. mStartSemaphore.Post();
  196. mEndSemaphore.Wait();
  197. return 0;
  198. }
  199. };
  200. CallstackTestThread remoteThread;
  201. remoteThread.mThread.Begin(&remoteThread, NULL, &remoteThread.mParameters);
  202. // make sure this thread is running
  203. remoteThread.mStartSemaphore.Wait();
  204. // context
  205. void* addressContextArray[64] = {nullptr};
  206. auto threadId = remoteThread.mThread.GetId();
  207. {
  208. #if defined(EA_PLATFORM_WINDOWS) || defined(EA_PLATFORM_XBOXONE)
  209. // suspend the target thread to make sure we get a coherent callstack
  210. bool wasSuspended = (::SuspendThread(threadId) != ((DWORD)-1)); // fail is (DWORD)-1
  211. #endif
  212. EA::Thread::CallstackContext callstackContext;
  213. if (EA::Thread::GetCallstackContext(callstackContext, (intptr_t)threadId))
  214. {
  215. EA::Thread::GetCallstack(addressContextArray, EAArrayCount(addressContextArray), &callstackContext);
  216. }
  217. #if defined(EA_PLATFORM_WINDOWS) || defined(EA_PLATFORM_XBOXONE)
  218. // resume the target thread as needed
  219. if (wasSuspended)
  220. {
  221. ::ResumeThread(threadId);
  222. }
  223. #endif
  224. }
  225. remoteThread.mEndSemaphore.Post();
  226. // make sure every address in the local callstack is in the remote. (remote is a superset of function calls because of suspended in kernel)
  227. for (void* localAddress: remoteThread.mAddressCallstackArray)
  228. {
  229. if (eastl::find_if(eastl::begin(addressContextArray), eastl::end(addressContextArray),
  230. [=](void* a) { return IsRoughlyEqualAddress(a, localAddress); }) == eastl::end(addressContextArray))
  231. {
  232. nErrorCount++;
  233. }
  234. }
  235. remoteThread.mThread.WaitForEnd();
  236. return nErrorCount;
  237. }
  238. int TestThreadCallstack()
  239. {
  240. int nErrorCount(0);
  241. #if EATHREAD_GETCALLSTACK_RELIABLE
  242. {
  243. EA::Thread::InitCallstack();
  244. CallstackTestInfo info;
  245. TestCallstack01(info, nErrorCount);
  246. EA::Thread::ShutdownCallstack();
  247. }
  248. #if defined(EA_PLATFORM_WIN64) || defined(EA_PLATFORM_XBOXONE) || defined(EA_PLATFORM_PS4)
  249. // This test will spawn a thread which will grab its own context and provide it to the main thread
  250. // to use when generating a callstack. We use semaphores to control the created thread to ensure
  251. // the thread is alive while we call GetCallstack() inside of VerifyCallstack()
  252. {
  253. EA::Thread::InitCallstack();
  254. EA::Thread::Thread testThread;
  255. CallstackTestInfo info;
  256. CallstackTestThreadContext threadContext;
  257. threadContext.mCallstackTestInfo = &info;
  258. threadContext.mnErrorCount = &nErrorCount;
  259. testThread.Begin(TestCallstackContextThreadFunc, (void*)&threadContext);
  260. while (testThread.GetStatus() != EA::Thread::Thread::kStatusRunning)
  261. {
  262. EA::Thread::ThreadSleep();
  263. }
  264. // Let the test thread proceed in generating test data
  265. threadContext.mThreadControlSema.Post();
  266. // Wait until the test thread is done entering test data
  267. threadContext.mTestStartSema.Wait();
  268. // Grab the context of the testThread and verify the callstack is what we expect
  269. VerifyCallstack(*threadContext.mCallstackTestInfo, &threadContext.mCallstackContext, nErrorCount);
  270. // Let the test thread finish
  271. threadContext.mThreadControlSema.Post();
  272. testThread.WaitForEnd();
  273. EA::Thread::ShutdownCallstack();
  274. }
  275. {
  276. EA::Thread::InitCallstack();
  277. const int numErrorInRemoteTest = TestRemoteThreadContextVsCallstack();
  278. #if defined(EA_PLATFORM_PS4) // We know that kettle cannot do remote callstacks. This is just to check that it does not crash when attempting to do a remote callstack
  279. EATEST_VERIFY(numErrorInRemoteTest != 0);
  280. #else
  281. nErrorCount += numErrorInRemoteTest;
  282. #endif
  283. EA::Thread::ShutdownCallstack();
  284. }
  285. #endif
  286. #endif
  287. #if defined(EA_PLATFORM_MICROSOFT)
  288. // bool ThreadHandlesAreEqual(intptr_t threadId1, intptr_t threadId2);
  289. // uint32_t GetThreadIdFromThreadHandle(intptr_t threadId);
  290. #endif
  291. // To do: Implement tests for the following for supporting platforms.
  292. // bool GetCallstackContext(CallstackContext& context, intptr_t threadId = 0);
  293. // bool GetCallstackContextSysThreadId(CallstackContext& context, intptr_t sysThreadId = 0);
  294. // void GetCallstackContext(CallstackContext& context, const Context* pContext = NULL);
  295. // size_t GetModuleFromAddress(const void* pAddress, char* pModuleFileName, size_t moduleNameCapacity);
  296. // ModuleHandle GetModuleHandleFromAddress(const void* pAddress);
  297. // EA::Thread::CallstackContext context;
  298. // EA::Thread::GetCallstackContext(context, EA::Thread::GetThreadId());
  299. // EATEST_VERIFY(context.mRIP != 0);
  300. // EATEST_VERIFY(context.mRSP != 0);
  301. // To consider: Test SetStackBase. It's not simple because SetStackBase is a backup for
  302. // when GetStackBase's default functionality doesn't happen to work.
  303. // void SetStackBase(void* pStackBase);
  304. // void SetStackBase(uintptr_t pStackBase){ SetStackBase((void*)pStackBase); }
  305. void* pStackBase = EA::Thread::GetStackBase();
  306. void* pStackLimit = EA::Thread::GetStackLimit();
  307. if(pStackBase && pStackLimit)
  308. {
  309. EATEST_VERIFY((uintptr_t)&nErrorCount < (uintptr_t)pStackBase);
  310. EATEST_VERIFY((uintptr_t)&nErrorCount > (uintptr_t)pStackLimit);
  311. }
  312. return nErrorCount;
  313. }