blob: 3bd61ea4e8bafe3e48f0bea5e1add7b2b9dc865b [file] [log] [blame]
Craig Tillere4860192015-02-23 17:10:41 -08001/*
2 *
3 * Copyright 2015, Google Inc.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Google Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
yang-g9e2f90c2015-08-21 15:35:03 -070034#include <unistd.h>
Craig Tiller2d0f36c2015-02-23 23:16:17 -080035#include <list>
36#include <thread>
Craig Tillere9a6eb72015-04-09 15:51:41 -070037#include <deque>
Craig Tiller2d0f36c2015-02-23 23:16:17 -080038#include <vector>
yang-g9e2f90c2015-08-21 15:35:03 -070039
40#include <grpc/support/alloc.h>
41#include <grpc/support/log.h>
42#include <grpc/support/host_port.h>
43#include <grpc++/client_context.h>
44#include <grpc++/create_channel.h>
45
46#include "src/core/support/env.h"
Craig Tillere9a6eb72015-04-09 15:51:41 -070047#include "test/core/util/port.h"
Craig Tiller882431f2015-05-19 09:25:37 -070048#include "test/core/util/test_config.h"
yang-g9e2f90c2015-08-21 15:35:03 -070049#include "test/cpp/qps/driver.h"
50#include "test/cpp/qps/histogram.h"
51#include "test/cpp/qps/qps_worker.h"
Craig Tillere4860192015-02-23 17:10:41 -080052
Craig Tiller2d0f36c2015-02-23 23:16:17 -080053using std::list;
54using std::thread;
55using std::unique_ptr;
Craig Tillere9a6eb72015-04-09 15:51:41 -070056using std::deque;
Craig Tiller4ef7a292015-02-23 17:29:01 -080057using std::vector;
Craig Tiller4ef7a292015-02-23 17:29:01 -080058
Craig Tiller6af9ed02015-03-02 22:42:10 -080059namespace grpc {
60namespace testing {
Craig Tillere9a6eb72015-04-09 15:51:41 -070061static deque<string> get_hosts(const string& name) {
Craig Tiller4ef7a292015-02-23 17:29:01 -080062 char* env = gpr_getenv(name.c_str());
Craig Tillere9a6eb72015-04-09 15:51:41 -070063 if (!env) return deque<string>();
Craig Tiller4ef7a292015-02-23 17:29:01 -080064
Craig Tillere9a6eb72015-04-09 15:51:41 -070065 deque<string> out;
Craig Tiller4ef7a292015-02-23 17:29:01 -080066 char* p = env;
67 for (;;) {
Craig Tiller6af9ed02015-03-02 22:42:10 -080068 char* comma = strchr(p, ',');
69 if (comma) {
70 out.emplace_back(p, comma);
71 p = comma + 1;
72 } else {
73 out.emplace_back(p);
74 gpr_free(env);
75 return out;
76 }
Craig Tiller4ef7a292015-02-23 17:29:01 -080077 }
78}
79
Vijay Pai4d06e2e2015-07-31 10:20:42 -070080// Namespace for classes and functions used only in RunScenario
81// Using this rather than local definitions to workaround gcc-4.4 limitations
Vijay Pai90e73692015-08-05 19:15:36 -070082// regarding using templates without linkage
Vijay Pai4d06e2e2015-07-31 10:20:42 -070083namespace runsc {
84
85// ClientContext allocator
86static ClientContext* AllocContext(list<ClientContext>* contexts) {
87 contexts->emplace_back();
88 return &contexts->back();
89}
90
91struct ServerData {
92 unique_ptr<Worker::Stub> stub;
93 unique_ptr<ClientReaderWriter<ServerArgs, ServerStatus>> stream;
94};
95
96struct ClientData {
97 unique_ptr<Worker::Stub> stub;
98 unique_ptr<ClientReaderWriter<ClientArgs, ClientStatus>> stream;
99};
Vijay Pai3ae11042015-08-11 22:43:14 -0700100} // namespace runsc
Vijay Pai4d06e2e2015-07-31 10:20:42 -0700101
David Garcia Quintas08116502015-05-20 17:27:23 -0700102std::unique_ptr<ScenarioResult> RunScenario(
103 const ClientConfig& initial_client_config, size_t num_clients,
104 const ServerConfig& server_config, size_t num_servers, int warmup_seconds,
105 int benchmark_seconds, int spawn_local_worker_count) {
Vijay Pai4d06e2e2015-07-31 10:20:42 -0700106 // ClientContext allocations (all are destroyed at scope exit)
Craig Tiller2d0f36c2015-02-23 23:16:17 -0800107 list<ClientContext> contexts;
Craig Tiller2d0f36c2015-02-23 23:16:17 -0800108
David Garcia Quintas6ba29ba2015-05-19 18:29:35 -0700109 // To be added to the result, containing the final configuration used for
110 // client and config (incluiding host, etc.)
111 ClientConfig result_client_config;
112 ServerConfig result_server_config;
113
Craig Tiller2d0f36c2015-02-23 23:16:17 -0800114 // Get client, server lists
Craig Tiller26598a32015-03-02 16:16:00 -0800115 auto workers = get_hosts("QPS_WORKERS");
Craig Tiller6af9ed02015-03-02 22:42:10 -0800116 ClientConfig client_config = initial_client_config;
Craig Tiller4ef7a292015-02-23 17:29:01 -0800117
Craig Tillere9a6eb72015-04-09 15:51:41 -0700118 // Spawn some local workers if desired
119 vector<unique_ptr<QpsWorker>> local_workers;
120 for (int i = 0; i < abs(spawn_local_worker_count); i++) {
Craig Tiller49c3b012015-05-19 08:18:02 -0700121 // act as if we're a new test -- gets a good rng seed
122 static bool called_init = false;
123 if (!called_init) {
Craig Tiller882431f2015-05-19 09:25:37 -0700124 char args_buf[100];
125 strcpy(args_buf, "some-benchmark");
Craig Tiller5c8737d2015-05-21 11:42:17 -0700126 char* args[] = {args_buf};
Craig Tiller49c3b012015-05-19 08:18:02 -0700127 grpc_test_init(1, args);
128 called_init = true;
129 }
130
Craig Tillere9a6eb72015-04-09 15:51:41 -0700131 int driver_port = grpc_pick_unused_port_or_die();
132 int benchmark_port = grpc_pick_unused_port_or_die();
133 local_workers.emplace_back(new QpsWorker(driver_port, benchmark_port));
134 char addr[256];
135 sprintf(addr, "localhost:%d", driver_port);
136 if (spawn_local_worker_count < 0) {
137 workers.push_front(addr);
138 } else {
139 workers.push_back(addr);
140 }
141 }
142
Craig Tiller10923c22015-03-03 14:24:49 -0800143 // TODO(ctiller): support running multiple configurations, and binpack
144 // client/server pairs
Craig Tiller6af9ed02015-03-02 22:42:10 -0800145 // to available workers
146 GPR_ASSERT(workers.size() >= num_clients + num_servers);
Craig Tiller2d0f36c2015-02-23 23:16:17 -0800147
148 // Trim to just what we need
Craig Tiller6af9ed02015-03-02 22:42:10 -0800149 workers.resize(num_clients + num_servers);
Craig Tiller2d0f36c2015-02-23 23:16:17 -0800150
151 // Start servers
Vijay Pai4d06e2e2015-07-31 10:20:42 -0700152 using runsc::ServerData;
Vijay Pai90e73692015-08-05 19:15:36 -0700153 // servers is array rather than std::vector to avoid gcc-4.4 issues
154 // where class contained in std::vector must have a copy constructor
vjpaib1db8692015-08-11 22:41:02 -0700155 auto* servers = new ServerData[num_servers];
Craig Tiller6af9ed02015-03-02 22:42:10 -0800156 for (size_t i = 0; i < num_servers; i++) {
Vijay Paieed63fa2015-08-05 23:08:34 +0000157 servers[i].stub = std::move(Worker::NewStub(
Craig Tiller68de8e92015-03-05 15:45:46 -0800158 CreateChannel(workers[i], InsecureCredentials(), ChannelArguments())));
Craig Tiller6af9ed02015-03-02 22:42:10 -0800159 ServerArgs args;
David Garcia Quintas6ba29ba2015-05-19 18:29:35 -0700160 result_server_config = server_config;
161 result_server_config.set_host(workers[i]);
Craig Tiller6af9ed02015-03-02 22:42:10 -0800162 *args.mutable_setup() = server_config;
Vijay Pai90e73692015-08-05 19:15:36 -0700163 servers[i].stream =
164 std::move(servers[i].stub->RunServer(runsc::AllocContext(&contexts)));
Vijay Paieed63fa2015-08-05 23:08:34 +0000165 GPR_ASSERT(servers[i].stream->Write(args));
Craig Tiller6af9ed02015-03-02 22:42:10 -0800166 ServerStatus init_status;
Vijay Paieed63fa2015-08-05 23:08:34 +0000167 GPR_ASSERT(servers[i].stream->Read(&init_status));
Craig Tiller6af9ed02015-03-02 22:42:10 -0800168 char* host;
169 char* driver_port;
170 char* cli_target;
171 gpr_split_host_port(workers[i].c_str(), &host, &driver_port);
172 gpr_join_host_port(&cli_target, host, init_status.port());
173 client_config.add_server_targets(cli_target);
174 gpr_free(host);
175 gpr_free(driver_port);
176 gpr_free(cli_target);
Craig Tiller2d0f36c2015-02-23 23:16:17 -0800177 }
178
179 // Start clients
Vijay Pai4d06e2e2015-07-31 10:20:42 -0700180 using runsc::ClientData;
Vijay Pai90e73692015-08-05 19:15:36 -0700181 // clients is array rather than std::vector to avoid gcc-4.4 issues
182 // where class contained in std::vector must have a copy constructor
vjpaib1db8692015-08-11 22:41:02 -0700183 auto* clients = new ClientData[num_clients];
Craig Tiller6af9ed02015-03-02 22:42:10 -0800184 for (size_t i = 0; i < num_clients; i++) {
Vijay Paieed63fa2015-08-05 23:08:34 +0000185 clients[i].stub = std::move(Worker::NewStub(CreateChannel(
Craig Tiller68de8e92015-03-05 15:45:46 -0800186 workers[i + num_servers], InsecureCredentials(), ChannelArguments())));
Craig Tiller6af9ed02015-03-02 22:42:10 -0800187 ClientArgs args;
David Garcia Quintas6ba29ba2015-05-19 18:29:35 -0700188 result_client_config = client_config;
189 result_client_config.set_host(workers[i + num_servers]);
Craig Tiller6af9ed02015-03-02 22:42:10 -0800190 *args.mutable_setup() = client_config;
Vijay Pai90e73692015-08-05 19:15:36 -0700191 clients[i].stream =
192 std::move(clients[i].stub->RunTest(runsc::AllocContext(&contexts)));
Vijay Paieed63fa2015-08-05 23:08:34 +0000193 GPR_ASSERT(clients[i].stream->Write(args));
Craig Tiller6af9ed02015-03-02 22:42:10 -0800194 ClientStatus init_status;
Vijay Paieed63fa2015-08-05 23:08:34 +0000195 GPR_ASSERT(clients[i].stream->Read(&init_status));
Craig Tiller2d0f36c2015-02-23 23:16:17 -0800196 }
197
Craig Tiller6af9ed02015-03-02 22:42:10 -0800198 // Let everything warmup
199 gpr_log(GPR_INFO, "Warming up");
Craig Tiller20b5fe92015-07-06 10:43:50 -0700200 gpr_timespec start = gpr_now(GPR_CLOCK_REALTIME);
Craig Tiller677c50c2015-07-13 10:49:06 -0700201 gpr_sleep_until(
202 gpr_time_add(start, gpr_time_from_seconds(warmup_seconds, GPR_TIMESPAN)));
Craig Tiller6af9ed02015-03-02 22:42:10 -0800203
204 // Start a run
205 gpr_log(GPR_INFO, "Starting");
206 ServerArgs server_mark;
207 server_mark.mutable_mark();
208 ClientArgs client_mark;
209 client_mark.mutable_mark();
Vijay Paieed63fa2015-08-05 23:08:34 +0000210 for (auto server = &servers[0]; server != &servers[num_servers]; server++) {
Vijay Pai82dd80a2015-03-24 10:36:08 -0700211 GPR_ASSERT(server->stream->Write(server_mark));
Craig Tiller6af9ed02015-03-02 22:42:10 -0800212 }
Vijay Paieed63fa2015-08-05 23:08:34 +0000213 for (auto client = &clients[0]; client != &clients[num_clients]; client++) {
Vijay Pai82dd80a2015-03-24 10:36:08 -0700214 GPR_ASSERT(client->stream->Write(client_mark));
Craig Tiller6af9ed02015-03-02 22:42:10 -0800215 }
216 ServerStatus server_status;
217 ClientStatus client_status;
Vijay Paieed63fa2015-08-05 23:08:34 +0000218 for (auto server = &servers[0]; server != &servers[num_servers]; server++) {
Vijay Pai82dd80a2015-03-24 10:36:08 -0700219 GPR_ASSERT(server->stream->Read(&server_status));
Craig Tiller6af9ed02015-03-02 22:42:10 -0800220 }
Vijay Paieed63fa2015-08-05 23:08:34 +0000221 for (auto client = &clients[0]; client != &clients[num_clients]; client++) {
Vijay Pai82dd80a2015-03-24 10:36:08 -0700222 GPR_ASSERT(client->stream->Read(&client_status));
Craig Tiller2d0f36c2015-02-23 23:16:17 -0800223 }
224
Craig Tiller6af9ed02015-03-02 22:42:10 -0800225 // Wait some time
226 gpr_log(GPR_INFO, "Running");
Vijay Pai90e73692015-08-05 19:15:36 -0700227 // Use gpr_sleep_until rather than this_thread::sleep_until to support
228 // compilers that don't work with this_thread
Craig Tiller677c50c2015-07-13 10:49:06 -0700229 gpr_sleep_until(gpr_time_add(
230 start, gpr_time_from_seconds(benchmark_seconds, GPR_TIMESPAN)));
Craig Tiller6af9ed02015-03-02 22:42:10 -0800231
232 // Finish a run
David Garcia Quintas08116502015-05-20 17:27:23 -0700233 std::unique_ptr<ScenarioResult> result(new ScenarioResult);
234 result->client_config = result_client_config;
235 result->server_config = result_server_config;
Craig Tiller6af9ed02015-03-02 22:42:10 -0800236 gpr_log(GPR_INFO, "Finishing");
Vijay Paieed63fa2015-08-05 23:08:34 +0000237 for (auto server = &servers[0]; server != &servers[num_servers]; server++) {
Vijay Pai82dd80a2015-03-24 10:36:08 -0700238 GPR_ASSERT(server->stream->Write(server_mark));
Craig Tiller6af9ed02015-03-02 22:42:10 -0800239 }
Vijay Paieed63fa2015-08-05 23:08:34 +0000240 for (auto client = &clients[0]; client != &clients[num_clients]; client++) {
Vijay Pai82dd80a2015-03-24 10:36:08 -0700241 GPR_ASSERT(client->stream->Write(client_mark));
Craig Tiller6af9ed02015-03-02 22:42:10 -0800242 }
Vijay Paieed63fa2015-08-05 23:08:34 +0000243 for (auto server = &servers[0]; server != &servers[num_servers]; server++) {
Vijay Pai82dd80a2015-03-24 10:36:08 -0700244 GPR_ASSERT(server->stream->Read(&server_status));
Craig Tillerf2825142015-03-03 17:15:36 -0800245 const auto& stats = server_status.stats();
Vijay Pai4d06e2e2015-07-31 10:20:42 -0700246 result->server_resources.emplace_back(
247 stats.time_elapsed(), stats.time_user(), stats.time_system());
Craig Tiller6af9ed02015-03-02 22:42:10 -0800248 }
Vijay Paieed63fa2015-08-05 23:08:34 +0000249 for (auto client = &clients[0]; client != &clients[num_clients]; client++) {
Vijay Pai82dd80a2015-03-24 10:36:08 -0700250 GPR_ASSERT(client->stream->Read(&client_status));
Craig Tillerf2825142015-03-03 17:15:36 -0800251 const auto& stats = client_status.stats();
David Garcia Quintas08116502015-05-20 17:27:23 -0700252 result->latencies.MergeProto(stats.latencies());
Vijay Pai4d06e2e2015-07-31 10:20:42 -0700253 result->client_resources.emplace_back(
254 stats.time_elapsed(), stats.time_user(), stats.time_system());
Craig Tiller6af9ed02015-03-02 22:42:10 -0800255 }
256
Vijay Paieed63fa2015-08-05 23:08:34 +0000257 for (auto client = &clients[0]; client != &clients[num_clients]; client++) {
Vijay Pai82dd80a2015-03-24 10:36:08 -0700258 GPR_ASSERT(client->stream->WritesDone());
Yang Gaoc1a2c312015-06-16 10:59:46 -0700259 GPR_ASSERT(client->stream->Finish().ok());
Craig Tiller6af9ed02015-03-02 22:42:10 -0800260 }
Vijay Paieed63fa2015-08-05 23:08:34 +0000261 for (auto server = &servers[0]; server != &servers[num_servers]; server++) {
Vijay Pai82dd80a2015-03-24 10:36:08 -0700262 GPR_ASSERT(server->stream->WritesDone());
Yang Gaoc1a2c312015-06-16 10:59:46 -0700263 GPR_ASSERT(server->stream->Finish().ok());
Craig Tiller2d0f36c2015-02-23 23:16:17 -0800264 }
vjpaib1db8692015-08-11 22:41:02 -0700265 delete[] clients;
266 delete[] servers;
Craig Tillerf2825142015-03-03 17:15:36 -0800267 return result;
Craig Tiller4ef7a292015-02-23 17:29:01 -0800268}
Craig Tillerf2825142015-03-03 17:15:36 -0800269} // namespace testing
270} // namespace grpc