ThreadHive.cpp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. // Copyright (C) 2009-2016, 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/ThreadHive.h>
  7. #include <chrono>
  8. #include <thread>
  9. namespace anki
  10. {
  11. class ThreadHiveTestContext
  12. {
  13. public:
  14. ThreadHiveTestContext()
  15. {
  16. }
  17. ~ThreadHiveTestContext()
  18. {
  19. }
  20. union
  21. {
  22. Atomic<I32> m_countAtomic;
  23. I32 m_count;
  24. };
  25. };
  26. //==============================================================================
  27. static void decNumber(void* arg, U32, ThreadHive& hive)
  28. {
  29. ThreadHiveTestContext* ctx = static_cast<ThreadHiveTestContext*>(arg);
  30. ctx->m_countAtomic.fetchSub(2);
  31. }
  32. //==============================================================================
  33. static void incNumber(void* arg, U32, ThreadHive& hive)
  34. {
  35. ThreadHiveTestContext* ctx = static_cast<ThreadHiveTestContext*>(arg);
  36. ctx->m_countAtomic.fetchAdd(4);
  37. hive.submitTask(decNumber, arg);
  38. }
  39. //==============================================================================
  40. static void taskToWaitOn(void* arg, U32, ThreadHive& hive)
  41. {
  42. ThreadHiveTestContext* ctx = static_cast<ThreadHiveTestContext*>(arg);
  43. std::this_thread::sleep_for(std::chrono::seconds(1));
  44. ctx->m_count = 10;
  45. std::this_thread::sleep_for(std::chrono::milliseconds(100));
  46. }
  47. //==============================================================================
  48. static void taskToWait(void* arg, U32 threadId, ThreadHive& hive)
  49. {
  50. ThreadHiveTestContext* ctx = static_cast<ThreadHiveTestContext*>(arg);
  51. U prev = ctx->m_countAtomic.fetchAdd(1);
  52. ANKI_TEST_EXPECT_GEQ(prev, 10);
  53. }
  54. //==============================================================================
  55. ANKI_TEST(Util, ThreadHive)
  56. {
  57. const U32 threadCount = 4;
  58. HeapAllocator<U8> alloc(allocAligned, nullptr);
  59. ThreadHive hive(threadCount, alloc);
  60. // Simple test
  61. if(1)
  62. {
  63. ThreadHiveTestContext ctx;
  64. ctx.m_countAtomic.set(0);
  65. const U INITIAL_TASK_COUNT = 100;
  66. for(U i = 0; i < INITIAL_TASK_COUNT; ++i)
  67. {
  68. hive.submitTask(incNumber, &ctx);
  69. }
  70. hive.waitAllTasks();
  71. ANKI_TEST_EXPECT_EQ(ctx.m_countAtomic.get(), INITIAL_TASK_COUNT * 2);
  72. }
  73. // Depedency tests
  74. if(1)
  75. {
  76. ThreadHiveTestContext ctx;
  77. ctx.m_count = 0;
  78. ThreadHiveTask task;
  79. task.m_callback = taskToWaitOn;
  80. task.m_argument = &ctx;
  81. hive.submitTasks(&task, 1);
  82. const U DEP_TASKS = 10;
  83. ThreadHiveTask dtasks[DEP_TASKS];
  84. for(U i = 0; i < DEP_TASKS; ++i)
  85. {
  86. dtasks[i].m_callback = taskToWait;
  87. dtasks[i].m_argument = &ctx;
  88. dtasks[i].m_inDependencies =
  89. WeakArray<ThreadHiveDependencyHandle>(&task.m_outDependency, 1);
  90. }
  91. hive.submitTasks(&dtasks[0], DEP_TASKS);
  92. // Again
  93. ThreadHiveTask dtasks2[DEP_TASKS];
  94. for(U i = 0; i < DEP_TASKS; ++i)
  95. {
  96. dtasks2[i].m_callback = taskToWait;
  97. dtasks2[i].m_argument = &ctx;
  98. dtasks2[i].m_inDependencies = WeakArray<ThreadHiveDependencyHandle>(
  99. &dtasks[i].m_outDependency, 1);
  100. }
  101. hive.submitTasks(&dtasks2[0], DEP_TASKS);
  102. hive.waitAllTasks();
  103. ANKI_TEST_EXPECT_EQ(ctx.m_countAtomic.get(), DEP_TASKS * 2 + 10);
  104. }
  105. // Fuzzy test
  106. if(1)
  107. {
  108. ThreadHiveTestContext ctx;
  109. ctx.m_count = 0;
  110. I number = 0;
  111. ThreadHiveDependencyHandle dep = 0;
  112. const U SUBMISSION_COUNT = 100;
  113. const U TASK_COUNT = 1000;
  114. for(U i = 0; i < SUBMISSION_COUNT; ++i)
  115. {
  116. for(U j = 0; j < TASK_COUNT; ++j)
  117. {
  118. Bool cb = rand() % 2;
  119. number = (cb) ? number + 2 : number - 2;
  120. ThreadHiveTask task;
  121. task.m_callback = (cb) ? incNumber : decNumber;
  122. task.m_argument = &ctx;
  123. if((rand() % 3) == 0 && j > 0)
  124. {
  125. task.m_inDependencies =
  126. WeakArray<ThreadHiveDependencyHandle>(&dep, 1);
  127. }
  128. hive.submitTasks(&task, 1);
  129. if((rand() % 7) == 0)
  130. {
  131. dep = task.m_outDependency;
  132. }
  133. }
  134. dep = 0;
  135. hive.waitAllTasks();
  136. }
  137. ANKI_TEST_EXPECT_EQ(ctx.m_countAtomic.get(), number);
  138. }
  139. }
  140. } // end namespace anki