diff --git a/Makefile b/Makefile
index 1f2c93af72d0b2cc742e8159138a934270ff2ddd..0dd0f266eeeda2952c01623c4962a3cb144b7c75 100644
--- a/Makefile
+++ b/Makefile
@@ -3600,6 +3600,21 @@ $(GENDIR)/test/proto/perf_tests/perf_control.grpc.pb.cc: test/proto/perf_tests/p
 	$(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
 endif
 
+ifeq ($(NO_PROTOC),true)
+$(GENDIR)/test/proto/perf_tests/perf_services.pb.cc: protoc_dep_error
+$(GENDIR)/test/proto/perf_tests/perf_services.grpc.pb.cc: protoc_dep_error
+else
+$(GENDIR)/test/proto/perf_tests/perf_services.pb.cc: test/proto/perf_tests/perf_services.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
+	$(E) "[PROTOC]  Generating protobuf CC file from $<"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(PROTOC) --cpp_out=$(GENDIR) $<
+
+$(GENDIR)/test/proto/perf_tests/perf_services.grpc.pb.cc: test/proto/perf_tests/perf_services.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
+	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
+endif
+
 ifeq ($(NO_PROTOC),true)
 $(GENDIR)/test/proto/perf_tests/perf_stats.pb.cc: protoc_dep_error
 $(GENDIR)/test/proto/perf_tests/perf_stats.grpc.pb.cc: protoc_dep_error
@@ -5206,6 +5221,7 @@ $(OBJDIR)/$(CONFIG)/test/cpp/interop/server.o: $(GENDIR)/test/proto/empty.pb.cc
 LIBQPS_SRC = \
     $(GENDIR)/test/proto/messages.pb.cc $(GENDIR)/test/proto/messages.grpc.pb.cc \
     $(GENDIR)/test/proto/perf_tests/perf_control.pb.cc $(GENDIR)/test/proto/perf_tests/perf_control.grpc.pb.cc \
+    $(GENDIR)/test/proto/perf_tests/perf_services.pb.cc $(GENDIR)/test/proto/perf_tests/perf_services.grpc.pb.cc \
     $(GENDIR)/test/proto/perf_tests/perf_stats.pb.cc $(GENDIR)/test/proto/perf_tests/perf_stats.grpc.pb.cc \
     $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc \
     test/cpp/qps/client_async.cc \
@@ -5261,16 +5277,16 @@ ifneq ($(NO_DEPS),true)
 -include $(LIBQPS_OBJS:.o=.dep)
 endif
 endif
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/client_async.o: $(GENDIR)/test/proto/messages.pb.cc $(GENDIR)/test/proto/messages.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_control.pb.cc $(GENDIR)/test/proto/perf_tests/perf_control.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_stats.pb.cc $(GENDIR)/test/proto/perf_tests/perf_stats.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/client_sync.o: $(GENDIR)/test/proto/messages.pb.cc $(GENDIR)/test/proto/messages.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_control.pb.cc $(GENDIR)/test/proto/perf_tests/perf_control.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_stats.pb.cc $(GENDIR)/test/proto/perf_tests/perf_stats.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/driver.o: $(GENDIR)/test/proto/messages.pb.cc $(GENDIR)/test/proto/messages.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_control.pb.cc $(GENDIR)/test/proto/perf_tests/perf_control.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_stats.pb.cc $(GENDIR)/test/proto/perf_tests/perf_stats.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/perf_db_client.o: $(GENDIR)/test/proto/messages.pb.cc $(GENDIR)/test/proto/messages.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_control.pb.cc $(GENDIR)/test/proto/perf_tests/perf_control.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_stats.pb.cc $(GENDIR)/test/proto/perf_tests/perf_stats.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/qps_worker.o: $(GENDIR)/test/proto/messages.pb.cc $(GENDIR)/test/proto/messages.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_control.pb.cc $(GENDIR)/test/proto/perf_tests/perf_control.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_stats.pb.cc $(GENDIR)/test/proto/perf_tests/perf_stats.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/report.o: $(GENDIR)/test/proto/messages.pb.cc $(GENDIR)/test/proto/messages.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_control.pb.cc $(GENDIR)/test/proto/perf_tests/perf_control.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_stats.pb.cc $(GENDIR)/test/proto/perf_tests/perf_stats.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/server_async.o: $(GENDIR)/test/proto/messages.pb.cc $(GENDIR)/test/proto/messages.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_control.pb.cc $(GENDIR)/test/proto/perf_tests/perf_control.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_stats.pb.cc $(GENDIR)/test/proto/perf_tests/perf_stats.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/server_sync.o: $(GENDIR)/test/proto/messages.pb.cc $(GENDIR)/test/proto/messages.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_control.pb.cc $(GENDIR)/test/proto/perf_tests/perf_control.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_stats.pb.cc $(GENDIR)/test/proto/perf_tests/perf_stats.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/timer.o: $(GENDIR)/test/proto/messages.pb.cc $(GENDIR)/test/proto/messages.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_control.pb.cc $(GENDIR)/test/proto/perf_tests/perf_control.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_stats.pb.cc $(GENDIR)/test/proto/perf_tests/perf_stats.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/util/benchmark_config.o: $(GENDIR)/test/proto/messages.pb.cc $(GENDIR)/test/proto/messages.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_control.pb.cc $(GENDIR)/test/proto/perf_tests/perf_control.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_stats.pb.cc $(GENDIR)/test/proto/perf_tests/perf_stats.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/client_async.o: $(GENDIR)/test/proto/messages.pb.cc $(GENDIR)/test/proto/messages.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_control.pb.cc $(GENDIR)/test/proto/perf_tests/perf_control.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_services.pb.cc $(GENDIR)/test/proto/perf_tests/perf_services.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_stats.pb.cc $(GENDIR)/test/proto/perf_tests/perf_stats.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/client_sync.o: $(GENDIR)/test/proto/messages.pb.cc $(GENDIR)/test/proto/messages.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_control.pb.cc $(GENDIR)/test/proto/perf_tests/perf_control.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_services.pb.cc $(GENDIR)/test/proto/perf_tests/perf_services.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_stats.pb.cc $(GENDIR)/test/proto/perf_tests/perf_stats.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/driver.o: $(GENDIR)/test/proto/messages.pb.cc $(GENDIR)/test/proto/messages.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_control.pb.cc $(GENDIR)/test/proto/perf_tests/perf_control.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_services.pb.cc $(GENDIR)/test/proto/perf_tests/perf_services.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_stats.pb.cc $(GENDIR)/test/proto/perf_tests/perf_stats.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/perf_db_client.o: $(GENDIR)/test/proto/messages.pb.cc $(GENDIR)/test/proto/messages.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_control.pb.cc $(GENDIR)/test/proto/perf_tests/perf_control.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_services.pb.cc $(GENDIR)/test/proto/perf_tests/perf_services.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_stats.pb.cc $(GENDIR)/test/proto/perf_tests/perf_stats.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/qps_worker.o: $(GENDIR)/test/proto/messages.pb.cc $(GENDIR)/test/proto/messages.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_control.pb.cc $(GENDIR)/test/proto/perf_tests/perf_control.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_services.pb.cc $(GENDIR)/test/proto/perf_tests/perf_services.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_stats.pb.cc $(GENDIR)/test/proto/perf_tests/perf_stats.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/report.o: $(GENDIR)/test/proto/messages.pb.cc $(GENDIR)/test/proto/messages.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_control.pb.cc $(GENDIR)/test/proto/perf_tests/perf_control.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_services.pb.cc $(GENDIR)/test/proto/perf_tests/perf_services.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_stats.pb.cc $(GENDIR)/test/proto/perf_tests/perf_stats.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/server_async.o: $(GENDIR)/test/proto/messages.pb.cc $(GENDIR)/test/proto/messages.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_control.pb.cc $(GENDIR)/test/proto/perf_tests/perf_control.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_services.pb.cc $(GENDIR)/test/proto/perf_tests/perf_services.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_stats.pb.cc $(GENDIR)/test/proto/perf_tests/perf_stats.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/server_sync.o: $(GENDIR)/test/proto/messages.pb.cc $(GENDIR)/test/proto/messages.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_control.pb.cc $(GENDIR)/test/proto/perf_tests/perf_control.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_services.pb.cc $(GENDIR)/test/proto/perf_tests/perf_services.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_stats.pb.cc $(GENDIR)/test/proto/perf_tests/perf_stats.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/timer.o: $(GENDIR)/test/proto/messages.pb.cc $(GENDIR)/test/proto/messages.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_control.pb.cc $(GENDIR)/test/proto/perf_tests/perf_control.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_services.pb.cc $(GENDIR)/test/proto/perf_tests/perf_services.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_stats.pb.cc $(GENDIR)/test/proto/perf_tests/perf_stats.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/util/benchmark_config.o: $(GENDIR)/test/proto/messages.pb.cc $(GENDIR)/test/proto/messages.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_control.pb.cc $(GENDIR)/test/proto/perf_tests/perf_control.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_services.pb.cc $(GENDIR)/test/proto/perf_tests/perf_services.grpc.pb.cc $(GENDIR)/test/proto/perf_tests/perf_stats.pb.cc $(GENDIR)/test/proto/perf_tests/perf_stats.grpc.pb.cc $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc
 
 
 LIBGRPC_CSHARP_EXT_SRC = \
diff --git a/build.yaml b/build.yaml
index b8c53f2739f5a374d488a402e8c517232569773a..a90cd12b15e74b1e42d346fcd858e2441b21e980 100644
--- a/build.yaml
+++ b/build.yaml
@@ -751,6 +751,7 @@ libs:
   src:
   - test/proto/messages.proto
   - test/proto/perf_tests/perf_control.proto
+  - test/proto/perf_tests/perf_services.proto
   - test/proto/perf_tests/perf_stats.proto
   - test/cpp/qps/perf_db.proto
   - test/cpp/qps/client_async.cc
diff --git a/include/grpc/support/histogram.h b/include/grpc/support/histogram.h
index 2fd1084208fdb9aeb3d42f1ba7488c432e4d51dc..fd56dacc989c6979b34fa3671ceb93a3e4e96206 100644
--- a/include/grpc/support/histogram.h
+++ b/include/grpc/support/histogram.h
@@ -50,7 +50,7 @@ void gpr_histogram_add(gpr_histogram *h, double x);
 /* The following merges the second histogram into the first. It only works
    if they have the same buckets and resolution. Returns 0 on failure, 1
    on success */
-int gpr_histogram_merge(gpr_histogram *dst, gpr_histogram *src);
+int gpr_histogram_merge(gpr_histogram *dst, const gpr_histogram *src);
 
 double gpr_histogram_percentile(gpr_histogram *histogram, double percentile);
 double gpr_histogram_mean(gpr_histogram *histogram);
diff --git a/src/core/support/histogram.c b/src/core/support/histogram.c
index 8a1a9d92330d2210d2195dc4adea0c0c8f30b5c7..77b48af9969f20cb6462d95f6a2c43ade950326c 100644
--- a/src/core/support/histogram.c
+++ b/src/core/support/histogram.c
@@ -125,7 +125,7 @@ void gpr_histogram_add(gpr_histogram *h, double x) {
   h->buckets[bucket_for(h, x)]++;
 }
 
-int gpr_histogram_merge(gpr_histogram *dst, gpr_histogram *src) {
+int gpr_histogram_merge(gpr_histogram *dst, const gpr_histogram *src) {
   if ((dst->num_buckets != src->num_buckets) ||
       (dst->multiplier != src->multiplier)) {
     /* Fail because these histograms don't match */
diff --git a/test/cpp/qps/async_streaming_ping_pong_test.cc b/test/cpp/qps/async_streaming_ping_pong_test.cc
index 2d3ebfdfdb47ba744c450707b1d03144c6dffd5e..e3a614e743305e2b192afb1eef66a18b874cda7e 100644
--- a/test/cpp/qps/async_streaming_ping_pong_test.cc
+++ b/test/cpp/qps/async_streaming_ping_pong_test.cc
@@ -58,6 +58,7 @@ static void RunAsyncStreamingPingPong() {
   client_config.set_payload_size(1);
   client_config.set_async_client_threads(1);
   client_config.set_rpc_type(STREAMING);
+  client_config.mutable_load_params()->mutable_closed();
 
   ServerConfig server_config;
   server_config.set_server_type(ASYNC_SERVER);
diff --git a/test/cpp/qps/async_unary_ping_pong_test.cc b/test/cpp/qps/async_unary_ping_pong_test.cc
index a5f91c515754a1fd250da4950fc9521e98b5ec44..caed835325e1dad250db55575ef5058c78a94c65 100644
--- a/test/cpp/qps/async_unary_ping_pong_test.cc
+++ b/test/cpp/qps/async_unary_ping_pong_test.cc
@@ -58,6 +58,7 @@ static void RunAsyncUnaryPingPong() {
   client_config.set_payload_size(1);
   client_config.set_async_client_threads(1);
   client_config.set_rpc_type(UNARY);
+  client_config.mutable_load_params()->mutable_closed();
 
   ServerConfig server_config;
   server_config.set_server_type(ASYNC_SERVER);
diff --git a/test/cpp/qps/client.h b/test/cpp/qps/client.h
index 7086ae820af23f081671a26136f39476468c3c90..110249bd2590688fad02d8060adff19297d51d5d 100644
--- a/test/cpp/qps/client.h
+++ b/test/cpp/qps/client.h
@@ -40,8 +40,8 @@
 #include "test/cpp/qps/histogram.h"
 #include "test/cpp/qps/interarrival.h"
 #include "test/cpp/qps/timer.h"
-#include "test/proto/perf_tests/perf_control.grpc.pb.h"
 #include "test/cpp/util/create_test_channel.h"
+#include "test/proto/perf_tests/perf_services.grpc.pb.h"
 
 namespace grpc {
 
@@ -80,22 +80,31 @@ class Client {
   }
   virtual ~Client() {}
 
-  ClientStats Mark() {
+  ClientStats Mark(bool reset) {
     Histogram latencies;
+    Timer::Result timer_result;
+
     // avoid std::vector for old compilers that expect a copy constructor
-    Histogram* to_merge = new Histogram[threads_.size()];
-    for (size_t i = 0; i < threads_.size(); i++) {
-      threads_[i]->BeginSwap(&to_merge[i]);
-    }
-    std::unique_ptr<Timer> timer(new Timer);
-    timer_.swap(timer);
-    for (size_t i = 0; i < threads_.size(); i++) {
-      threads_[i]->EndSwap();
-      latencies.Merge(&to_merge[i]);
+    if (reset) {
+      Histogram* to_merge = new Histogram[threads_.size()];
+      for (size_t i = 0; i < threads_.size(); i++) {
+	threads_[i]->BeginSwap(&to_merge[i]);
+      }
+      std::unique_ptr<Timer> timer(new Timer);
+      timer_.swap(timer);
+      for (size_t i = 0; i < threads_.size(); i++) {
+	threads_[i]->EndSwap();
+	latencies.Merge(to_merge[i]);
+      }
+      delete[] to_merge;
+      timer_result = timer->Mark();
+    } else {
+      // merge snapshots of each thread histogram
+      for (size_t i = 0; i < threads_.size(); i++) {
+	threads_[i]->MergeStatsInto(&latencies);
+      }
+      timer_result = timer_->Mark();
     }
-    delete[] to_merge;
-
-    auto timer_result = timer->Mark();
 
     ClientStats stats;
     latencies.FillProto(stats.mutable_latencies());
@@ -123,14 +132,14 @@ class Client {
       // constructor followed by an initializer function to make
       // old compilers happy with using this in std::vector
       channel_ = CreateTestChannel(target, config.use_tls());
-      stub_ = TestService::NewStub(channel_);
+      stub_ = BenchmarkService::NewStub(channel_);
     }
     Channel* get_channel() { return channel_.get(); }
-    TestService::Stub* get_stub() { return stub_.get(); }
+    BenchmarkService::Stub* get_stub() { return stub_.get(); }
 
    private:
     std::shared_ptr<Channel> channel_;
-    std::unique_ptr<TestService::Stub> stub_;
+    std::unique_ptr<BenchmarkService::Stub> stub_;
   };
   std::vector<ClientChannelInfo> channels_;
 
@@ -162,7 +171,10 @@ class Client {
     } else if (load.has_pareto()) {
       random_dist.reset(new ParetoDist(load.pareto().interarrival_base() * num_threads,
 				       load.pareto().alpha()));
-    } else { // No load parameters, so must be closed-loop
+    } else if (load.has_closed()) {
+      // Closed-loop doesn't use random dist at all
+    } else { // invalid load type
+      GPR_ASSERT(false);
     }
 
     // Set closed_loop_ based on whether or not random_dist is set
@@ -198,7 +210,7 @@ class Client {
    public:
     Thread(Client* client, size_t idx)
         : done_(false),
-          new_(nullptr),
+          new_stats_(nullptr),
           client_(client),
           idx_(idx),
           impl_(&Thread::ThreadFunc, this) {}
@@ -213,16 +225,21 @@ class Client {
 
     void BeginSwap(Histogram* n) {
       std::lock_guard<std::mutex> g(mu_);
-      new_ = n;
+      new_stats_ = n;
     }
 
     void EndSwap() {
       std::unique_lock<std::mutex> g(mu_);
-      while (new_ != nullptr) {
+      while (new_stats_ != nullptr) {
         cv_.wait(g);
       };
     }
 
+    void MergeStatsInto(Histogram* hist) {
+      std::unique_lock<std::mutex> g(mu_);
+      hist->Merge(histogram_);
+    }
+
    private:
     Thread(const Thread&);
     Thread& operator=(const Thread&);
@@ -240,21 +257,21 @@ class Client {
         if (done_) {
           return;
         }
-        // check if we're marking, swap out the histogram if so
-        if (new_) {
-          new_->Swap(&histogram_);
-          new_ = nullptr;
+        // check if we're resetting stats, swap out the histogram if so
+        if (new_stats_) {
+          new_stats_->Swap(&histogram_);
+          new_stats_ = nullptr;
           cv_.notify_one();
         }
       }
     }
 
-    TestService::Stub* stub_;
+    BenchmarkService::Stub* stub_;
     ClientConfig config_;
     std::mutex mu_;
     std::condition_variable cv_;
     bool done_;
-    Histogram* new_;
+    Histogram* new_stats_;
     Histogram histogram_;
     Client* client_;
     size_t idx_;
diff --git a/test/cpp/qps/client_async.cc b/test/cpp/qps/client_async.cc
index cef17fa1f9a5bc0627f21465c6d89d33b10470c3..41db6151c5a1574eb230c8acfb0af59b9c89b879 100644
--- a/test/cpp/qps/client_async.cc
+++ b/test/cpp/qps/client_async.cc
@@ -48,10 +48,10 @@
 #include <gflags/gflags.h>
 #include <grpc++/client_context.h>
 
-#include "test/proto/perf_tests/perf_control.grpc.pb.h"
 #include "test/cpp/qps/timer.h"
 #include "test/cpp/qps/client.h"
 #include "test/cpp/util/create_test_channel.h"
+#include "test/proto/perf_tests/perf_services.grpc.pb.h"
 
 namespace grpc {
 namespace testing {
@@ -88,10 +88,10 @@ template <class RequestType, class ResponseType>
 class ClientRpcContextUnaryImpl : public ClientRpcContext {
  public:
   ClientRpcContextUnaryImpl(
-      int channel_id, TestService::Stub* stub, const RequestType& req,
+      int channel_id, BenchmarkService::Stub* stub, const RequestType& req,
       std::function<
           std::unique_ptr<grpc::ClientAsyncResponseReader<ResponseType>>(
-              TestService::Stub*, grpc::ClientContext*, const RequestType&,
+              BenchmarkService::Stub*, grpc::ClientContext*, const RequestType&,
               CompletionQueue*)> start_req,
       std::function<void(grpc::Status, ResponseType*)> on_done)
       : ClientRpcContext(channel_id),
@@ -131,13 +131,13 @@ class ClientRpcContextUnaryImpl : public ClientRpcContext {
     return true;  // we're done, this'll be ignored
   }
   grpc::ClientContext context_;
-  TestService::Stub* stub_;
+  BenchmarkService::Stub* stub_;
   RequestType req_;
   ResponseType response_;
   bool (ClientRpcContextUnaryImpl::*next_state_)(bool);
   std::function<void(grpc::Status, ResponseType*)> callback_;
   std::function<std::unique_ptr<grpc::ClientAsyncResponseReader<ResponseType>>(
-      TestService::Stub*, grpc::ClientContext*, const RequestType&,
+      BenchmarkService::Stub*, grpc::ClientContext*, const RequestType&,
       CompletionQueue*)> start_req_;
   grpc::Status status_;
   double start_;
@@ -151,7 +151,7 @@ class AsyncClient : public Client {
  public:
   explicit AsyncClient(
       const ClientConfig& config,
-      std::function<ClientRpcContext*(int, TestService::Stub*,
+      std::function<ClientRpcContext*(int, BenchmarkService::Stub*,
                                       const SimpleRequest&)> setup_ctx)
       : Client(config),
         channel_lock_(new std::mutex[config.client_channels()]),
@@ -354,11 +354,11 @@ class AsyncUnaryClient GRPC_FINAL : public AsyncClient {
  private:
   static void CheckDone(grpc::Status s, SimpleResponse* response) {}
   static std::unique_ptr<grpc::ClientAsyncResponseReader<SimpleResponse>>
-  StartReq(TestService::Stub* stub, grpc::ClientContext* ctx,
+  StartReq(BenchmarkService::Stub* stub, grpc::ClientContext* ctx,
            const SimpleRequest& request, CompletionQueue* cq) {
     return stub->AsyncUnaryCall(ctx, request, cq);
   };
-  static ClientRpcContext* SetupCtx(int channel_id, TestService::Stub* stub,
+  static ClientRpcContext* SetupCtx(int channel_id, BenchmarkService::Stub* stub,
                                     const SimpleRequest& req) {
     return new ClientRpcContextUnaryImpl<SimpleRequest, SimpleResponse>(
         channel_id, stub, req, AsyncUnaryClient::StartReq,
@@ -370,9 +370,9 @@ template <class RequestType, class ResponseType>
 class ClientRpcContextStreamingImpl : public ClientRpcContext {
  public:
   ClientRpcContextStreamingImpl(
-      int channel_id, TestService::Stub* stub, const RequestType& req,
+      int channel_id, BenchmarkService::Stub* stub, const RequestType& req,
       std::function<std::unique_ptr<grpc::ClientAsyncReaderWriter<
-          RequestType, ResponseType>>(TestService::Stub*, grpc::ClientContext*,
+          RequestType, ResponseType>>(BenchmarkService::Stub*, grpc::ClientContext*,
                                       CompletionQueue*, void*)> start_req,
       std::function<void(grpc::Status, ResponseType*)> on_done)
       : ClientRpcContext(channel_id),
@@ -420,14 +420,14 @@ class ClientRpcContextStreamingImpl : public ClientRpcContext {
     return StartWrite(ok);
   }
   grpc::ClientContext context_;
-  TestService::Stub* stub_;
+  BenchmarkService::Stub* stub_;
   RequestType req_;
   ResponseType response_;
   bool (ClientRpcContextStreamingImpl::*next_state_)(bool, Histogram*);
   std::function<void(grpc::Status, ResponseType*)> callback_;
   std::function<
       std::unique_ptr<grpc::ClientAsyncReaderWriter<RequestType, ResponseType>>(
-          TestService::Stub*, grpc::ClientContext*, CompletionQueue*, void*)>
+          BenchmarkService::Stub*, grpc::ClientContext*, CompletionQueue*, void*)>
       start_req_;
   grpc::Status status_;
   double start_;
@@ -451,12 +451,12 @@ class AsyncStreamingClient GRPC_FINAL : public AsyncClient {
   static void CheckDone(grpc::Status s, SimpleResponse* response) {}
   static std::unique_ptr<
       grpc::ClientAsyncReaderWriter<SimpleRequest, SimpleResponse>>
-  StartReq(TestService::Stub* stub, grpc::ClientContext* ctx,
+  StartReq(BenchmarkService::Stub* stub, grpc::ClientContext* ctx,
            CompletionQueue* cq, void* tag) {
     auto stream = stub->AsyncStreamingCall(ctx, cq, tag);
     return stream;
   };
-  static ClientRpcContext* SetupCtx(int channel_id, TestService::Stub* stub,
+  static ClientRpcContext* SetupCtx(int channel_id, BenchmarkService::Stub* stub,
                                     const SimpleRequest& req) {
     return new ClientRpcContextStreamingImpl<SimpleRequest, SimpleResponse>(
         channel_id, stub, req, AsyncStreamingClient::StartReq,
diff --git a/test/cpp/qps/client_sync.cc b/test/cpp/qps/client_sync.cc
index b9d857c4826beb895f954e88088c8698f5014e36..44d525b1965d5cc9689d74fc3d182ac241bcc987 100644
--- a/test/cpp/qps/client_sync.cc
+++ b/test/cpp/qps/client_sync.cc
@@ -54,10 +54,10 @@
 
 #include "test/cpp/util/create_test_channel.h"
 #include "test/cpp/qps/client.h"
-#include "test/proto/perf_tests/perf_control.grpc.pb.h"
 #include "test/cpp/qps/histogram.h"
 #include "test/cpp/qps/interarrival.h"
 #include "test/cpp/qps/timer.h"
+#include "test/proto/perf_tests/perf_services.grpc.pb.h"
 
 #include "src/core/profiling/timers.h"
 
diff --git a/test/cpp/qps/driver.cc b/test/cpp/qps/driver.cc
index 500cc510188ce6d5069e95b74886c78d925608ab..12b9feed2518cd84bc80765d2f6c4c37b309210d 100644
--- a/test/cpp/qps/driver.cc
+++ b/test/cpp/qps/driver.cc
@@ -48,6 +48,7 @@
 #include "test/cpp/qps/driver.h"
 #include "test/cpp/qps/histogram.h"
 #include "test/cpp/qps/qps_worker.h"
+#include "test/proto/perf_tests/perf_services.grpc.pb.h"
 
 using std::list;
 using std::thread;
@@ -91,12 +92,12 @@ static ClientContext* AllocContext(list<ClientContext>* contexts, T deadline) {
 }
 
 struct ServerData {
-  unique_ptr<Worker::Stub> stub;
+  unique_ptr<WorkerService::Stub> stub;
   unique_ptr<ClientReaderWriter<ServerArgs, ServerStatus>> stream;
 };
 
 struct ClientData {
-  unique_ptr<Worker::Stub> stub;
+  unique_ptr<WorkerService::Stub> stub;
   unique_ptr<ClientReaderWriter<ClientArgs, ClientStatus>> stream;
 };
 }  // namespace runsc
@@ -162,7 +163,7 @@ std::unique_ptr<ScenarioResult> RunScenario(
   auto* servers = new ServerData[num_servers];
   for (size_t i = 0; i < num_servers; i++) {
     servers[i].stub =
-        Worker::NewStub(CreateChannel(workers[i], InsecureCredentials()));
+        WorkerService::NewStub(CreateChannel(workers[i], InsecureCredentials()));
     ServerArgs args;
     result_server_config = server_config;
     result_server_config.set_host(workers[i]);
@@ -189,7 +190,7 @@ std::unique_ptr<ScenarioResult> RunScenario(
   // where class contained in std::vector must have a copy constructor
   auto* clients = new ClientData[num_clients];
   for (size_t i = 0; i < num_clients; i++) {
-    clients[i].stub = Worker::NewStub(
+    clients[i].stub = WorkerService::NewStub(
         CreateChannel(workers[i + num_servers], InsecureCredentials()));
     ClientArgs args;
     result_client_config = client_config;
@@ -211,9 +212,9 @@ std::unique_ptr<ScenarioResult> RunScenario(
   // Start a run
   gpr_log(GPR_INFO, "Starting");
   ServerArgs server_mark;
-  server_mark.mutable_mark();
+  server_mark.mutable_mark()->set_reset(true);
   ClientArgs client_mark;
-  client_mark.mutable_mark();
+  client_mark.mutable_mark()->set_reset(true);
   for (auto server = &servers[0]; server != &servers[num_servers]; server++) {
     GPR_ASSERT(server->stream->Write(server_mark));
   }
diff --git a/test/cpp/qps/histogram.h b/test/cpp/qps/histogram.h
index 8ea9cb62e1a5208090b857997495936d17471f82..f7cb30871d23b7478ce1186d670e113cc1c2f23d 100644
--- a/test/cpp/qps/histogram.h
+++ b/test/cpp/qps/histogram.h
@@ -48,7 +48,7 @@ class Histogram {
   }
   Histogram(Histogram&& other) : impl_(other.impl_) { other.impl_ = nullptr; }
 
-  void Merge(Histogram* h) { gpr_histogram_merge(impl_, h->impl_); }
+  void Merge(const Histogram& h) { gpr_histogram_merge(impl_, h.impl_); }
   void Add(double value) { gpr_histogram_add(impl_, value); }
   double Percentile(double pctile) const {
     return gpr_histogram_percentile(impl_, pctile);
diff --git a/test/cpp/qps/qps_driver.cc b/test/cpp/qps/qps_driver.cc
index 3d352b4996e46174ce7980ed7a1053e604ed4af0..658cf873e8430237ff6a80c04dbf228e6dcca9c8 100644
--- a/test/cpp/qps/qps_driver.cc
+++ b/test/cpp/qps/qps_driver.cc
@@ -72,8 +72,6 @@ DEFINE_double(determ_load, -1.0, "Deterministic offered load (qps)");
 DEFINE_double(pareto_base, -1.0, "Pareto base interarrival time (us)");
 DEFINE_double(pareto_alpha, -1.0, "Pareto alpha value");
 
-DEFINE_string(load_type, "CLOSED_LOOP", "Load type");
-
 using grpc::testing::ClientConfig;
 using grpc::testing::ServerConfig;
 using grpc::testing::ClientType;
@@ -119,8 +117,8 @@ static void QpsDriver() {
     pareto->set_interarrival_base(FLAGS_pareto_base / 1e6);
     pareto->set_alpha(FLAGS_pareto_alpha);
   } else {
-    // Default is closed loop
-    // No need to set up any other load parameters here
+    client_config.mutable_load_params()->mutable_closed();
+    // No further load parameters to set up for closed loop
   }
 
   ServerConfig server_config;
diff --git a/test/cpp/qps/qps_test.cc b/test/cpp/qps/qps_test.cc
index c3dbc255740e440a185b9e839adb230110db99ba..82850e5dbe4a8c85bfb75bb660dd42485f49e437 100644
--- a/test/cpp/qps/qps_test.cc
+++ b/test/cpp/qps/qps_test.cc
@@ -58,6 +58,7 @@ static void RunQPS() {
   client_config.set_payload_size(1);
   client_config.set_async_client_threads(8);
   client_config.set_rpc_type(UNARY);
+  client_config.mutable_load_params()->mutable_closed();
 
   ServerConfig server_config;
   server_config.set_server_type(ASYNC_SERVER);
diff --git a/test/cpp/qps/qps_test_with_poll.cc b/test/cpp/qps/qps_test_with_poll.cc
index a7a11a615cc65a0451b78a383e32022b909ff9c5..153cbd7cea061256b7a44599457e526ed54b689e 100644
--- a/test/cpp/qps/qps_test_with_poll.cc
+++ b/test/cpp/qps/qps_test_with_poll.cc
@@ -62,6 +62,7 @@ static void RunQPS() {
   client_config.set_payload_size(1);
   client_config.set_async_client_threads(8);
   client_config.set_rpc_type(UNARY);
+  client_config.mutable_load_params()->mutable_closed();
 
   ServerConfig server_config;
   server_config.set_server_type(ASYNC_SERVER);
diff --git a/test/cpp/qps/qps_worker.cc b/test/cpp/qps/qps_worker.cc
index f16740b18d7b660bb76595acf1462cd9c79871ad..76b4c9b875fb5c0a5a07fd66ffb73864b965194f 100644
--- a/test/cpp/qps/qps_worker.cc
+++ b/test/cpp/qps/qps_worker.cc
@@ -52,10 +52,10 @@
 #include <grpc++/security/server_credentials.h>
 
 #include "test/core/util/grpc_profiler.h"
-#include "test/proto/perf_tests/perf_control.pb.h"
 #include "test/cpp/qps/client.h"
 #include "test/cpp/qps/server.h"
 #include "test/cpp/util/create_test_channel.h"
+#include "test/proto/perf_tests/perf_services.pb.h"
 
 namespace grpc {
 namespace testing {
@@ -89,9 +89,9 @@ std::unique_ptr<Server> CreateServer(const ServerConfig& config,
   abort();
 }
 
-class WorkerImpl GRPC_FINAL : public Worker::Service {
+class WorkerServiceImpl GRPC_FINAL : public WorkerService::Service {
  public:
-  explicit WorkerImpl(int server_port)
+  explicit WorkerServiceImpl(int server_port)
       : server_port_(server_port), acquired_(false) {}
 
   Status RunClient(ServerContext* ctx,
@@ -126,7 +126,7 @@ class WorkerImpl GRPC_FINAL : public Worker::Service {
   // Protect against multiple clients using this worker at once.
   class InstanceGuard {
    public:
-    InstanceGuard(WorkerImpl* impl)
+    InstanceGuard(WorkerServiceImpl* impl)
         : impl_(impl), acquired_(impl->TryAcquireInstance()) {}
     ~InstanceGuard() {
       if (acquired_) {
@@ -137,7 +137,7 @@ class WorkerImpl GRPC_FINAL : public Worker::Service {
     bool Acquired() const { return acquired_; }
 
    private:
-    WorkerImpl* const impl_;
+    WorkerServiceImpl* const impl_;
     const bool acquired_;
   };
 
@@ -175,7 +175,7 @@ class WorkerImpl GRPC_FINAL : public Worker::Service {
       if (!args.has_mark()) {
         return Status(StatusCode::INVALID_ARGUMENT, "");
       }
-      *status.mutable_stats() = client->Mark();
+      *status.mutable_stats() = client->Mark(args.mark().reset());
       stream->Write(status);
     }
 
@@ -204,7 +204,7 @@ class WorkerImpl GRPC_FINAL : public Worker::Service {
       if (!args.has_mark()) {
         return Status(StatusCode::INVALID_ARGUMENT, "");
       }
-      *status.mutable_stats() = server->Mark();
+      *status.mutable_stats() = server->Mark(args.mark().reset());
       stream->Write(status);
     }
 
@@ -218,7 +218,7 @@ class WorkerImpl GRPC_FINAL : public Worker::Service {
 };
 
 QpsWorker::QpsWorker(int driver_port, int server_port) {
-  impl_.reset(new WorkerImpl(server_port));
+  impl_.reset(new WorkerServiceImpl(server_port));
 
   char* server_address = NULL;
   gpr_join_host_port(&server_address, "::", driver_port);
diff --git a/test/cpp/qps/qps_worker.h b/test/cpp/qps/qps_worker.h
index 861588907ecbc390010a4b946889446dd87a3564..d5a7d7df1c5f645f9d58539c7ee8370d4a878784 100644
--- a/test/cpp/qps/qps_worker.h
+++ b/test/cpp/qps/qps_worker.h
@@ -42,7 +42,7 @@ class Server;
 
 namespace testing {
 
-class WorkerImpl;
+class WorkerServiceImpl;
 
 class QpsWorker {
  public:
@@ -50,7 +50,7 @@ class QpsWorker {
   ~QpsWorker();
 
  private:
-  std::unique_ptr<WorkerImpl> impl_;
+  std::unique_ptr<WorkerServiceImpl> impl_;
   std::unique_ptr<Server> server_;
 };
 
diff --git a/test/cpp/qps/server.h b/test/cpp/qps/server.h
index ba8394badc35eeca2590adeb29fd843a40aff339..c99ef97564fb5798babfed6a354d10def117beb5 100644
--- a/test/cpp/qps/server.h
+++ b/test/cpp/qps/server.h
@@ -35,6 +35,7 @@
 #define TEST_QPS_SERVER_H
 
 #include "test/cpp/qps/timer.h"
+#include "test/proto/messages.grpc.pb.h"
 #include "test/proto/perf_tests/perf_control.grpc.pb.h"
 
 namespace grpc {
@@ -45,11 +46,15 @@ class Server {
   Server() : timer_(new Timer) {}
   virtual ~Server() {}
 
-  ServerStats Mark() {
-    std::unique_ptr<Timer> timer(new Timer);
-    timer.swap(timer_);
-
-    auto timer_result = timer->Mark();
+  ServerStats Mark(bool reset) {
+    Timer::Result timer_result;
+    if (reset) {
+      std::unique_ptr<Timer> timer(new Timer);
+      timer.swap(timer_);
+      timer_result = timer->Mark();
+    } else {
+      timer_result = timer_->Mark();
+    }
 
     ServerStats stats;
     stats.set_time_elapsed(timer_result.wall);
diff --git a/test/cpp/qps/server_async.cc b/test/cpp/qps/server_async.cc
index db5218629af9cfb55659f5be74b6e0ae27a6f1f1..2aee7294d4fef45698e1dffdf043fa3a9e795401 100644
--- a/test/cpp/qps/server_async.cc
+++ b/test/cpp/qps/server_async.cc
@@ -49,8 +49,8 @@
 #include <grpc++/security/server_credentials.h>
 #include <gtest/gtest.h>
 
-#include "test/proto/perf_tests/perf_control.grpc.pb.h"
 #include "test/cpp/qps/server.h"
+#include "test/proto/perf_tests/perf_services.grpc.pb.h"
 
 namespace grpc {
 namespace testing {
@@ -76,10 +76,10 @@ class AsyncQpsServerTest : public Server {
     for (int i = 0; i < 10000 / config.threads(); i++) {
       for (int j = 0; j < config.threads(); j++) {
         auto request_unary = std::bind(
-            &TestService::AsyncService::RequestUnaryCall, &async_service_, _1,
+            &BenchmarkService::AsyncService::RequestUnaryCall, &async_service_, _1,
             _2, _3, srv_cqs_[j].get(), srv_cqs_[j].get(), _4);
         auto request_streaming = std::bind(
-            &TestService::AsyncService::RequestStreamingCall, &async_service_,
+            &BenchmarkService::AsyncService::RequestStreamingCall, &async_service_,
             _1, _2, srv_cqs_[j].get(), srv_cqs_[j].get(), _3);
         contexts_.push_front(
             new ServerRpcContextUnaryImpl<SimpleRequest, SimpleResponse>(
@@ -309,7 +309,7 @@ class AsyncQpsServerTest : public Server {
   std::vector<std::thread> threads_;
   std::unique_ptr<grpc::Server> server_;
   std::vector<std::unique_ptr<grpc::ServerCompletionQueue>> srv_cqs_;
-  TestService::AsyncService async_service_;
+  BenchmarkService::AsyncService async_service_;
   std::forward_list<ServerRpcContext *> contexts_;
 
   class PerThreadShutdownState {
diff --git a/test/cpp/qps/server_sync.cc b/test/cpp/qps/server_sync.cc
index 2b83548d19e5598858c6feae04865a7e06820957..20da139826a3af697ad10d31225f3e2e6be88091 100644
--- a/test/cpp/qps/server_sync.cc
+++ b/test/cpp/qps/server_sync.cc
@@ -43,14 +43,14 @@
 #include <grpc++/server_context.h>
 #include <grpc++/security/server_credentials.h>
 
-#include "test/proto/perf_tests/perf_control.grpc.pb.h"
 #include "test/cpp/qps/server.h"
 #include "test/cpp/qps/timer.h"
+#include "test/proto/perf_tests/perf_services.grpc.pb.h"
 
 namespace grpc {
 namespace testing {
 
-class TestServiceImpl GRPC_FINAL : public TestService::Service {
+class BenchmarkServiceImpl GRPC_FINAL : public BenchmarkService::Service {
  public:
   Status UnaryCall(ServerContext* context, const SimpleRequest* request,
                    SimpleResponse* response) GRPC_OVERRIDE {
@@ -101,7 +101,7 @@ class SynchronousServer GRPC_FINAL : public grpc::testing::Server {
     return builder.BuildAndStart();
   }
 
-  TestServiceImpl service_;
+  BenchmarkServiceImpl service_;
   std::unique_ptr<grpc::Server> impl_;
 };
 
diff --git a/test/cpp/qps/sync_streaming_ping_pong_test.cc b/test/cpp/qps/sync_streaming_ping_pong_test.cc
index 6dddb9ef228a426cdb3a5253e129577f1d936055..ce10a87ab3742d870c8b6b93332e1bd555a61948 100644
--- a/test/cpp/qps/sync_streaming_ping_pong_test.cc
+++ b/test/cpp/qps/sync_streaming_ping_pong_test.cc
@@ -57,6 +57,7 @@ static void RunSynchronousStreamingPingPong() {
   client_config.set_client_channels(1);
   client_config.set_payload_size(1);
   client_config.set_rpc_type(STREAMING);
+  client_config.mutable_load_params()->mutable_closed();
 
   ServerConfig server_config;
   server_config.set_server_type(SYNCHRONOUS_SERVER);
diff --git a/test/cpp/qps/sync_unary_ping_pong_test.cc b/test/cpp/qps/sync_unary_ping_pong_test.cc
index 774e70e19772d66135fcb6155489d837686f0591..c20e2c5ff0b178cf84693d7d390264cd33019c99 100644
--- a/test/cpp/qps/sync_unary_ping_pong_test.cc
+++ b/test/cpp/qps/sync_unary_ping_pong_test.cc
@@ -57,6 +57,7 @@ static void RunSynchronousUnaryPingPong() {
   client_config.set_client_channels(1);
   client_config.set_payload_size(1);
   client_config.set_rpc_type(UNARY);
+  client_config.mutable_load_params()->mutable_closed();
 
   ServerConfig server_config;
   server_config.set_server_type(SYNCHRONOUS_SERVER);
diff --git a/test/cpp/qps/timer.cc b/test/cpp/qps/timer.cc
index 8edb838da37dff75d5e64141660010ad509931d8..3ec7f49f8321d80b35b7195f7f3b4b12f06aa867 100644
--- a/test/cpp/qps/timer.cc
+++ b/test/cpp/qps/timer.cc
@@ -61,7 +61,7 @@ Timer::Result Timer::Sample() {
   return r;
 }
 
-Timer::Result Timer::Mark() {
+Timer::Result Timer::Mark() const {
   Result s = Sample();
   Result r;
   r.wall = s.wall - start_.wall;
diff --git a/test/cpp/qps/timer.h b/test/cpp/qps/timer.h
index 30dbd7e7d50dd6c5cdeefafc15f4f45c08696857..d1aee1a9d199ecb897eb91fae6657cbee6fdbcec 100644
--- a/test/cpp/qps/timer.h
+++ b/test/cpp/qps/timer.h
@@ -44,7 +44,7 @@ class Timer {
     double system;
   };
 
-  Result Mark();
+  Result Mark() const;
 
   static double Now();
 
diff --git a/test/proto/perf_tests/perf_control.proto b/test/proto/perf_tests/perf_control.proto
index 9c3e82285fcd1a554d08cbbf26e8ff28b9b35312..bfdbfacb124c3479c3a35476677f8e3f869781b3 100644
--- a/test/proto/perf_tests/perf_control.proto
+++ b/test/proto/perf_tests/perf_control.proto
@@ -31,7 +31,6 @@
 // of unary/streaming requests/responses.
 syntax = "proto3";
 
-import "test/proto/messages.proto";
 import "test/proto/perf_tests/perf_stats.proto";
 
 package grpc.testing;
@@ -69,14 +68,16 @@ message ParetoParams {
   double alpha = 2;
 }
 
+message ClosedLoopParams {
+}
+
 message LoadParams {
   oneof load {
     PoissonParams poisson = 1;
     UniformParams uniform = 2;
     DeterministicParams determ = 3;
     ParetoParams pareto = 4;
-    // No need to separately specify Closed-Loop as that
-    // will just be the absence of any of the above
+    ClosedLoopParams closed = 5;
   };
 }
 
@@ -100,6 +101,7 @@ message ClientStatus {
 
 // Request current stats
 message Mark {
+  bool reset = 1;
 }
 
 message ClientArgs {
@@ -127,21 +129,3 @@ message ServerStatus {
   ServerStats stats = 1;
   int32 port = 2;
 }
-
-service TestService {
-  // One request followed by one response.
-  // The server returns the client payload as-is.
-  rpc UnaryCall(SimpleRequest) returns (SimpleResponse);
-
-  // One request followed by one response.
-  // The server returns the client payload as-is.
-  rpc StreamingCall(stream SimpleRequest) returns (stream SimpleResponse);
-}
-
-service Worker {
-  // Start server with specified workload
-  rpc RunServer(stream ServerArgs) returns (stream ServerStatus);
-
-  // Start client with specified workload
-  rpc RunClient(stream ClientArgs) returns (stream ClientStatus);
-}
diff --git a/test/proto/perf_tests/perf_services.proto b/test/proto/perf_tests/perf_services.proto
new file mode 100644
index 0000000000000000000000000000000000000000..f9497e2f7586c6346c50c7acdba324765cb44d9f
--- /dev/null
+++ b/test/proto/perf_tests/perf_services.proto
@@ -0,0 +1,56 @@
+// 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.
+
+// An integration test service that covers all the method signature permutations
+// of unary/streaming requests/responses.
+syntax = "proto3";
+
+import "test/proto/messages.proto";
+import "test/proto/perf_tests/perf_stats.proto";
+import "test/proto/perf_tests/perf_control.proto";
+
+package grpc.testing;
+
+service BenchmarkService {
+  // One request followed by one response.
+  // The server returns the client payload as-is.
+  rpc UnaryCall(SimpleRequest) returns (SimpleResponse);
+
+  // One request followed by one response.
+  // The server returns the client payload as-is.
+  rpc StreamingCall(stream SimpleRequest) returns (stream SimpleResponse);
+}
+
+service WorkerService {
+  // Start server with specified workload
+  rpc RunServer(stream ServerArgs) returns (stream ServerStatus);
+
+  // Start client with specified workload
+  rpc RunClient(stream ClientArgs) returns (stream ClientStatus);
+}
diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json
index 60abb62e3a3a902b39e89139382f8e39f01ead6b..a3902cf38177918bf0d50921eaa3dc9b72dd47cc 100644
--- a/tools/run_tests/sources_and_headers.json
+++ b/tools/run_tests/sources_and_headers.json
@@ -13660,6 +13660,8 @@
       "test/proto/messages.pb.h", 
       "test/proto/perf_tests/perf_control.grpc.pb.h", 
       "test/proto/perf_tests/perf_control.pb.h", 
+      "test/proto/perf_tests/perf_services.grpc.pb.h", 
+      "test/proto/perf_tests/perf_services.pb.h", 
       "test/proto/perf_tests/perf_stats.grpc.pb.h", 
       "test/proto/perf_tests/perf_stats.pb.h"
     ], 
diff --git a/vsprojects/vcxproj/qps/qps.vcxproj b/vsprojects/vcxproj/qps/qps.vcxproj
index e1987dba5dd6a2451a0b5ea4a224e77b9fe7ba28..152ba7af6c50c525ce92ef4bf03dbc803eea9660 100644
--- a/vsprojects/vcxproj/qps/qps.vcxproj
+++ b/vsprojects/vcxproj/qps/qps.vcxproj
@@ -163,6 +163,14 @@
     </ClCompile>
     <ClInclude Include="..\..\..\test\proto\perf_tests\perf_control.grpc.pb.h">
     </ClInclude>
+    <ClCompile Include="..\..\..\test\proto\perf_tests\perf_services.pb.cc">
+    </ClCompile>
+    <ClInclude Include="..\..\..\test\proto\perf_tests\perf_services.pb.h">
+    </ClInclude>
+    <ClCompile Include="..\..\..\test\proto\perf_tests\perf_services.grpc.pb.cc">
+    </ClCompile>
+    <ClInclude Include="..\..\..\test\proto\perf_tests\perf_services.grpc.pb.h">
+    </ClInclude>
     <ClCompile Include="..\..\..\test\proto\perf_tests\perf_stats.pb.cc">
     </ClCompile>
     <ClInclude Include="..\..\..\test\proto\perf_tests\perf_stats.pb.h">
diff --git a/vsprojects/vcxproj/qps/qps.vcxproj.filters b/vsprojects/vcxproj/qps/qps.vcxproj.filters
index f679ad4d54314e1e6207f7d37514e2acf696cc02..8bbd5c35c2b577852eba1719fce05fde65ed9c4e 100644
--- a/vsprojects/vcxproj/qps/qps.vcxproj.filters
+++ b/vsprojects/vcxproj/qps/qps.vcxproj.filters
@@ -7,6 +7,9 @@
     <ClCompile Include="..\..\..\test\proto\perf_tests\perf_control.proto">
       <Filter>test\proto\perf_tests</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\..\test\proto\perf_tests\perf_services.proto">
+      <Filter>test\proto\perf_tests</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\..\test\proto\perf_tests\perf_stats.proto">
       <Filter>test\proto\perf_tests</Filter>
     </ClCompile>