diff options
Diffstat (limited to 'test/cpp/qps')
-rw-r--r-- | test/cpp/qps/client.cc | 58 | ||||
-rw-r--r-- | test/cpp/qps/driver.cc | 125 | ||||
-rw-r--r-- | test/cpp/qps/driver.h | 4 | ||||
-rw-r--r-- | test/cpp/qps/qps_driver.cc | 34 | ||||
-rw-r--r-- | test/cpp/qps/qpstest.proto | 36 | ||||
-rw-r--r-- | test/cpp/qps/server.cc | 77 | ||||
-rwxr-xr-x | test/cpp/qps/single_run_localhost.sh | 12 | ||||
-rw-r--r-- | test/cpp/qps/timer.cc | 65 | ||||
-rw-r--r-- | test/cpp/qps/timer.h | 55 |
9 files changed, 363 insertions, 103 deletions
diff --git a/test/cpp/qps/client.cc b/test/cpp/qps/client.cc index 213e5d9214..214711e205 100644 --- a/test/cpp/qps/client.cc +++ b/test/cpp/qps/client.cc @@ -54,13 +54,17 @@ #include "test/core/util/grpc_profiler.h" #include "test/cpp/util/create_test_channel.h" #include "test/cpp/qps/qpstest.pb.h" +#include "test/cpp/qps/timer.h" DEFINE_int32(driver_port, 0, "Client driver port."); using grpc::ChannelInterface; using grpc::CreateTestChannel; using grpc::ServerBuilder; +using grpc::ServerContext; +using grpc::Status; using grpc::testing::ClientArgs; +using grpc::testing::ClientConfig; using grpc::testing::ClientResult; using grpc::testing::QpsClient; using grpc::testing::SimpleRequest; @@ -85,21 +89,22 @@ static bool got_sigint = false; static void sigint_handler(int x) { got_sigint = 1; } ClientResult RunTest(const ClientArgs& args) { + const auto& config = args.config(); + gpr_log(GPR_INFO, "QPS test with parameters\n" "enable_ssl = %d\n" "client_channels = %d\n" "client_threads = %d\n" "num_rpcs = %d\n" - "payload_size = %d\n" - "server_target = %s\n\n", - args.enable_ssl(), args.client_channels(), args.client_threads(), args.num_rpcs(), - args.payload_size(), args.server_target().c_str()); + "payload_size = %d\n", + config.enable_ssl(), config.client_channels(), config.client_threads(), config.num_rpcs(), + config.payload_size()); class ClientChannelInfo { public: - explicit ClientChannelInfo(const ClientArgs& args) - : channel_(CreateTestChannel(args.server_target(), args.enable_ssl())), + explicit ClientChannelInfo(const grpc::string& target, const ClientConfig& config) + : channel_(CreateTestChannel(target, config.enable_ssl())), stub_(TestService::NewStub(channel_)) {} ChannelInterface *get_channel() { return channel_.get(); } TestService::Stub *get_stub() { return stub_.get(); } @@ -110,33 +115,33 @@ ClientResult RunTest(const ClientArgs& args) { }; std::vector<ClientChannelInfo> channels; - for (int i = 0; i < args.client_channels(); i++) { - channels.push_back(ClientChannelInfo(args)); + for (int i = 0; i < config.client_channels(); i++) { + channels.push_back(ClientChannelInfo(args.server_targets(i % args.server_targets_size()), config)); } std::vector<std::thread> threads; // Will add threads when ready to execute - std::vector< ::gpr_histogram *> thread_stats(args.client_threads()); + std::vector< ::gpr_histogram *> thread_stats(config.client_threads()); grpc::ClientContext context_stats_begin; grpc_profiler_start("qps_client.prof"); - gpr_timespec start = gpr_now(); + Timer timer; - for (int i = 0; i < args.client_threads(); i++) { + for (int i = 0; i < config.client_threads(); i++) { gpr_histogram *hist = gpr_histogram_create(0.01, 60e9); GPR_ASSERT(hist != NULL); thread_stats[i] = hist; threads.push_back( - std::thread([hist, args, &channels](int channel_num) { + std::thread([hist, config, &channels](int channel_num) { SimpleRequest request; SimpleResponse response; request.set_response_type( grpc::testing::PayloadType::COMPRESSABLE); - request.set_response_size(args.payload_size()); + request.set_response_size(config.payload_size()); - for (int j = 0; j < args.num_rpcs(); j++) { + for (int j = 0; j < config.num_rpcs(); j++) { TestService::Stub *stub = channels[channel_num].get_stub(); double start = now(); @@ -149,29 +154,29 @@ ClientResult RunTest(const ClientArgs& args) { (response.payload().type() == grpc::testing::PayloadType::COMPRESSABLE) && (response.payload().body().length() == - static_cast<size_t>(args.payload_size()))); + static_cast<size_t>(config.payload_size()))); // Now do runtime round-robin assignment of the next // channel number - channel_num += args.client_threads(); - channel_num %= args.client_channels(); + channel_num += config.client_threads(); + channel_num %= config.client_channels(); } }, - i % args.client_channels())); + i % config.client_channels())); } for (auto &t : threads) { t.join(); } - gpr_timespec stop = gpr_now(); + auto timer_result = timer.Mark(); grpc_profiler_stop(); gpr_histogram *hist = gpr_histogram_create(0.01, 60e9); GPR_ASSERT(hist != NULL); - for (int i = 0; i < args.client_threads(); i++) { + for (int i = 0; i < config.client_threads(); i++) { gpr_histogram *h = thread_stats[i]; gpr_log(GPR_INFO, "latency at thread %d (50/90/95/99/99.9): %f/%f/%f/%f/%f", i, gpr_histogram_percentile(h, 50), gpr_histogram_percentile(h, 90), @@ -187,17 +192,22 @@ ClientResult RunTest(const ClientArgs& args) { latencies->set_l_90(gpr_histogram_percentile(hist, 90)); latencies->set_l_99(gpr_histogram_percentile(hist, 99)); latencies->set_l_999(gpr_histogram_percentile(hist, 99.9)); - gpr_timespec elapsed = gpr_time_sub(stop, start); - result.set_num_rpcs(args.client_threads() * args.num_rpcs()); - result.set_time_elapsed(elapsed.tv_sec + 1e-9 * elapsed.tv_nsec); + result.set_num_rpcs(config.client_threads() * config.num_rpcs()); + result.set_time_elapsed(timer_result.wall); + result.set_time_system(timer_result.system); + result.set_time_user(timer_result.user); gpr_histogram_destroy(hist); return result; } -class ClientImpl : public QpsClient::Service { +class ClientImpl final : public QpsClient::Service { public: + Status RunTest(ServerContext* ctx, const ClientArgs* args, ClientResult* result) override { + *result = ::RunTest(*args); + return Status::OK; + } private: std::mutex client_mu_; diff --git a/test/cpp/qps/driver.cc b/test/cpp/qps/driver.cc index e7fc46b9e8..098860610c 100644 --- a/test/cpp/qps/driver.cc +++ b/test/cpp/qps/driver.cc @@ -35,9 +35,33 @@ #include "src/core/support/env.h" #include <grpc/support/alloc.h> #include <grpc/support/log.h> +#include <grpc/support/host_port.h> +#include <grpc++/channel_arguments.h> +#include <grpc++/client_context.h> +#include <grpc++/create_channel.h> +#include <grpc++/stream.h> +#include <list> +#include <thread> +#include <vector> +using std::list; +using std::thread; +using std::unique_ptr; using std::vector; using grpc::string; +using grpc::ChannelArguments; +using grpc::ClientContext; +using grpc::ClientReaderWriter; +using grpc::CreateChannelDeprecated; +using grpc::Status; +using grpc::testing::ClientArgs; +using grpc::testing::ClientConfig; +using grpc::testing::ClientResult; +using grpc::testing::QpsClient; +using grpc::testing::QpsServer; +using grpc::testing::ServerArgs; +using grpc::testing::ServerConfig; +using grpc::testing::ServerStatus; static vector<string> get_hosts(const string& name) { char* env = gpr_getenv(name.c_str()); @@ -58,12 +82,107 @@ static vector<string> get_hosts(const string& name) { } } -void RunScenario(const grpc::testing::ClientArgs& client_args, size_t num_clients, - const grpc::testing::ServerArgs& server_args, - size_t num_servers) { +void RunScenario(const ClientConfig& client_config, size_t num_clients, + const ServerConfig& server_config, size_t num_servers) { + // ClientContext allocator (all are destroyed at scope exit) + list<ClientContext> contexts; + auto alloc_context = [&contexts]() { + contexts.emplace_back(); + return &contexts.back(); + }; + + // Get client, server lists auto clients = get_hosts("QPS_CLIENTS"); auto servers = get_hosts("QPS_SERVERS"); GPR_ASSERT(clients.size() >= num_clients); GPR_ASSERT(servers.size() >= num_servers); + + // Trim to just what we need + clients.resize(num_clients); + servers.resize(num_servers); + + // Start servers + vector<unique_ptr<QpsServer::Stub>> server_stubs; + vector<unique_ptr<ClientReaderWriter<ServerArgs, ServerStatus>>> server_streams; + vector<string> server_targets; + for (const auto& target : servers) { + server_stubs.push_back(QpsServer::NewStub(CreateChannelDeprecated(target, ChannelArguments()))); + auto* stub = server_stubs.back().get(); + ServerArgs args; + *args.mutable_config() = server_config; + server_streams.push_back(stub->RunServer(alloc_context())); + auto* stream = server_streams.back().get(); + if (!stream->Write(args)) { + gpr_log(GPR_ERROR, "Failed starting server"); + return; + } + ServerStatus init_status; + if (!stream->Read(&init_status)) { + gpr_log(GPR_ERROR, "Failed starting server"); + return; + } + char* host; + char* driver_port; + char* cli_target; + gpr_split_host_port(target.c_str(), &host, &driver_port); + gpr_join_host_port(&cli_target, host, init_status.port()); + server_targets.push_back(cli_target); + gpr_free(host); + gpr_free(driver_port); + gpr_free(cli_target); + } + + // Start clients + class Client { + public: + Client(ClientContext* ctx, const string& target, const ClientArgs& args) + : thread_([ctx, target, args, this]() { + auto stub = QpsClient::NewStub(CreateChannelDeprecated(target, ChannelArguments())); + status_ = stub->RunTest(ctx, args, &result_); + }) {} + + ~Client() { join(); } + + void join() { if (!joined_) { thread_.join(); joined_ = true; } } + + const Status& status() const { return status_; } + const ClientResult& result() const { return result_; } + + private: + bool joined_ = false; + Status status_; + ClientResult result_; + thread thread_; + }; + list<Client> running_clients; + size_t svr_idx = 0; + for (const auto& target : clients) { + ClientArgs args; + *args.mutable_config() = client_config; + for (size_t i = 0; i < num_servers; i++) { + args.add_server_targets(server_targets[svr_idx]); + svr_idx = (svr_idx + 1) % num_servers; + } + + running_clients.emplace_back(alloc_context(), target, args); + } + + // Finish clients + for (auto& client : running_clients) { + client.join(); + if (!client.status().IsOk()) { + gpr_log(GPR_ERROR, "Client failed"); + return; + } + } + + // Finish servers + for (auto& stream : server_streams) { + ServerStatus final_status; + ServerStatus dummy; + if (!stream->WritesDone() || !stream->Read(&final_status) || stream->Read(&dummy) || !stream->Finish().IsOk()) { + gpr_log(GPR_ERROR, "Server protocol error"); + } + } } diff --git a/test/cpp/qps/driver.h b/test/cpp/qps/driver.h index 615e5b1b17..8ac9d2f0a3 100644 --- a/test/cpp/qps/driver.h +++ b/test/cpp/qps/driver.h @@ -36,7 +36,7 @@ #include "test/cpp/qps/qpstest.pb.h" -void RunScenario(const grpc::testing::ClientArgs& client_args, size_t num_clients, - const grpc::testing::ServerArgs& server_args, size_t num_servers); +void RunScenario(const grpc::testing::ClientConfig& client_config, size_t num_clients, + const grpc::testing::ServerConfig& server_config, size_t num_servers); #endif diff --git a/test/cpp/qps/qps_driver.cc b/test/cpp/qps/qps_driver.cc index e7dda8e8ee..88b9d373a1 100644 --- a/test/cpp/qps/qps_driver.cc +++ b/test/cpp/qps/qps_driver.cc @@ -35,11 +35,23 @@ #include "test/cpp/qps/driver.h" -DEFINE_int32(num_clients, 1, "number of client binaries"); -DEFINE_int32(num_servers, 1, "number of server binaries"); +DEFINE_int32(num_clients, 1, "Number of client binaries"); +DEFINE_int32(num_servers, 1, "Number of server binaries"); -using grpc::testing::ClientArgs; -using grpc::testing::ServerArgs; +// Common config +DEFINE_bool(enable_ssl, false, "Use SSL"); + +// Server config +DEFINE_int32(server_threads, 1, "Number of server threads"); + +// Client config +DEFINE_int32(client_threads, 1, "Number of client threads"); +DEFINE_int32(client_channels, 1, "Number of client channels"); +DEFINE_int32(num_rpcs, 10000, "Number of rpcs per client thread"); +DEFINE_int32(payload_size, 1, "Payload size"); + +using grpc::testing::ClientConfig; +using grpc::testing::ServerConfig; // In some distros, gflags is in the namespace google, and in some others, // in gflags. This hack is enabling us to find both. @@ -52,10 +64,18 @@ int main(int argc, char **argv) { grpc_init(); ParseCommandLineFlags(&argc, &argv, true); - ClientArgs client_args; - ServerArgs server_args; + ClientConfig client_config; + client_config.set_enable_ssl(FLAGS_enable_ssl); + client_config.set_client_threads(FLAGS_client_threads); + client_config.set_client_channels(FLAGS_client_channels); + client_config.set_num_rpcs(FLAGS_num_rpcs); + client_config.set_payload_size(FLAGS_payload_size); + + ServerConfig server_config; + server_config.set_threads(FLAGS_server_threads); + server_config.set_enable_ssl(FLAGS_enable_ssl); - RunScenario(client_args, FLAGS_num_clients, server_args, FLAGS_num_servers); + RunScenario(client_config, FLAGS_num_clients, server_config, FLAGS_num_servers); grpc_shutdown(); return 0; diff --git a/test/cpp/qps/qpstest.proto b/test/cpp/qps/qpstest.proto index fc58960017..11b7c882a6 100644 --- a/test/cpp/qps/qpstest.proto +++ b/test/cpp/qps/qpstest.proto @@ -51,17 +51,14 @@ message StatsRequest { } message ServerStats { - // wall clock time for timestamp - required double time_now = 1; + // wall clock time + required double time_elapsed = 1; // user time used by the server process and threads required double time_user = 2; // server time used by the server process and all threads required double time_system = 3; - - // RPC count so far - optional int32 num_rpcs = 4; } message Payload { @@ -78,10 +75,9 @@ message Latencies { required double l_999 = 4; } -message ClientArgs { - required string server_target = 1; - required bool enable_ssl = 3; - required int32 client_threads = 4; +message ClientConfig { + required bool enable_ssl = 1; + required int32 client_threads = 2; // We have a configurable number of channels for sending RPCs. // RPCs are sent round-robin on the available channels by the // various threads. Interesting cases are 1 global channel or @@ -90,9 +86,14 @@ message ClientArgs { // rather than just at initialization time in order to also measure the // impact of cache thrashing caused by channel changes. This is an issue // if you are not in one of the above "interesting cases" - required int32 client_channels = 5; - required int32 num_rpcs = 6; - required int32 payload_size = 7; + required int32 client_channels = 3; + required int32 num_rpcs = 4; + required int32 payload_size = 5; +} + +message ClientArgs { + repeated string server_targets = 1; + required ClientConfig config = 2; } message ClientResult { @@ -103,12 +104,18 @@ message ClientResult { required double time_system = 5; } -message ServerArgs { +message ServerConfig { required int32 threads = 1; + required bool enable_ssl = 2; +} + +message ServerArgs { + required ServerConfig config = 1; } message ServerStatus { optional ServerStats stats = 1; + required int32 port = 2; } message SimpleRequest { @@ -168,9 +175,6 @@ message StreamingOutputCallResponse { } service TestService { - // Collect stats from server, ignore request content - rpc CollectServerStats(StatsRequest) returns (ServerStats); - // One request followed by one response. // The server returns the client payload as-is. rpc UnaryCall(SimpleRequest) returns (SimpleResponse); diff --git a/test/cpp/qps/server.cc b/test/cpp/qps/server.cc index a5edb05493..89fdfeb0cb 100644 --- a/test/cpp/qps/server.cc +++ b/test/cpp/qps/server.cc @@ -31,8 +31,6 @@ * */ -#include <sys/time.h> -#include <sys/resource.h> #include <sys/signal.h> #include <thread> @@ -48,6 +46,7 @@ #include "src/cpp/server/thread_pool.h" #include "test/core/util/grpc_profiler.h" #include "test/cpp/qps/qpstest.pb.h" +#include "test/cpp/qps/timer.h" #include <grpc/grpc.h> #include <grpc/support/log.h> @@ -84,10 +83,6 @@ static bool got_sigint = false; static void sigint_handler(int x) { got_sigint = 1; } -static double time_double(struct timeval* tv) { - return tv->tv_sec + 1e-6 * tv->tv_usec; -} - static bool SetPayload(PayloadType type, int size, Payload* payload) { PayloadType response_type = type; // TODO(yangg): Support UNCOMPRESSABLE payload. @@ -104,19 +99,8 @@ namespace { class TestServiceImpl final : public TestService::Service { public: - Status CollectServerStats(ServerContext* context, const StatsRequest*, - ServerStats* response) { - struct rusage usage; - struct timeval tv; - gettimeofday(&tv, NULL); - getrusage(RUSAGE_SELF, &usage); - response->set_time_now(time_double(&tv)); - response->set_time_user(time_double(&usage.ru_utime)); - response->set_time_system(time_double(&usage.ru_stime)); - return Status::OK; - } Status UnaryCall(ServerContext* context, const SimpleRequest* request, - SimpleResponse* response) { + SimpleResponse* response) override { if (request->has_response_size() && request->response_size() > 0) { if (!SetPayload(request->response_type(), request->response_size(), response->mutable_payload())) { @@ -133,48 +117,47 @@ class ServerImpl : public QpsServer::Service { public: Status RunServer(ServerContext* ctx, ServerReaderWriter<ServerStatus, ServerArgs>* stream) { ServerArgs args; - std::unique_ptr<ServerStats> last_stats; if (!stream->Read(&args)) return Status::OK; - bool done = false; - while (!done) { - std::lock_guard<std::mutex> lock(server_mu_); + std::lock_guard<std::mutex> lock(server_mu_); - char* server_address = NULL; - gpr_join_host_port(&server_address, "::", FLAGS_port); + char* server_address = NULL; + gpr_join_host_port(&server_address, "::", FLAGS_port); - TestServiceImpl service; + TestServiceImpl service; - ServerBuilder builder; - builder.AddPort(server_address); - builder.RegisterService(&service); + ServerBuilder builder; + builder.AddPort(server_address); + builder.RegisterService(&service); - gpr_free(server_address); + std::unique_ptr<ThreadPool> pool(new ThreadPool(args.config().threads())); + builder.SetThreadPool(pool.get()); - std::unique_ptr<ThreadPool> pool(new ThreadPool(args.threads())); - builder.SetThreadPool(pool.get()); + auto server = builder.BuildAndStart(); + gpr_log(GPR_INFO, "Server listening on %s\n", server_address); - auto server = builder.BuildAndStart(); - gpr_log(GPR_INFO, "Server listening on %s\n", server_address); + gpr_free(server_address); - ServerStatus last_status; - if (last_stats.get()) { - *last_status.mutable_stats() = *last_stats; - } - if (!stream->Write(last_status)) return Status(grpc::UNKNOWN); - - grpc_profiler_start("qps_server.prof"); + ServerStatus status; + status.set_port(FLAGS_port); + if (!stream->Write(status)) return Status(grpc::UNKNOWN); - done = stream->Read(&args); + grpc_profiler_start("qps_server.prof"); + Timer timer; - grpc_profiler_stop(); + if (stream->Read(&args)) { + gpr_log(GPR_ERROR, "Got a server request, but not expecting one"); + return Status(grpc::UNKNOWN); } - ServerStatus last_status; - if (last_stats.get()) { - *last_status.mutable_stats() = *last_stats; - } - stream->Write(last_status); + auto timer_result = timer.Mark(); + grpc_profiler_stop(); + + auto* stats = status.mutable_stats(); + stats->set_time_elapsed(timer_result.wall); + stats->set_time_system(timer_result.system); + stats->set_time_user(timer_result.user); + stream->Write(status); return Status::OK; } diff --git a/test/cpp/qps/single_run_localhost.sh b/test/cpp/qps/single_run_localhost.sh index ef3e343ebd..317202a6ab 100755 --- a/test/cpp/qps/single_run_localhost.sh +++ b/test/cpp/qps/single_run_localhost.sh @@ -6,13 +6,17 @@ set -ex cd $(dirname $0)/../../.. +killall qps_server qps_client || true + +config=opt + NUMCPUS=`python2.7 -c 'import multiprocessing; print multiprocessing.cpu_count()'` -make CONFIG=opt qps_client qps_server qps_driver -j$NUMCPUS +make CONFIG=$config qps_client qps_server qps_driver -j$NUMCPUS -bins/opt/qps_server -driver_port 10000 -port 10002 & +bins/$config/qps_server -driver_port 10000 -port 10002 & SERVER_PID=$! -bins/opt/qps_client -driver_port 10001 & +bins/$config/qps_client -driver_port 10001 & CLIENT_PID=$! # wait for startup @@ -21,7 +25,7 @@ sleep 2 export QPS_SERVERS=localhost:10000 export QPS_CLIENTS=localhost:10001 -bins/opt/qps_driver $* +bins/$config/qps_driver $* kill -2 $CLIENT_PID kill -2 $SERVER_PID diff --git a/test/cpp/qps/timer.cc b/test/cpp/qps/timer.cc new file mode 100644 index 0000000000..ff21f1a377 --- /dev/null +++ b/test/cpp/qps/timer.cc @@ -0,0 +1,65 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "test/cpp/qps/timer.h" + +#include <sys/time.h> +#include <sys/resource.h> + +Timer::Timer() : start_(Sample()) {} + +static double time_double(struct timeval* tv) { + return tv->tv_sec + 1e-6 * tv->tv_usec; +} + +Timer::Result Timer::Sample() { + struct rusage usage; + struct timeval tv; + gettimeofday(&tv, NULL); + getrusage(RUSAGE_SELF, &usage); + + Result r; + r.wall = time_double(&tv); + r.user = time_double(&usage.ru_utime); + r.system = time_double(&usage.ru_stime); + return r; +} + +Timer::Result Timer::Mark() { + Result s = Sample(); + Result r; + r.wall = s.wall - start_.wall; + r.user = s.user - start_.user; + r.system = s.system - start_.system; + return r; +}
\ No newline at end of file diff --git a/test/cpp/qps/timer.h b/test/cpp/qps/timer.h new file mode 100644 index 0000000000..8a229cbd30 --- /dev/null +++ b/test/cpp/qps/timer.h @@ -0,0 +1,55 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef TEST_QPS_TIMER_H +#define TEST_QPS_TIMER_H + +class Timer { + public: + Timer(); + + struct Result { + double wall; + double user; + double system; + }; + + Result Mark(); + + private: + static Result Sample(); + + const Result start_; +}; + +#endif // TEST_QPS_TIMER_H |