Thread.cpp 3.6 KB

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