Skip to content

Commit

Permalink
Merge pull request grpc#16446 from hcaseyal/add_per_second_profiling
Browse files Browse the repository at this point in the history
Add an option to collect latency medians every epoch
  • Loading branch information
hcaseyal authored Aug 26, 2018
2 parents 98fd5a7 + e360d82 commit 0761cfc
Show file tree
Hide file tree
Showing 9 changed files with 75 additions and 13 deletions.
4 changes: 4 additions & 0 deletions src/proto/grpc/testing/control.proto
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ message ClientConfig {

// Use coalescing API when possible.
bool use_coalesce_api = 19;

// If 0, disabled. Else, specifies the period between gathering latency
// medians in milliseconds.
int32 median_latency_collection_interval_millis = 20;
}

message ClientStatus { ClientStats stats = 1; }
Expand Down
45 changes: 44 additions & 1 deletion test/cpp/qps/client.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,19 @@ class Client {
timer_result = timer_->Mark();
}

// Print the median latency per interval for one thread.
// If the number of warmup seconds is x, then the first x + 1 numbers in the
// vector are from the warmup period and should be discarded.
if (median_latency_collection_interval_seconds_ > 0) {
std::vector<double> medians_per_interval =
threads_[0]->GetMedianPerIntervalList();
gpr_log(GPR_INFO, "Num threads: %ld", threads_.size());
gpr_log(GPR_INFO, "Number of medians: %ld", medians_per_interval.size());
for (size_t j = 0; j < medians_per_interval.size(); j++) {
gpr_log(GPR_INFO, "%f", medians_per_interval[j]);
}
}

grpc_stats_data core_stats;
grpc_stats_collect(&core_stats);

Expand Down Expand Up @@ -210,6 +223,12 @@ class Client {
}
}

// Returns the interval (in seconds) between collecting latency medians. If 0,
// no periodic median latencies will be collected.
double GetLatencyCollectionIntervalInSeconds() {
return median_latency_collection_interval_seconds_;
}

