thread_pool_tests.cpp 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. // This file is part of OpenCV project.
  2. // It is subject to the license terms in the LICENSE file found in the top-level directory
  3. // of this distribution and at http://opencv.org/license.html.
  4. //
  5. // Copyright (C) 2024 Intel Corporation
  6. #include "../test_precomp.hpp"
  7. #include <chrono>
  8. #include <thread>
  9. #include "executor/thread_pool.hpp"
  10. namespace opencv_test
  11. {
  12. using namespace cv::gapi;
  13. TEST(ThreadPool, ScheduleNotBlock)
  14. {
  15. own::Latch latch(1u);
  16. std::atomic<uint32_t> counter{0u};
  17. own::ThreadPool tp(4u);
  18. tp.schedule([&](){
  19. std::this_thread::sleep_for(std::chrono::milliseconds{500u});
  20. counter++;
  21. latch.count_down();
  22. });
  23. EXPECT_EQ(0u, counter);
  24. latch.wait();
  25. EXPECT_EQ(1u, counter);
  26. }
  27. TEST(ThreadPool, MultipleTasks)
  28. {
  29. const uint32_t kNumTasks = 100u;
  30. own::Latch latch(kNumTasks);
  31. std::atomic<uint32_t> completed{0u};
  32. own::ThreadPool tp(4u);
  33. for (uint32_t i = 0; i < kNumTasks; ++i) {
  34. tp.schedule([&]() {
  35. ++completed;
  36. latch.count_down();
  37. });
  38. }
  39. latch.wait();
  40. EXPECT_EQ(kNumTasks, completed.load());
  41. }
  42. struct ExecutionState {
  43. ExecutionState(const uint32_t num_threads,
  44. const uint32_t num_tasks)
  45. : guard(0u),
  46. critical(0u),
  47. limit(num_tasks),
  48. latch(num_threads),
  49. tp(num_threads) {
  50. }
  51. std::atomic<uint32_t> guard;
  52. std::atomic<uint32_t> critical;
  53. const uint32_t limit;
  54. own::Latch latch;
  55. own::ThreadPool tp;
  56. };
  57. static void doRecursive(ExecutionState& state) {
  58. // NB: Protects function to be executed no more than limit number of times
  59. if (state.guard.fetch_add(1u) >= state.limit) {
  60. state.latch.count_down();
  61. return;
  62. }
  63. // NB: This simulates critical section
  64. std::this_thread::sleep_for(std::chrono::milliseconds{50});
  65. ++state.critical;
  66. // NB: Schedule the new one recursively
  67. state.tp.schedule([&](){ doRecursive(state); });
  68. }
  69. TEST(ThreadPool, ScheduleRecursively)
  70. {
  71. const int kNumThreads = 5u;
  72. const uint32_t kNumTasks = 100u;
  73. ExecutionState state(kNumThreads, kNumTasks);
  74. for (uint32_t i = 0; i < kNumThreads; ++i) {
  75. state.tp.schedule([&](){
  76. doRecursive(state);
  77. });
  78. }
  79. state.latch.wait();
  80. EXPECT_EQ(kNumTasks, state.critical.load());
  81. }
  82. TEST(ThreadPool, ExecutionIsParallel)
  83. {
  84. const uint32_t kNumThreads = 4u;
  85. std::atomic<uint32_t> counter{0};
  86. own::Latch latch{kNumThreads};
  87. own::ThreadPool tp(kNumThreads);
  88. auto start = std::chrono::high_resolution_clock::now();
  89. for (uint32_t i = 0; i < kNumThreads; ++i) {
  90. tp.schedule([&]() {
  91. std::this_thread::sleep_for(std::chrono::milliseconds{800u});
  92. ++counter;
  93. latch.count_down();
  94. });
  95. }
  96. latch.wait();
  97. auto end = std::chrono::high_resolution_clock::now();
  98. auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
  99. EXPECT_GE(1000u, elapsed);
  100. EXPECT_EQ(kNumThreads, counter.load());
  101. }
  102. } // namespace opencv_test