blob: dc3a9f2ac583261640015ea32afb59303104057e [file] [log] [blame]
Craig Tiller26598a32015-03-02 16:16:00 -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
34#ifndef TEST_QPS_CLIENT_H
35#define TEST_QPS_CLIENT_H
36
Craig Tiller88568752015-03-04 10:50:43 -080037#include "test/cpp/qps/histogram.h"
38#include "test/cpp/qps/timer.h"
Nicolas "Pixel" Noble0caebbf2015-04-09 23:08:51 +020039#include "test/cpp/qps/qpstest.grpc.pb.h"
Craig Tiller26598a32015-03-02 16:16:00 -080040
Craig Tillere38ec212015-03-04 11:19:15 -080041#include <condition_variable>
42#include <mutex>
43
Craig Tiller26598a32015-03-02 16:16:00 -080044namespace grpc {
45namespace testing {
46
47class Client {
48 public:
Craig Tiller88568752015-03-04 10:50:43 -080049 explicit Client(const ClientConfig& config) : timer_(new Timer) {
50 for (int i = 0; i < config.client_channels(); i++) {
51 channels_.push_back(ClientChannelInfo(
52 config.server_targets(i % config.server_targets_size()), config));
53 }
54 request_.set_response_type(grpc::testing::PayloadType::COMPRESSABLE);
55 request_.set_response_size(config.payload_size());
56 }
Craig Tiller26598a32015-03-02 16:16:00 -080057 virtual ~Client() {}
Craig Tiller6af9ed02015-03-02 22:42:10 -080058
Craig Tiller88568752015-03-04 10:50:43 -080059 ClientStats Mark() {
60 Histogram latencies;
61 std::vector<Histogram> to_merge(threads_.size());
62 for (size_t i = 0; i < threads_.size(); i++) {
63 threads_[i]->BeginSwap(&to_merge[i]);
64 }
65 std::unique_ptr<Timer> timer(new Timer);
66 timer_.swap(timer);
67 for (size_t i = 0; i < threads_.size(); i++) {
68 threads_[i]->EndSwap();
69 latencies.Merge(&to_merge[i]);
70 }
71
72 auto timer_result = timer->Mark();
73
74 ClientStats stats;
75 latencies.FillProto(stats.mutable_latencies());
76 stats.set_time_elapsed(timer_result.wall);
77 stats.set_time_system(timer_result.system);
78 stats.set_time_user(timer_result.user);
79 return stats;
80 }
81
82 protected:
83 SimpleRequest request_;
84
85 class ClientChannelInfo {
86 public:
Craig Tillera182bf12015-03-04 13:54:39 -080087 ClientChannelInfo(const grpc::string& target, const ClientConfig& config)
Craig Tiller88568752015-03-04 10:50:43 -080088 : channel_(CreateTestChannel(target, config.enable_ssl())),
89 stub_(TestService::NewStub(channel_)) {}
90 ChannelInterface* get_channel() { return channel_.get(); }
91 TestService::Stub* get_stub() { return stub_.get(); }
92
93 private:
94 std::shared_ptr<ChannelInterface> channel_;
95 std::unique_ptr<TestService::Stub> stub_;
96 };
97 std::vector<ClientChannelInfo> channels_;
98
99 void StartThreads(size_t num_threads) {
Craig Tillera182bf12015-03-04 13:54:39 -0800100 for (size_t i = 0; i < num_threads; i++) {
101 threads_.emplace_back(new Thread(this, i));
102 }
Craig Tiller88568752015-03-04 10:50:43 -0800103 }
104
Craig Tillera182bf12015-03-04 13:54:39 -0800105 void EndThreads() { threads_.clear(); }
Craig Tiller88568752015-03-04 10:50:43 -0800106
Craig Tiller8a5a6662015-04-09 11:31:28 -0700107 virtual bool ThreadFunc(Histogram* histogram, size_t thread_idx) = 0;
Craig Tiller88568752015-03-04 10:50:43 -0800108
109 private:
110 class Thread {
111 public:
112 Thread(Client* client, size_t idx)
113 : done_(false),
114 new_(nullptr),
115 impl_([this, idx, client]() {
Craig Tiller5c8737d2015-05-21 11:42:17 -0700116 for (;;) {
117 // run the loop body
118 bool thread_still_ok = client->ThreadFunc(&histogram_, idx);
119 // lock, see if we're done
120 std::lock_guard<std::mutex> g(mu_);
121 if (!thread_still_ok) {
122 gpr_log(GPR_ERROR, "Finishing client thread due to RPC error");
123 done_ = true;
Craig Tiller88568752015-03-04 10:50:43 -0800124 }
Craig Tiller5c8737d2015-05-21 11:42:17 -0700125 if (done_) {
126 return;
127 }
128 // check if we're marking, swap out the histogram if so
129 if (new_) {
130 new_->Swap(&histogram_);
131 new_ = nullptr;
132 cv_.notify_one();
133 }
134 }
135 }) {}
Craig Tiller88568752015-03-04 10:50:43 -0800136
137 ~Thread() {
138 {
139 std::lock_guard<std::mutex> g(mu_);
140 done_ = true;
141 }
142 impl_.join();
143 }
144
145 void BeginSwap(Histogram* n) {
146 std::lock_guard<std::mutex> g(mu_);
147 new_ = n;
148 }
149
150 void EndSwap() {
151 std::unique_lock<std::mutex> g(mu_);
152 cv_.wait(g, [this]() { return new_ == nullptr; });
153 }
154
155 private:
156 Thread(const Thread&);
157 Thread& operator=(const Thread&);
158
159 TestService::Stub* stub_;
160 ClientConfig config_;
161 std::mutex mu_;
162 std::condition_variable cv_;
163 bool done_;
164 Histogram* new_;
165 Histogram histogram_;
166 std::thread impl_;
167 };
168
169 std::vector<std::unique_ptr<Thread>> threads_;
170 std::unique_ptr<Timer> timer_;
Craig Tiller26598a32015-03-02 16:16:00 -0800171};
172
Craig Tiller5c8737d2015-05-21 11:42:17 -0700173std::unique_ptr<Client> CreateSynchronousUnaryClient(const ClientConfig& args);
174std::unique_ptr<Client> CreateSynchronousStreamingClient(
175 const ClientConfig& args);
vjpai46f65232015-03-23 10:10:27 -0700176std::unique_ptr<Client> CreateAsyncUnaryClient(const ClientConfig& args);
177std::unique_ptr<Client> CreateAsyncStreamingClient(const ClientConfig& args);
Craig Tiller26598a32015-03-02 16:16:00 -0800178
179} // namespace testing
180} // namespace grpc
181
182#endif