TestThreadCallstack.cpp 13 KB

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