threadpool_test.cc 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  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. static const int kSmallThreadPoolSize = 20;
  21. static const int kLargeThreadPoolSize = 100;
  22. static const int kThreadSmallIter = 100;
  23. static const int kThreadLargeIter = 10000;
  24. static void test_size_zero(void) {
  25. gpr_log(GPR_INFO, "test_size_zero");
  26. grpc_core::ThreadPool* pool_size_zero = new grpc_core::ThreadPool(0);
  27. GPR_ASSERT(pool_size_zero->pool_capacity() == 1);
  28. delete pool_size_zero;
  29. }
  30. static void test_constructor_option(void) {
  31. gpr_log(GPR_INFO, "test_constructor_option");
  32. // Tests options
  33. grpc_core::Thread::Options options;
  34. options.set_stack_size(192 * 1024); // Random non-default value
  35. grpc_core::ThreadPool* pool =
  36. new grpc_core::ThreadPool(0, "test_constructor_option", options);
  37. GPR_ASSERT(pool->thread_options().stack_size() == options.stack_size());
  38. delete pool;
  39. }
  40. // Simple functor for testing. It will count how many times being called.
  41. class SimpleFunctorForAdd : public grpc_completion_queue_functor {
  42. public:
  43. friend class SimpleFunctorCheckForAdd;
  44. SimpleFunctorForAdd() {
  45. functor_run = &SimpleFunctorForAdd::Run;
  46. inlineable = true;
  47. internal_next = this;
  48. internal_success = 0;
  49. }
  50. ~SimpleFunctorForAdd() {}
  51. static void Run(struct grpc_completion_queue_functor* cb, int /*ok*/) {
  52. auto* callback = static_cast<SimpleFunctorForAdd*>(cb);
  53. callback->count_.fetch_add(1, std::memory_order_relaxed);
  54. }
  55. int count() { return count_.load(std::memory_order_relaxed); }
  56. private:
  57. std::atomic<int> count_{0};
  58. };
  59. static void test_add(void) {
  60. gpr_log(GPR_INFO, "test_add");
  61. grpc_core::ThreadPool* pool =
  62. new grpc_core::ThreadPool(kSmallThreadPoolSize, "test_add");
  63. SimpleFunctorForAdd* functor = new SimpleFunctorForAdd();
  64. for (int i = 0; i < kThreadSmallIter; ++i) {
  65. pool->Add(functor);
  66. }
  67. delete pool;
  68. GPR_ASSERT(functor->count() == kThreadSmallIter);
  69. delete functor;
  70. gpr_log(GPR_DEBUG, "Done.");
  71. }
  72. // Thread that adds closures to pool
  73. class WorkThread {
  74. public:
  75. WorkThread(grpc_core::ThreadPool* pool, SimpleFunctorForAdd* cb, int num_add)
  76. : num_add_(num_add), cb_(cb), pool_(pool) {
  77. thd_ = grpc_core::Thread(
  78. "thread_pool_test_add_thd",
  79. [](void* th) { static_cast<WorkThread*>(th)->Run(); }, this);
  80. }
  81. ~WorkThread() {}
  82. void Start() { thd_.Start(); }
  83. void Join() { thd_.Join(); }
  84. private:
  85. void Run() {
  86. for (int i = 0; i < num_add_; ++i) {
  87. pool_->Add(cb_);
  88. }
  89. }
  90. int num_add_;
  91. SimpleFunctorForAdd* cb_;
  92. grpc_core::ThreadPool* pool_;
  93. grpc_core::Thread thd_;
  94. };
  95. static void test_multi_add(void) {
  96. gpr_log(GPR_INFO, "test_multi_add");
  97. const int num_work_thds = 10;
  98. grpc_core::ThreadPool* pool =
  99. new grpc_core::ThreadPool(kLargeThreadPoolSize, "test_multi_add");
  100. SimpleFunctorForAdd* functor = new SimpleFunctorForAdd();
  101. WorkThread** work_thds = static_cast<WorkThread**>(
  102. gpr_zalloc(sizeof(WorkThread*) * num_work_thds));
  103. gpr_log(GPR_DEBUG, "Fork threads for adding...");
  104. for (int i = 0; i < num_work_thds; ++i) {
  105. work_thds[i] = new WorkThread(pool, functor, kThreadLargeIter);
  106. work_thds[i]->Start();
  107. }
  108. // Wait for all threads finish
  109. gpr_log(GPR_DEBUG, "Waiting for all work threads finish...");
  110. for (int i = 0; i < num_work_thds; ++i) {
  111. work_thds[i]->Join();
  112. delete work_thds[i];
  113. }
  114. gpr_free(work_thds);
  115. gpr_log(GPR_DEBUG, "Done.");
  116. gpr_log(GPR_DEBUG, "Waiting for all closures finish...");
  117. // Destructor of thread pool will wait for all closures to finish
  118. delete pool;
  119. GPR_ASSERT(functor->count() == kThreadLargeIter * num_work_thds);
  120. delete functor;
  121. gpr_log(GPR_DEBUG, "Done.");
  122. }
  123. // Checks the current count with a given number.
  124. class SimpleFunctorCheckForAdd : public grpc_completion_queue_functor {
  125. public:
  126. SimpleFunctorCheckForAdd(int ok, int* count) : count_(count) {
  127. functor_run = &SimpleFunctorCheckForAdd::Run;
  128. inlineable = true;
  129. internal_success = ok;
  130. }
  131. ~SimpleFunctorCheckForAdd() {}
  132. static void Run(struct grpc_completion_queue_functor* cb, int /*ok*/) {
  133. auto* callback = static_cast<SimpleFunctorCheckForAdd*>(cb);
  134. (*callback->count_)++;
  135. GPR_ASSERT(*callback->count_ == callback->internal_success);
  136. }
  137. private:
  138. int* count_;
  139. };
  140. static void test_one_thread_FIFO(void) {
  141. gpr_log(GPR_INFO, "test_one_thread_FIFO");
  142. int counter = 0;
  143. grpc_core::ThreadPool* pool =
  144. new grpc_core::ThreadPool(1, "test_one_thread_FIFO");
  145. SimpleFunctorCheckForAdd** check_functors =
  146. static_cast<SimpleFunctorCheckForAdd**>(
  147. gpr_zalloc(sizeof(SimpleFunctorCheckForAdd*) * kThreadSmallIter));
  148. for (int i = 0; i < kThreadSmallIter; ++i) {
  149. check_functors[i] = new SimpleFunctorCheckForAdd(i + 1, &counter);
  150. pool->Add(check_functors[i]);
  151. }
  152. // Destructor of pool will wait until all closures finished.
  153. delete pool;
  154. for (int i = 0; i < kThreadSmallIter; ++i) {
  155. delete check_functors[i];
  156. }
  157. gpr_free(check_functors);
  158. gpr_log(GPR_DEBUG, "Done.");
  159. }
  160. int main(int argc, char** argv) {
  161. grpc::testing::TestEnvironment env(argc, argv);
  162. grpc_init();
  163. test_size_zero();
  164. test_constructor_option();
  165. test_add();
  166. test_multi_add();
  167. test_one_thread_FIFO();
  168. grpc_shutdown();
  169. return 0;
  170. }