virtual int GetPollCount() {
// For sync client.
return 0;
Expand All @@ -218,6 +237,7 @@ class Client {
protected:
bool closed_loop_;
gpr_atm thread_pool_done_;
double median_latency_collection_interval_seconds_; // In seconds

void StartThreads(size_t num_threads) {
gpr_atm_rel_store(&thread_pool_done_, static_cast<gpr_atm>(false));
Expand Down Expand Up @@ -299,10 +319,27 @@ class Client {
MergeStatusHistogram(statuses_, s);
}

std::vector<double> GetMedianPerIntervalList() {
return medians_each_interval_list_;
}

void UpdateHistogram(HistogramEntry* entry) {
std::lock_guard<std::mutex> g(mu_);
if (entry->value_used()) {
histogram_.Add(entry->value());
if (client_->GetLatencyCollectionIntervalInSeconds() > 0) {
histogram_per_interval_.Add(entry->value());
double now = UsageTimer::Now();
if ((now - interval_start_time_) >=
client_->GetLatencyCollectionIntervalInSeconds()) {
// Record the median latency of requests from the last interval.
// Divide by 1e3 to get microseconds.
medians_each_interval_list_.push_back(
histogram_per_interval_.Percentile(50) / 1e3);
histogram_per_interval_.Reset();
interval_start_time_ = now;
}
}
}
if (entry->status_used()) {
statuses_[entry->status()]++;
Expand Down Expand Up @@ -334,6 +371,11 @@ class Client {
Client* client_;
const size_t idx_;
std::thread impl_;
// The following are used only if
// median_latency_collection_interval_seconds_ is greater than 0
Histogram histogram_per_interval_;
std::vector<double> medians_each_interval_list_;
double interval_start_time_;
};

bool ThreadCompleted() {
Expand Down Expand Up @@ -392,7 +434,8 @@ class ClientImpl : public Client {
for (auto& t : connecting_threads) {
t->join();
}

median_latency_collection_interval_seconds_ =
config.median_latency_collection_interval_millis() / 1e3;
ClientRequestCreator<RequestType> create_req(&request_,
config.payload_config());
}
Expand Down
6 changes: 5 additions & 1 deletion test/cpp/qps/driver.cc
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,8 @@ std::unique_ptr<ScenarioResult> RunScenario(
const ServerConfig& initial_server_config, size_t num_servers,
int warmup_seconds, int benchmark_seconds, int spawn_local_worker_count,
const grpc::string& qps_server_target_override,
const grpc::string& credential_type, bool run_inproc) {
const grpc::string& credential_type, bool run_inproc,
int32_t median_latency_collection_interval_millis) {
if (run_inproc) {
g_inproc_servers = new std::vector<grpc::testing::Server*>;
}
Expand Down Expand Up @@ -317,6 +318,9 @@ std::unique_ptr<ScenarioResult> RunScenario(
}
}

client_config.set_median_latency_collection_interval_millis(
median_latency_collection_interval_millis);

// Targets are all set by now
result_client_config = client_config;
// Start clients
Expand Down
3 changes: 2 additions & 1 deletion test/cpp/qps/driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ std::unique_ptr<ScenarioResult> RunScenario(
const grpc::testing::ServerConfig& server_config, size_t num_servers,
int warmup_seconds, int benchmark_seconds, int spawn_local_worker_count,
const grpc::string& qps_server_target_override,
const grpc::string& credential_type, bool run_inproc);
const grpc::string& credential_type, bool run_inproc,
int32_t median_latency_collection_interval_millis);

bool RunQuit(const grpc::string& credential_type);
} // namespace testing
Expand Down
5 changes: 5 additions & 0 deletions test/cpp/qps/histogram.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ class Histogram {
~Histogram() {
if (impl_) grpc_histogram_destroy(impl_);
}
void Reset() {
if (impl_) grpc_histogram_destroy(impl_);
impl_ = grpc_histogram_create(default_resolution(), default_max_possible());
}

Histogram(Histogram&& other) : impl_(other.impl_) { other.impl_ = nullptr; }

void Merge(const Histogram& h) { grpc_histogram_merge(impl_, h.impl_); }
Expand Down
2 changes: 1 addition & 1 deletion test/cpp/qps/inproc_sync_unary_ping_pong_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ static void RunSynchronousUnaryPingPong() {

const auto result =
RunScenario(client_config, 1, server_config, 1, WARMUP, BENCHMARK, -2, "",
kInsecureCredentialsType, true);
kInsecureCredentialsType, true, 0);

GetReporter()->ReportQPS(*result);
GetReporter()->ReportLatency(*result);
Expand Down
19 changes: 12 additions & 7 deletions test/cpp/qps/qps_json_driver.cc
Original file line number Diff line number Diff line change
Expand Up @@ -66,20 +66,25 @@ DEFINE_string(json_file_out, "", "File to write the JSON output to.");
DEFINE_string(credential_type, grpc::testing::kInsecureCredentialsType,
"Credential type for communication with workers");
DEFINE_bool(run_inproc, false, "Perform an in-process transport test");
DEFINE_int32(
median_latency_collection_interval_millis, 0,
"Specifies the period between gathering latency medians in "
"milliseconds. The medians will be logged out on the client at the "
"end of the benchmark run. If 0, this periodic collection is disabled.");

namespace grpc {
namespace testing {

static std::unique_ptr<ScenarioResult> RunAndReport(const Scenario& scenario,
bool* success) {
std::cerr << "RUNNING SCENARIO: " << scenario.name() << "\n";
auto result =
RunScenario(scenario.client_config(), scenario.num_clients(),
scenario.server_config(), scenario.num_servers(),
scenario.warmup_seconds(), scenario.benchmark_seconds(),
!FLAGS_run_inproc ? scenario.spawn_local_worker_count() : -2,
FLAGS_qps_server_target_override, FLAGS_credential_type,
FLAGS_run_inproc);
auto result = RunScenario(
scenario.client_config(), scenario.num_clients(),
scenario.server_config(), scenario.num_servers(),
scenario.warmup_seconds(), scenario.benchmark_seconds(),
!FLAGS_run_inproc ? scenario.spawn_local_worker_count() : -2,
FLAGS_qps_server_target_override, FLAGS_credential_type, FLAGS_run_inproc,
FLAGS_median_latency_collection_interval_millis);

// Amend the result with scenario config. Eventually we should adjust
// RunScenario contract so we don't need to touch the result here.
Expand Down
2 changes: 1 addition & 1 deletion test/cpp/qps/qps_openloop_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ static void RunQPS() {

const auto result =
RunScenario(client_config, 1, server_config, 1, WARMUP, BENCHMARK, -2, "",
kInsecureCredentialsType, false);
kInsecureCredentialsType, false, 0);

GetReporter()->ReportQPSPerCore(*result);
GetReporter()->ReportLatency(*result);
Expand Down
2 changes: 1 addition & 1 deletion test/cpp/qps/secure_sync_unary_ping_pong_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ static void RunSynchronousUnaryPingPong() {

const auto result =
RunScenario(client_config, 1, server_config, 1, WARMUP, BENCHMARK, -2, "",
kInsecureCredentialsType, false);
kInsecureCredentialsType, false, 0);

GetReporter()->ReportQPS(*result);
GetReporter()->ReportLatency(*result);
Expand Down

0 comments on commit 0761cfc

Please sign in to comment.