threadpool_test.cc 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. /*
  2. *
  3. * Copyright 2019 gRPC authors.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. #include "src/core/lib/iomgr/executor/threadpool.h"
  19. #include "test/core/util/test_config.h"
  20. #define SMALL_THREAD_POOL_SIZE 20
  21. #define LARGE_THREAD_POOL_SIZE 100
  22. #define THREAD_SMALL_ITERATION 100
  23. #define THREAD_LARGE_ITERATION 10000
  24. grpc_core::Mutex mu;
  25. // Simple functor for testing. It will count how many times being called.
  26. class SimpleFunctorForAdd : public grpc_experimental_completion_queue_functor {
  27. public:
  28. friend class SimpleFunctorCheckForAdd;
  29. SimpleFunctorForAdd() : count_(0) {
  30. functor_run = &SimpleFunctorForAdd::Run;
  31. internal_next = this;
  32. internal_success = 0;
  33. }
  34. ~SimpleFunctorForAdd() {}
  35. static void Run(struct grpc_experimental_completion_queue_functor* cb,
  36. int ok) {
  37. auto* callback = static_cast<SimpleFunctorForAdd*>(cb);
  38. grpc_core::MutexLock l(&mu);
  39. callback->count_++;
  40. }
  41. int count() {
  42. grpc_core::MutexLock l(&mu);
  43. return count_;
  44. }
  45. private:
  46. int count_;
  47. };
  48. // Checks the given SimpleFunctorForAdd's count with a given number.
  49. class SimpleFunctorCheckForAdd
  50. : public grpc_experimental_completion_queue_functor {
  51. public:
  52. SimpleFunctorCheckForAdd(
  53. struct grpc_experimental_completion_queue_functor* cb, int ok) {
  54. functor_run = &SimpleFunctorCheckForAdd::Run;
  55. internal_next = cb;
  56. internal_success = ok;
  57. }
  58. ~SimpleFunctorCheckForAdd() {}
  59. static void Run(struct grpc_experimental_completion_queue_functor* cb,
  60. int ok) {
  61. auto* callback = static_cast<SimpleFunctorForAdd*>(cb);
  62. GPR_ASSERT(callback->count_ == ok);
  63. }
  64. };
  65. static void test_add(void) {
  66. gpr_log(GPR_INFO, "test_add");
  67. grpc_core::ThreadPool* pool =
  68. grpc_core::New<grpc_core::ThreadPool>(SMALL_THREAD_POOL_SIZE, "test_add");
  69. SimpleFunctorForAdd* functor = grpc_core::New<SimpleFunctorForAdd>();
  70. for (int i = 0; i < THREAD_SMALL_ITERATION; ++i) {
  71. pool->Add(functor);
  72. }
  73. grpc_core::Delete(pool);
  74. GPR_ASSERT(functor->count() == THREAD_SMALL_ITERATION);
  75. grpc_core::Delete(functor);
  76. gpr_log(GPR_DEBUG, "Done.");
  77. }
  78. // Thread that adds closures to pool
  79. class WorkThread {
  80. public:
  81. WorkThread(grpc_core::ThreadPool* pool, SimpleFunctorForAdd* cb, int num_add)
  82. : num_add_(num_add), cb_(cb), pool_(pool) {
  83. thd_ = grpc_core::Thread(
  84. "thread_pool_test_add_thd",
  85. [](void* th) { static_cast<WorkThread*>(th)->Run(); }, this);
  86. }
  87. ~WorkThread() {}
  88. void Start() { thd_.Start(); }
  89. void Join() { thd_.Join(); }
  90. private:
  91. void Run() {
  92. for (int i = 0; i < num_add_; ++i) {
  93. pool_->Add(cb_);
  94. }
  95. }
  96. int num_add_;
  97. SimpleFunctorForAdd* cb_;
  98. grpc_core::ThreadPool* pool_;
  99. grpc_core::Thread thd_;
  100. };
  101. static void test_multi_add(void) {
  102. gpr_log(GPR_INFO, "test_multi_add");
  103. const int num_work_thds = 10;
  104. grpc_core::ThreadPool* pool = grpc_core::New<grpc_core::ThreadPool>(
  105. LARGE_THREAD_POOL_SIZE, "test_multi_add");
  106. SimpleFunctorForAdd* functor = grpc_core::New<SimpleFunctorForAdd>();
  107. WorkThread** work_thds = static_cast<WorkThread**>(
  108. gpr_zalloc(sizeof(WorkThread*) * num_work_thds));
  109. gpr_log(GPR_DEBUG, "Fork threads for adding...");
  110. for (int i = 0; i < num_work_thds; ++i) {
  111. work_thds[i] =
  112. grpc_core::New<WorkThread>(pool, functor, THREAD_LARGE_ITERATION);
  113. work_thds[i]->Start();
  114. }
  115. // Wait for all threads finish
  116. gpr_log(GPR_DEBUG, "Waiting for all work threads finish...");
  117. for (int i = 0; i < num_work_thds; ++i) {
  118. work_thds[i]->Join();
  119. grpc_core::Delete(work_thds[i]);
  120. }
  121. gpr_free(work_thds);
  122. gpr_log(GPR_DEBUG, "Done.");
  123. gpr_log(GPR_DEBUG, "Waiting for all closures finish...");
  124. // Destructor of thread pool will wait for all closures to finish
  125. grpc_core::Delete(pool);
  126. GPR_ASSERT(functor->count() == THREAD_LARGE_ITERATION * num_work_thds);
  127. grpc_core::Delete(functor);
  128. gpr_log(GPR_DEBUG, "Done.");
  129. }
  130. static void test_one_thread_FIFO(void) {
  131. gpr_log(GPR_INFO, "test_one_thread_FIFO");
  132. grpc_core::ThreadPool* pool =
  133. grpc_core::New<grpc_core::ThreadPool>(1, "test_one_thread_FIFO");
  134. SimpleFunctorForAdd* functor = grpc_core::New<SimpleFunctorForAdd>();
  135. SimpleFunctorCheckForAdd** check_functors =
  136. static_cast<SimpleFunctorCheckForAdd**>(gpr_zalloc(
  137. sizeof(SimpleFunctorCheckForAdd*) * THREAD_SMALL_ITERATION));
  138. for (int i = 0; i < THREAD_SMALL_ITERATION; ++i) {
  139. pool->Add(functor);
  140. check_functors[i] =
  141. grpc_core::New<SimpleFunctorCheckForAdd>(functor, i + 1);
  142. pool->Add(check_functors[i]);
  143. }
  144. // Destructor of pool will wait until all closures finished.
  145. grpc_core::Delete(pool);
  146. grpc_core::Delete(functor);
  147. for (int i = 0; i < THREAD_SMALL_ITERATION; ++i) {
  148. grpc_core::Delete(check_functors[i]);
  149. }
  150. gpr_free(check_functors);
  151. gpr_log(GPR_DEBUG, "Done.");
  152. }
  153. int main(int argc, char** argv) {
  154. grpc::testing::TestEnvironment env(argc, argv);
  155. grpc_init();
  156. test_add();
  157. test_multi_add();
  158. test_one_thread_FIFO();
  159. grpc_shutdown();
  160. return 0;
  161. }