From 76877c3f6612f9c19103ce0d3273952d7f1f0350 Mon Sep 17 00:00:00 2001
From: Craig Tiller <ctiller@google.com>
Date: Tue, 3 Mar 2015 16:04:23 -0800
Subject: [PATCH] Generate latencies in driver

---
 include/grpc/support/histogram.h | 10 +++++++++
 src/core/support/histogram.c     | 35 +++++++++++++++++++++++---------
 test/cpp/qps/client.cc           |  7 +------
 test/cpp/qps/driver.cc           |  6 ++++++
 test/cpp/qps/histogram.h         | 16 +++++++++++++++
 test/cpp/qps/qpstest.proto       | 15 +++++++-------
 test/cpp/qps/worker.cc           |  1 +
 7 files changed, 67 insertions(+), 23 deletions(-)

diff --git a/include/grpc/support/histogram.h b/include/grpc/support/histogram.h
index 31f7fedfd5..64d08f0bf1 100644
--- a/include/grpc/support/histogram.h
+++ b/include/grpc/support/histogram.h
@@ -34,6 +34,9 @@
 #ifndef GRPC_SUPPORT_HISTOGRAM_H
 #define GRPC_SUPPORT_HISTOGRAM_H
 
+#include <grpc/support/port_platform.h>
+#include <stddef.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -59,6 +62,13 @@ double gpr_histogram_count(gpr_histogram *histogram);
 double gpr_histogram_sum(gpr_histogram *histogram);
 double gpr_histogram_sum_of_squares(gpr_histogram *histogram);
 
