Thread.cpp 3.7 KB

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