Thread.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. // Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <Tests/Framework/Framework.h>
  6. #include "anki/util/Thread.h"
  7. #include "anki/util/StdTypes.h"
  8. #include "anki/util/HighRezTimer.h"
  9. #include "anki/util/ThreadPool.h"
  10. #include <cstring>
  11. namespace anki
  12. {
  13. ANKI_TEST(Util, Thread)
  14. {
  15. static const char* THREAD_NAME = "name";
  16. Thread t(THREAD_NAME);
  17. static const U64 NUMBER = 0xFAFAFAFABABABA;
  18. U64 u = NUMBER;
  19. t.start(&u, [](ThreadCallbackInfo& info) -> Error {
  20. Bool check = true;
  21. // Check name
  22. check = check && (std::strcmp(info.m_threadName, THREAD_NAME) == 0);
  23. // Check user value
  24. U64& num = *reinterpret_cast<U64*>(info.m_userData);
  25. check = check && (num == NUMBER);
  26. // Change number
  27. num = 0xF00;
  28. HighRezTimer::sleep(1.0);
  29. return (check != true) ? Error::FUNCTION_FAILED : Error::NONE;
  30. });
  31. ANKI_TEST_EXPECT_EQ(u, NUMBER); // It should be the old value
  32. Error err = t.join();
  33. ANKI_TEST_EXPECT_EQ(err, 0);
  34. ANKI_TEST_EXPECT_EQ(u, 0xF00);
  35. }
  36. ANKI_TEST(Util, Mutex)
  37. {
  38. Thread t0(nullptr), t1(nullptr);
  39. Mutex mtx;
  40. static const U ITERATIONS = 1000000;
  41. class In
  42. {
  43. public:
  44. I64 m_num = ITERATIONS;
  45. Mutex* m_mtx;
  46. };
  47. In in;
  48. in.m_mtx = &mtx;
  49. t0.start(&in, [](ThreadCallbackInfo& info) -> Error {
  50. In& in = *reinterpret_cast<In*>(info.m_userData);
  51. I64& num = in.m_num;
  52. Mutex& mtx = *in.m_mtx;
  53. for(U i = 0; i < ITERATIONS; i++)
  54. {
  55. mtx.lock();
  56. num += 2;
  57. mtx.unlock();
  58. }
  59. return Error::NONE;
  60. });
  61. t1.start(&in, [](ThreadCallbackInfo& info) -> Error {
  62. In& in = *reinterpret_cast<In*>(info.m_userData);
  63. I64& num = in.m_num;
  64. Mutex& mtx = *in.m_mtx;
  65. for(U i = 0; i < ITERATIONS; i++)
  66. {
  67. mtx.lock();
  68. --num;
  69. mtx.unlock();
  70. }
  71. return Error::NONE;
  72. });
  73. ANKI_TEST_EXPECT_NO_ERR(t0.join());
  74. ANKI_TEST_EXPECT_NO_ERR(t1.join());
  75. ANKI_TEST_EXPECT_EQ(in.m_num, ITERATIONS * 2);
  76. }
  77. /// Struct for our tests
  78. struct TestJobTP : ThreadPoolTask
  79. {
  80. U32 in = 0;
  81. U32 iterations = 0;
  82. Error operator()(U32 /*threadId*/, PtrSize /*threadsCount*/)
  83. {
  84. for(U32 i = 0; i < iterations; i++)
  85. {
  86. ++in;
  87. }
  88. return Error::NONE;
  89. }
  90. };
  91. } // end namespace anki
  92. ANKI_TEST(Util, ThreadPool)
  93. {
  94. const U32 threadsCount = 4;
  95. const U32 repeat = 5;
  96. ThreadPool* tp = new ThreadPool(threadsCount);
  97. TestJobTP jobs[threadsCount];
  98. for(U32 i = 1; i < repeat; i++)
  99. {
  100. U32 iterations = rand() % 100000;
  101. for(U32 j = 0; j < threadsCount; j++)
  102. {
  103. jobs[j].in = i;
  104. jobs[j].iterations = iterations;
  105. tp->assignNewTask(j, &jobs[j]);
  106. }
  107. ANKI_TEST_EXPECT_NO_ERR(tp->waitForAllThreadsToFinish());
  108. for(U32 j = 0; j < threadsCount; j++)
  109. {
  110. ANKI_TEST_EXPECT_EQ(jobs[j].in, i + iterations);
  111. }
  112. }
  113. delete tp;
  114. // Test splitThreadedProblem()
  115. {
  116. const U ITERATIONS = 100000;
  117. for(U it = 0; it < ITERATIONS; ++it)
  118. {
  119. const U32 problemSize = max<U32>(1, rand());
  120. const U32 threadCount = max<U32>(1, rand() % 128);
  121. U32 totalCount = 0;
  122. for(U32 tid = 0; tid < threadCount; ++tid)
  123. {
  124. U32 start, end;
  125. splitThreadedProblem(tid, threadCount, problemSize, start, end);
  126. if(tid == 0)
  127. {
  128. ANKI_TEST_EXPECT_EQ(start, 0);
  129. }
  130. else if(tid == threadCount - 1)
  131. {
  132. ANKI_TEST_EXPECT_EQ(end, problemSize);
  133. }
  134. totalCount += end - start;
  135. }
  136. ANKI_TEST_EXPECT_EQ(totalCount, problemSize);
  137. }
  138. }
  139. }
  140. ANKI_TEST(Util, Barrier)
  141. {
  142. // Simple test
  143. {
  144. Barrier b(2);
  145. Thread t(nullptr);
  146. t.start(&b, [](ThreadCallbackInfo& info) -> Error {
  147. Barrier& b = *reinterpret_cast<Barrier*>(info.m_userData);
  148. b.wait();
  149. return Error::NONE;
  150. });
  151. b.wait();
  152. ANKI_TEST_EXPECT_NO_ERR(t.join());
  153. }
  154. }