+const gpr_uint32 *gpr_histogram_get_contents(gpr_histogram *histogram,
+                                             size_t *count);
+void gpr_histogram_merge_contents(gpr_histogram *histogram,
+                                  const gpr_uint32 *data, size_t data_count,
+                                  double min_seen, double max_seen, double sum,
+                                  double sum_of_squares, double count);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/core/support/histogram.c b/src/core/support/histogram.c
index eacb77082f..2d52786ce5 100644
--- a/src/core/support/histogram.c
+++ b/src/core/support/histogram.c
@@ -126,25 +126,35 @@ void gpr_histogram_add(gpr_histogram *h, double x) {
 }
 
 int gpr_histogram_merge(gpr_histogram *dst, gpr_histogram *src) {
-  size_t i;
   if ((dst->num_buckets != src->num_buckets) ||
       (dst->multiplier != src->multiplier)) {
     /* Fail because these histograms don't match */
     return 0;
   }
-  dst->sum += src->sum;
-  dst->sum_of_squares += src->sum_of_squares;
-  dst->count += src->count;
-  if (src->min_seen < dst->min_seen) {
-    dst->min_seen = src->min_seen;
+  gpr_histogram_merge_contents(dst, src->buckets, src->num_buckets,
+                               src->min_seen, src->max_seen, src->sum,
+                               src->sum_of_squares, src->count);
+  return 1;
+}
+
+void gpr_histogram_merge_contents(gpr_histogram *dst, const gpr_uint32 *data,
+                                  size_t data_count, double min_seen,
+                                  double max_seen, double sum,
+                                  double sum_of_squares, double count) {
+  size_t i;
+  GPR_ASSERT(dst->num_buckets == data_count);
+  dst->sum += sum;
+  dst->sum_of_squares += sum_of_squares;
+  dst->count += count;
+  if (min_seen < dst->min_seen) {
+    dst->min_seen = min_seen;
   }
-  if (src->max_seen > dst->max_seen) {
-    dst->max_seen = src->max_seen;
+  if (max_seen > dst->max_seen) {
+    dst->max_seen = max_seen;
   }
   for (i = 0; i < dst->num_buckets; i++) {
-    dst->buckets[i] += src->buckets[i];
+    dst->buckets[i] += data[i];
   }
-  return 1;
 }
 
 static double threshold_for_count_below(gpr_histogram *h, double count_below) {
@@ -222,3 +232,8 @@ double gpr_histogram_sum(gpr_histogram *h) { return h->sum; }
 double gpr_histogram_sum_of_squares(gpr_histogram *h) {
   return h->sum_of_squares;
 }
+
+const gpr_uint32 *gpr_histogram_get_contents(gpr_histogram *h, size_t *size) {
+  *size = h->num_buckets;
+  return h->buckets;
+}
\ No newline at end of file
diff --git a/test/cpp/qps/client.cc b/test/cpp/qps/client.cc
index 951670c612..877007038e 100644
--- a/test/cpp/qps/client.cc
+++ b/test/cpp/qps/client.cc
@@ -90,12 +90,7 @@ class SynchronousClient GRPC_FINAL : public Client {
     auto timer_result = timer->Mark();
 
     ClientStats stats;
-    auto* l = stats.mutable_latencies();
-    l->set_l_50(latencies.Percentile(50));
-    l->set_l_90(latencies.Percentile(90));
-    l->set_l_99(latencies.Percentile(99));
-    l->set_l_999(latencies.Percentile(99.9));
-    stats.set_num_rpcs(latencies.Count());
+    latencies.FillProto(stats.mutable_latencies());
     stats.set_time_elapsed(timer_result.wall);
     stats.set_time_system(timer_result.system);
     stats.set_time_user(timer_result.user);
diff --git a/test/cpp/qps/driver.cc b/test/cpp/qps/driver.cc
index 0b200400cb..a9bd4b9dbd 100644
--- a/test/cpp/qps/driver.cc
+++ b/test/cpp/qps/driver.cc
@@ -43,6 +43,7 @@
 #include <list>
 #include <thread>
 #include <vector>
+#include "test/cpp/qps/histogram.h"
 
 using std::list;
 using std::thread;
@@ -171,6 +172,7 @@ void RunScenario(const ClientConfig& initial_client_config, size_t num_clients,
   gpr_sleep_until(gpr_time_add(start, gpr_time_from_seconds(15)));
 
   // Finish a run
+  Histogram latencies;
   gpr_log(GPR_INFO, "Finishing");
   for (auto& server : servers) {
     GPR_ASSERT(server.stream->Write(server_mark));
@@ -183,6 +185,7 @@ void RunScenario(const ClientConfig& initial_client_config, size_t num_clients,
   }
   for (auto& client : clients) {
     GPR_ASSERT(client.stream->Read(&client_status));
+    latencies.MergeProto(client_status.stats().latencies());
   }
 
   for (auto& client : clients) {
@@ -193,6 +196,9 @@ void RunScenario(const ClientConfig& initial_client_config, size_t num_clients,
     GPR_ASSERT(server.stream->WritesDone());
     GPR_ASSERT(server.stream->Finish().IsOk());
   }
+
+  gpr_log(GPR_INFO, "Latencies (50/95/99/99.9%%-ile): %.1f/%.1f/%.1f/%.1f us",
+    latencies.Percentile(50) / 1e3, latencies.Percentile(95) / 1e3, latencies.Percentile(99) / 1e3, latencies.Percentile(99.9) / 1e3);
 }
 }
 }
diff --git a/test/cpp/qps/histogram.h b/test/cpp/qps/histogram.h
index e660579008..a7ccc09ef9 100644
--- a/test/cpp/qps/histogram.h
+++ b/test/cpp/qps/histogram.h
@@ -35,6 +35,7 @@
 #define TEST_QPS_HISTOGRAM_H
 
 #include <grpc/support/histogram.h>
+#include "test/cpp/qps/qpstest.pb.h"
 
 namespace grpc {
 namespace testing {
@@ -51,6 +52,21 @@ class Histogram {
   }
   double Count() { return gpr_histogram_count(impl_); }
   void Swap(Histogram* other) { std::swap(impl_, other->impl_); }
+  void FillProto(HistogramData* p) {
+    size_t n;
+    const auto* data = gpr_histogram_get_contents(impl_, &n);
+    for (size_t i = 0; i < n; i++) {
+      p->add_bucket(data[i]);
+    }
+    p->set_min_seen(gpr_histogram_minimum(impl_));
+    p->set_max_seen(gpr_histogram_maximum(impl_));
+    p->set_sum(gpr_histogram_sum(impl_));
+    p->set_sum_of_squares(gpr_histogram_sum_of_squares(impl_));
+    p->set_count(gpr_histogram_count(impl_));
+  }
+  void MergeProto(const HistogramData& p) {
+    gpr_histogram_merge_contents(impl_, &*p.bucket().begin(), p.bucket_size(), p.min_seen(), p.max_seen(), p.sum(), p.sum_of_squares(), p.count());
+  }
 
  private:
   Histogram(const Histogram&);
diff --git a/test/cpp/qps/qpstest.proto b/test/cpp/qps/qpstest.proto
index 39d44cd0ed..6543e64a01 100644
--- a/test/cpp/qps/qpstest.proto
+++ b/test/cpp/qps/qpstest.proto
@@ -68,11 +68,13 @@ message Payload {
   optional bytes body = 2;
 }
 
-message Latencies {
-  required double l_50 = 1;
-  required double l_90 = 2;
-  required double l_99 = 3;
-  required double l_999 = 4;
+message HistogramData {
+  repeated uint32 bucket = 1;
+  required double min_seen = 2;
+  required double max_seen = 3;
+  required double sum = 4;
+  required double sum_of_squares = 5;
+  required double count = 6;
 }
 
 enum ClientType {
@@ -104,8 +106,7 @@ message ClientArgs {
 }
 
 message ClientStats {
-  required Latencies latencies = 1;
-  required int32 num_rpcs = 2;
+  required HistogramData latencies = 1;
   required double time_elapsed = 3;
   required double time_user = 4;
   required double time_system = 5;
diff --git a/test/cpp/qps/worker.cc b/test/cpp/qps/worker.cc
index 1279afc18c..b5dbc1570d 100644
--- a/test/cpp/qps/worker.cc
+++ b/test/cpp/qps/worker.cc
@@ -169,6 +169,7 @@ class WorkerImpl final : public Worker::Service {
   }
 
  private:
+  // Protect against multiple clients using this worker at once.
   class InstanceGuard {
    public:
     InstanceGuard(WorkerImpl* impl)
-- 
GitLab