thread_stress_test.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. /*
  2. *
  3. * Copyright 2015 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 <cinttypes>
  19. #include <mutex>
  20. #include <thread>
  21. #include <gtest/gtest.h>
  22. #include <grpc/grpc.h>
  23. #include <grpc/support/time.h>
  24. #include <grpcpp/channel.h>
  25. #include <grpcpp/client_context.h>
  26. #include <grpcpp/create_channel.h>
  27. #include <grpcpp/impl/codegen/sync.h>
  28. #include <grpcpp/resource_quota.h>
  29. #include <grpcpp/server.h>
  30. #include <grpcpp/server_builder.h>
  31. #include <grpcpp/server_context.h>
  32. #include "src/core/lib/gpr/env.h"
  33. #include "src/core/lib/surface/api_trace.h"
  34. #include "src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h"
  35. #include "src/proto/grpc/testing/echo.grpc.pb.h"
  36. #include "test/core/util/port.h"
  37. #include "test/core/util/test_config.h"
  38. using grpc::testing::EchoRequest;
  39. using grpc::testing::EchoResponse;
  40. const int kNumThreads = 300; // Number of threads
  41. const int kNumAsyncSendThreads = 2;
  42. const int kNumAsyncReceiveThreads = 50;
  43. const int kNumAsyncServerThreads = 50;
  44. const int kNumRpcs = 1000; // Number of RPCs per thread
  45. namespace grpc {
  46. namespace testing {
  47. class TestServiceImpl : public grpc::testing::EchoTestService::Service {
  48. public:
  49. TestServiceImpl() {}
  50. Status Echo(ServerContext* /*context*/, const EchoRequest* request,
  51. EchoResponse* response) override {
  52. response->set_message(request->message());
  53. return Status::OK;
  54. }
  55. };
  56. template <class Service>
  57. class CommonStressTest {
  58. public:
  59. CommonStressTest() : kMaxMessageSize_(8192) {
  60. #if TARGET_OS_IPHONE
  61. // Workaround Apple CFStream bug
  62. gpr_setenv("grpc_cfstream", "0");
  63. #endif
  64. }
  65. virtual ~CommonStressTest() {}
  66. virtual void SetUp() = 0;
  67. virtual void TearDown() = 0;
  68. virtual void ResetStub() = 0;
  69. virtual bool AllowExhaustion() = 0;
  70. grpc::testing::EchoTestService::Stub* GetStub() { return stub_.get(); }
  71. protected:
  72. std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_;
  73. std::unique_ptr<Server> server_;
  74. virtual void SetUpStart(ServerBuilder* builder, Service* service) = 0;
  75. void SetUpStartCommon(ServerBuilder* builder, Service* service) {
  76. builder->RegisterService(service);
  77. builder->SetMaxMessageSize(
  78. kMaxMessageSize_); // For testing max message size.
  79. }
  80. void SetUpEnd(ServerBuilder* builder) { server_ = builder->BuildAndStart(); }
  81. void TearDownStart() { server_->Shutdown(); }
  82. void TearDownEnd() {}
  83. private:
  84. const int kMaxMessageSize_;
  85. };
  86. template <class Service>
  87. class CommonStressTestInsecure : public CommonStressTest<Service> {
  88. public:
  89. void ResetStub() override {
  90. std::shared_ptr<Channel> channel = grpc::CreateChannel(
  91. server_address_.str(), InsecureChannelCredentials());
  92. this->stub_ = grpc::testing::EchoTestService::NewStub(channel);
  93. }
  94. bool AllowExhaustion() override { return false; }
  95. protected:
  96. void SetUpStart(ServerBuilder* builder, Service* service) override {
  97. int port = grpc_pick_unused_port_or_die();
  98. this->server_address_ << "localhost:" << port;
  99. // Setup server
  100. builder->AddListeningPort(server_address_.str(),
  101. InsecureServerCredentials());
  102. this->SetUpStartCommon(builder, service);
  103. }
  104. private:
  105. std::ostringstream server_address_;
  106. };
  107. template <class Service, bool allow_resource_exhaustion>
  108. class CommonStressTestInproc : public CommonStressTest<Service> {
  109. public:
  110. void ResetStub() override {
  111. ChannelArguments args;
  112. std::shared_ptr<Channel> channel = this->server_->InProcessChannel(args);
  113. this->stub_ = grpc::testing::EchoTestService::NewStub(channel);
  114. }
  115. bool AllowExhaustion() override { return allow_resource_exhaustion; }
  116. protected:
  117. void SetUpStart(ServerBuilder* builder, Service* service) override {
  118. this->SetUpStartCommon(builder, service);
  119. }
  120. };
  121. template <class BaseClass>
  122. class CommonStressTestSyncServer : public BaseClass {
  123. public:
  124. void SetUp() override {
  125. ServerBuilder builder;
  126. this->SetUpStart(&builder, &service_);
  127. this->SetUpEnd(&builder);
  128. }
  129. void TearDown() override {
  130. this->TearDownStart();
  131. this->TearDownEnd();
  132. }
  133. private:
  134. TestServiceImpl service_;
  135. };
  136. template <class BaseClass>
  137. class CommonStressTestSyncServerLowThreadCount : public BaseClass {
  138. public:
  139. void SetUp() override {
  140. ServerBuilder builder;
  141. ResourceQuota quota;
  142. this->SetUpStart(&builder, &service_);
  143. quota.SetMaxThreads(4);
  144. builder.SetResourceQuota(quota);
  145. this->SetUpEnd(&builder);
  146. }
  147. void TearDown() override {
  148. this->TearDownStart();
  149. this->TearDownEnd();
  150. }
  151. private:
  152. TestServiceImpl service_;
  153. };
  154. template <class BaseClass>
  155. class CommonStressTestAsyncServer : public BaseClass {
  156. public:
  157. CommonStressTestAsyncServer() : contexts_(kNumAsyncServerThreads * 100) {}
  158. void SetUp() override {
  159. shutting_down_ = false;
  160. ServerBuilder builder;
  161. this->SetUpStart(&builder, &service_);
  162. cq_ = builder.AddCompletionQueue();
  163. this->SetUpEnd(&builder);
  164. for (int i = 0; i < kNumAsyncServerThreads * 100; i++) {
  165. RefreshContext(i);
  166. }
  167. for (int i = 0; i < kNumAsyncServerThreads; i++) {
  168. server_threads_.emplace_back(&CommonStressTestAsyncServer::ProcessRpcs,
  169. this);
  170. }
  171. }
  172. void TearDown() override {
  173. {
  174. grpc::internal::MutexLock l(&mu_);
  175. this->TearDownStart();
  176. shutting_down_ = true;
  177. cq_->Shutdown();
  178. }
  179. for (int i = 0; i < kNumAsyncServerThreads; i++) {
  180. server_threads_[i].join();
  181. }
  182. void* ignored_tag;
  183. bool ignored_ok;
  184. while (cq_->Next(&ignored_tag, &ignored_ok)) {
  185. }
  186. this->TearDownEnd();
  187. }
  188. private:
  189. void ProcessRpcs() {
  190. void* tag;
  191. bool ok;
  192. while (cq_->Next(&tag, &ok)) {
  193. if (ok) {
  194. int i = static_cast<int>(reinterpret_cast<intptr_t>(tag));
  195. switch (contexts_[i].state) {
  196. case Context::READY: {
  197. contexts_[i].state = Context::DONE;
  198. EchoResponse send_response;
  199. send_response.set_message(contexts_[i].recv_request.message());
  200. contexts_[i].response_writer->Finish(send_response, Status::OK,
  201. tag);
  202. break;
  203. }
  204. case Context::DONE:
  205. RefreshContext(i);
  206. break;
  207. }
  208. }
  209. }
  210. }
  211. void RefreshContext(int i) {
  212. grpc::internal::MutexLock l(&mu_);
  213. if (!shutting_down_) {
  214. contexts_[i].state = Context::READY;
  215. contexts_[i].srv_ctx.reset(new ServerContext);
  216. contexts_[i].response_writer.reset(
  217. new grpc::ServerAsyncResponseWriter<EchoResponse>(
  218. contexts_[i].srv_ctx.get()));
  219. service_.RequestEcho(contexts_[i].srv_ctx.get(),
  220. &contexts_[i].recv_request,
  221. contexts_[i].response_writer.get(), cq_.get(),
  222. cq_.get(), reinterpret_cast<void*>(i));
  223. }
  224. }
  225. struct Context {
  226. std::unique_ptr<ServerContext> srv_ctx;
  227. std::unique_ptr<grpc::ServerAsyncResponseWriter<EchoResponse>>
  228. response_writer;
  229. EchoRequest recv_request;
  230. enum { READY, DONE } state;
  231. };
  232. std::vector<Context> contexts_;
  233. grpc::testing::EchoTestService::AsyncService service_;
  234. std::unique_ptr<ServerCompletionQueue> cq_;
  235. bool shutting_down_;
  236. grpc::internal::Mutex mu_;
  237. std::vector<std::thread> server_threads_;
  238. };
  239. template <class Common>
  240. class End2endTest : public ::testing::Test {
  241. protected:
  242. End2endTest() {}
  243. void SetUp() override { common_.SetUp(); }
  244. void TearDown() override { common_.TearDown(); }
  245. void ResetStub() { common_.ResetStub(); }
  246. Common common_;
  247. };
  248. static void SendRpc(grpc::testing::EchoTestService::Stub* stub, int num_rpcs,
  249. bool allow_exhaustion, gpr_atm* errors) {
  250. EchoRequest request;
  251. EchoResponse response;
  252. request.set_message("Hello");
  253. for (int i = 0; i < num_rpcs; ++i) {
  254. ClientContext context;
  255. Status s = stub->Echo(&context, request, &response);
  256. EXPECT_TRUE(s.ok() || (allow_exhaustion &&
  257. s.error_code() == StatusCode::RESOURCE_EXHAUSTED));
  258. if (!s.ok()) {
  259. if (!(allow_exhaustion &&
  260. s.error_code() == StatusCode::RESOURCE_EXHAUSTED)) {
  261. gpr_log(GPR_ERROR, "RPC error: %d: %s", s.error_code(),
  262. s.error_message().c_str());
  263. }
  264. gpr_atm_no_barrier_fetch_add(errors, static_cast<gpr_atm>(1));
  265. } else {
  266. EXPECT_EQ(response.message(), request.message());
  267. }
  268. }
  269. }
  270. typedef ::testing::Types<
  271. CommonStressTestSyncServer<CommonStressTestInsecure<TestServiceImpl>>,
  272. CommonStressTestSyncServer<CommonStressTestInproc<TestServiceImpl, false>>,
  273. CommonStressTestSyncServerLowThreadCount<
  274. CommonStressTestInproc<TestServiceImpl, true>>,
  275. CommonStressTestAsyncServer<
  276. CommonStressTestInsecure<grpc::testing::EchoTestService::AsyncService>>,
  277. CommonStressTestAsyncServer<CommonStressTestInproc<
  278. grpc::testing::EchoTestService::AsyncService, false>>>
  279. CommonTypes;
  280. TYPED_TEST_SUITE(End2endTest, CommonTypes);
  281. TYPED_TEST(End2endTest, ThreadStress) {
  282. this->common_.ResetStub();
  283. std::vector<std::thread> threads;
  284. gpr_atm errors;
  285. gpr_atm_rel_store(&errors, static_cast<gpr_atm>(0));
  286. threads.reserve(kNumThreads);
  287. for (int i = 0; i < kNumThreads; ++i) {
  288. threads.emplace_back(SendRpc, this->common_.GetStub(), kNumRpcs,
  289. this->common_.AllowExhaustion(), &errors);
  290. }
  291. for (int i = 0; i < kNumThreads; ++i) {
  292. threads[i].join();
  293. }
  294. uint64_t error_cnt = static_cast<uint64_t>(gpr_atm_no_barrier_load(&errors));
  295. if (error_cnt != 0) {
  296. gpr_log(GPR_INFO, "RPC error count: %" PRIu64, error_cnt);
  297. }
  298. // If this test allows resource exhaustion, expect that it actually sees some
  299. if (this->common_.AllowExhaustion()) {
  300. EXPECT_GT(error_cnt, static_cast<uint64_t>(0));
  301. }
  302. }
  303. template <class Common>
  304. class AsyncClientEnd2endTest : public ::testing::Test {
  305. protected:
  306. AsyncClientEnd2endTest() : rpcs_outstanding_(0) {}
  307. void SetUp() override { common_.SetUp(); }
  308. void TearDown() override {
  309. void* ignored_tag;
  310. bool ignored_ok;
  311. while (cq_.Next(&ignored_tag, &ignored_ok)) {
  312. }
  313. common_.TearDown();
  314. }
  315. void Wait() {
  316. grpc::internal::MutexLock l(&mu_);
  317. while (rpcs_outstanding_ != 0) {
  318. cv_.Wait(&mu_);
  319. }
  320. cq_.Shutdown();
  321. }
  322. struct AsyncClientCall {
  323. EchoResponse response;
  324. ClientContext context;
  325. Status status;
  326. std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader;
  327. };
  328. void AsyncSendRpc(int num_rpcs) {
  329. for (int i = 0; i < num_rpcs; ++i) {
  330. AsyncClientCall* call = new AsyncClientCall;
  331. EchoRequest request;
  332. request.set_message("Hello: " + std::to_string(i));
  333. call->response_reader =
  334. common_.GetStub()->AsyncEcho(&call->context, request, &cq_);
  335. call->response_reader->Finish(&call->response, &call->status, call);
  336. grpc::internal::MutexLock l(&mu_);
  337. rpcs_outstanding_++;
  338. }
  339. }
  340. void AsyncCompleteRpc() {
  341. while (true) {
  342. void* got_tag;
  343. bool ok = false;
  344. if (!cq_.Next(&got_tag, &ok)) break;
  345. AsyncClientCall* call = static_cast<AsyncClientCall*>(got_tag);
  346. if (!ok) {
  347. gpr_log(GPR_DEBUG, "Error: %d", call->status.error_code());
  348. }
  349. delete call;
  350. bool notify;
  351. {
  352. grpc::internal::MutexLock l(&mu_);
  353. rpcs_outstanding_--;
  354. notify = (rpcs_outstanding_ == 0);
  355. }
  356. if (notify) {
  357. cv_.Signal();
  358. }
  359. }
  360. }
  361. Common common_;
  362. CompletionQueue cq_;
  363. grpc::internal::Mutex mu_;
  364. grpc::internal::CondVar cv_;
  365. int rpcs_outstanding_;
  366. };
  367. TYPED_TEST_SUITE(AsyncClientEnd2endTest, CommonTypes);
  368. TYPED_TEST(AsyncClientEnd2endTest, ThreadStress) {
  369. this->common_.ResetStub();
  370. std::vector<std::thread> send_threads, completion_threads;
  371. for (int i = 0; i < kNumAsyncReceiveThreads; ++i) {
  372. completion_threads.emplace_back(
  373. &AsyncClientEnd2endTest_ThreadStress_Test<TypeParam>::AsyncCompleteRpc,
  374. this);
  375. }
  376. for (int i = 0; i < kNumAsyncSendThreads; ++i) {
  377. send_threads.emplace_back(
  378. &AsyncClientEnd2endTest_ThreadStress_Test<TypeParam>::AsyncSendRpc,
  379. this, kNumRpcs);
  380. }
  381. for (int i = 0; i < kNumAsyncSendThreads; ++i) {
  382. send_threads[i].join();
  383. }
  384. this->Wait();
  385. for (int i = 0; i < kNumAsyncReceiveThreads; ++i) {
  386. completion_threads[i].join();
  387. }
  388. }
  389. } // namespace testing
  390. } // namespace grpc
  391. int main(int argc, char** argv) {
  392. grpc::testing::TestEnvironment env(argc, argv);
  393. ::testing::InitGoogleTest(&argc, argv);
  394. return RUN_ALL_TESTS();
  395. }