diff --git a/Makefile b/Makefile
index 79dec086e49d385f83b1190187526fce0078b679..e7b784b857baeafc7be34b1af6d6eefacf9083a5 100644
--- a/Makefile
+++ b/Makefile
@@ -2674,6 +2674,21 @@ $(GENDIR)/examples/pubsub/pubsub.grpc.pb.cc: examples/pubsub/pubsub.proto $(PROT
 	$(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
 endif
 
+ifeq ($(NO_PROTOC),true)
+$(GENDIR)/test/cpp/qps/perf_db.pb.cc: protoc_dep_error
+$(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc: protoc_dep_error
+else
+$(GENDIR)/test/cpp/qps/perf_db.pb.cc: test/cpp/qps/perf_db.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
+	$(E) "[PROTOC]  Generating protobuf CC file from $<"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(PROTOC) --cpp_out=$(GENDIR) $<
+
+$(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc: test/cpp/qps/perf_db.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/cpp/qps/qpstest.pb.cc: protoc_dep_error
 $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc: protoc_dep_error
@@ -4244,9 +4259,11 @@ $(OBJDIR)/$(CONFIG)/examples/pubsub/subscriber.o: $(GENDIR)/examples/pubsub/labe
 
 LIBQPS_SRC = \
     $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.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 \
     test/cpp/qps/client_sync.cc \
     test/cpp/qps/driver.cc \
+    test/cpp/qps/perf_db_client.cc \
     test/cpp/qps/qps_worker.cc \
     test/cpp/qps/report.cc \
     test/cpp/qps/server_async.cc \
@@ -4296,15 +4313,16 @@ ifneq ($(NO_DEPS),true)
 -include $(LIBQPS_OBJS:.o=.dep)
 endif
 endif
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/client_async.o: $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/client_sync.o: $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/driver.o: $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/qps_worker.o: $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/report.o: $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/server_async.o: $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/server_sync.o: $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/timer.o: $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/util/benchmark_config.o: $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/client_async.o: $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.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/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.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/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.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/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.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/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.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/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.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/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.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/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.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/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.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/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.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.json b/build.json
index c77b7340bad2fecf771c650c30fdf17d2b69ed1d..19078ed72654c596282a64bbf7977c533eb66173 100644
--- a/build.json
+++ b/build.json
@@ -768,6 +768,7 @@
         "test/cpp/qps/driver.h",
         "test/cpp/qps/histogram.h",
         "test/cpp/qps/interarrival.h",
+        "test/cpp/qps/perf_db_client.h",
         "test/cpp/qps/qps_worker.h",
         "test/cpp/qps/report.h",
         "test/cpp/qps/server.h",
@@ -777,9 +778,11 @@
       ],
       "src": [
         "test/cpp/qps/qpstest.proto",
+        "test/cpp/qps/perf_db.proto",
         "test/cpp/qps/client_async.cc",
         "test/cpp/qps/client_sync.cc",
         "test/cpp/qps/driver.cc",
+        "test/cpp/qps/perf_db_client.cc",
         "test/cpp/qps/qps_worker.cc",
         "test/cpp/qps/report.cc",
         "test/cpp/qps/server_async.cc",
diff --git a/gRPC.podspec b/gRPC.podspec
index d96e65c1ba7f6a287b3a2bb5f6b7300868b46943..bdcbc3f612219a424190ad8bff7a6a3b367b75a3 100644
--- a/gRPC.podspec
+++ b/gRPC.podspec
@@ -524,9 +524,9 @@ Pod::Spec.new do |s|
     BAD_TIME="$DIR_TIME/time.h"
     GOOD_TIME="$DIR_TIME/grpc_time.h"
     grep -rl "$BAD_TIME" grpc src/core src/objective-c/GRPCClient | xargs sed -i '' -e s@$BAD_TIME@$GOOD_TIME@g
-    if [ -f "include/$BAD_TIME" ];
+    if [ -f "$BAD_TIME" ];
     then
-      mv -f "include/$BAD_TIME" "include/$GOOD_TIME"
+      mv -f "$BAD_TIME" "$GOOD_TIME"
     fi
 
     DIR_STRING="src/core/support"
diff --git a/src/core/transport/chttp2/incoming_metadata.c b/src/core/transport/chttp2/incoming_metadata.c
index a4b7174329ba73d8a1f9a147cdda356e5ff33347..68e0912b9ca89d8ea73b0a8a4467e9ea9b695864 100644
--- a/src/core/transport/chttp2/incoming_metadata.c
+++ b/src/core/transport/chttp2/incoming_metadata.c
@@ -124,6 +124,7 @@ void grpc_incoming_metadata_buffer_move_to_referencing_sopb(
     sopb->ops[i].data.metadata.list.tail =
         (void *)(delta + (gpr_intptr)sopb->ops[i].data.metadata.list.tail);
   }
+  src->count = 0;
 }
 
 void grpc_chttp2_incoming_metadata_buffer_postprocess_sopb_and_begin_live_op(
diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h
index 33aae1074759edc967d9eb6229c525a1c5702ecd..cba53fa2f67a0713e9769d042d1612f9f26a283b 100644
--- a/src/objective-c/GRPCClient/GRPCCall.h
+++ b/src/objective-c/GRPCClient/GRPCCall.h
@@ -48,8 +48,6 @@
 #import <Foundation/Foundation.h>
 #import <RxLibrary/GRXWriter.h>
 
-@class GRPCMethodName;
-
 // Key used in |NSError|'s |userInfo| dictionary to store the response metadata sent by the server.
 extern id const kGRPCStatusMetadataKey;
 
@@ -90,7 +88,7 @@ extern id const kGRPCStatusMetadataKey;
 // the specific remote method called).
 // To finish a call right away, invoke cancel.
 - (instancetype)initWithHost:(NSString *)host
-                      method:(GRPCMethodName *)method
+                        path:(NSString *)path
               requestsWriter:(id<GRXWriter>)requestsWriter NS_DESIGNATED_INITIALIZER;
 
 // Finishes the request side of this call, notifies the server that the RPC
diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m
index 77eebeff7615cc12d36aa4de756990be33e6fa29..4ac4e4d37f5ca3fc11bb8d6fc80cbcc1fd4a47a8 100644
--- a/src/objective-c/GRPCClient/GRPCCall.m
+++ b/src/objective-c/GRPCClient/GRPCCall.m
@@ -36,11 +36,9 @@
 #include <grpc/grpc.h>
 #include <grpc/support/time.h>
 
-#import "GRPCMethodName.h"
 #import "private/GRPCChannel.h"
 #import "private/GRPCCompletionQueue.h"
 #import "private/GRPCDelegateWrapper.h"
-#import "private/GRPCMethodName+HTTP2Encoding.h"
 #import "private/GRPCWrappedCall.h"
 #import "private/NSData+GRPC.h"
 #import "private/NSDictionary+GRPC.h"
@@ -90,14 +88,14 @@ NSString * const kGRPCStatusMetadataKey = @"io.grpc.StatusMetadataKey";
 @synthesize state = _state;
 
 - (instancetype)init {
-  return [self initWithHost:nil method:nil requestsWriter:nil];
+  return [self initWithHost:nil path:nil requestsWriter:nil];
 }
 
 // Designated initializer
 - (instancetype)initWithHost:(NSString *)host
-                      method:(GRPCMethodName *)method
+                        path:(NSString *)path
               requestsWriter:(id<GRXWriter>)requestWriter {
-  if (!host || !method) {
+  if (!host || !path) {
     [NSException raise:NSInvalidArgumentException format:@"Neither host nor method can be nil."];
   }
   if (requestWriter.state != GRXWriterStateNotStarted) {
@@ -114,7 +112,7 @@ NSString * const kGRPCStatusMetadataKey = @"io.grpc.StatusMetadataKey";
     _channel = [GRPCChannel channelToHost:host];
 
     _wrappedCall = [[GRPCWrappedCall alloc] initWithChannel:_channel
-                                                     method:method.HTTP2Path
+                                                       path:path
                                                        host:host];
 
     // Serial queue to invoke the non-reentrant methods of the grpc_call object.
diff --git a/src/objective-c/GRPCClient/private/GRPCMethodName+HTTP2Encoding.h b/src/objective-c/GRPCClient/private/GRPCMethodName+HTTP2Encoding.h
deleted file mode 100644
index 81c80f2a49228769b0b18ced30b942c6c26bfcf7..0000000000000000000000000000000000000000
--- a/src/objective-c/GRPCClient/private/GRPCMethodName+HTTP2Encoding.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- *
- * 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.
- *
- */
-
-#import <Foundation/Foundation.h>
-
-#import "GRPCClient/GRPCMethodName.h"
-
-@interface GRPCMethodName (HTTP2Encoding)
-- (NSString *)HTTP2Path;
-@end
diff --git a/src/objective-c/GRPCClient/private/GRPCMethodName+HTTP2Encoding.m b/src/objective-c/GRPCClient/private/GRPCMethodName+HTTP2Encoding.m
deleted file mode 100644
index 3ad757fb29a64eca92627aec5ef45a5dbae9e293..0000000000000000000000000000000000000000
--- a/src/objective-c/GRPCClient/private/GRPCMethodName+HTTP2Encoding.m
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- *
- * 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.
- *
- */
-
-#import "GRPCMethodName+HTTP2Encoding.h"
-
-@implementation GRPCMethodName (HTTP2Encoding)
-- (NSString *)HTTP2Path {
-  if (self.package) {
-    return [NSString stringWithFormat:@"/%@.%@/%@", self.package, self.interface, self.method];
-  } else {
-    return [NSString stringWithFormat:@"/%@/%@", self.interface, self.method];
-  }
-}
-@end
diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.h b/src/objective-c/GRPCClient/private/GRPCWrappedCall.h
index c08aefc6a8fc8557c24da82393651632daf52f08..18f8bb553101f329811374b08c58a9e513d7a923 100644
--- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.h
+++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.h
@@ -84,7 +84,7 @@
 @interface GRPCWrappedCall : NSObject
 
 - (instancetype)initWithChannel:(GRPCChannel *)channel
-                         method:(NSString *)method
+                           path:(NSString *)path
                            host:(NSString *)host NS_DESIGNATED_INITIALIZER;
 
 - (void)startBatchWithOperations:(NSArray *)ops errorHandler:(void(^)())errorHandler;
diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m
index d94b25091e6a02615256c44e9dae2e9e0fc83e41..45f10f5d63db226a6381df715e1905656f2f4742 100644
--- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m
+++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m
@@ -225,13 +225,13 @@
 }
 
 - (instancetype)init {
-  return [self initWithChannel:nil method:nil host:nil];
+  return [self initWithChannel:nil path:nil host:nil];
 }
 
 - (instancetype)initWithChannel:(GRPCChannel *)channel
-                         method:(NSString *)method
+                           path:(NSString *)path
                            host:(NSString *)host {
-  if (!channel || !method || !host) {
+  if (!channel || !path || !host) {
     [NSException raise:NSInvalidArgumentException
                 format:@"channel, method, and host cannot be nil."];
   }
@@ -247,7 +247,7 @@
       return nil;
     }
     _call = grpc_channel_create_call(channel.unmanagedChannel, _queue.unmanagedQueue,
-                                     method.UTF8String, host.UTF8String, gpr_inf_future);
+                                     path.UTF8String, host.UTF8String, gpr_inf_future);
     if (_call == NULL) {
       return nil;
     }
diff --git a/src/objective-c/GRPCClient/GRPCMethodName.h b/src/objective-c/ProtoRPC/ProtoMethod.h
similarity index 80%
rename from src/objective-c/GRPCClient/GRPCMethodName.h
rename to src/objective-c/ProtoRPC/ProtoMethod.h
index fe153dd478b2cacd48d6f0079a24191652dd7718..8f554a04832d9298aaf9380064e61e5ecde1efd0 100644
--- a/src/objective-c/GRPCClient/GRPCMethodName.h
+++ b/src/objective-c/ProtoRPC/ProtoMethod.h
@@ -33,17 +33,16 @@
 
 #import <Foundation/Foundation.h>
 
-// See the README file for an introduction to this library.
-
-// A fully-qualified gRPC method name. Full qualification is needed because a gRPC endpoint can
-// implement multiple interfaces.
-// TODO(jcanizales): Move to ProtoRPC package.
-// TODO(jcanizales): Rename interface -> service.
-@interface GRPCMethodName : NSObject
+// A fully-qualified proto service method name. Full qualification is needed because a gRPC endpoint
+// can implement multiple services.
+@interface ProtoMethod : NSObject
 @property(nonatomic, readonly) NSString *package;
-@property(nonatomic, readonly) NSString *interface;
+@property(nonatomic, readonly) NSString *service;
 @property(nonatomic, readonly) NSString *method;
+
+@property(nonatomic, readonly) NSString *HTTPPath;
+
 - (instancetype)initWithPackage:(NSString *)package
-                      interface:(NSString *)interface
+                        service:(NSString *)service
                          method:(NSString *)method;
 @end
diff --git a/src/objective-c/GRPCClient/GRPCMethodName.m b/src/objective-c/ProtoRPC/ProtoMethod.m
similarity index 83%
rename from src/objective-c/GRPCClient/GRPCMethodName.m
rename to src/objective-c/ProtoRPC/ProtoMethod.m
index 96724073a5f387ad85e2f8572dfed39f2780543a..1113b4fbaa3ce74dcd2c5b8062ec0a5a67685ff1 100644
--- a/src/objective-c/GRPCClient/GRPCMethodName.m
+++ b/src/objective-c/ProtoRPC/ProtoMethod.m
@@ -31,17 +31,25 @@
  *
  */
 
-#import "GRPCMethodName.h"
+#import "ProtoMethod.h"
 
-@implementation GRPCMethodName
+@implementation ProtoMethod
 - (instancetype)initWithPackage:(NSString *)package
-                      interface:(NSString *)interface
+                        service:(NSString *)service
                          method:(NSString *)method {
   if ((self = [super init])) {
     _package = [package copy];
-    _interface = [interface copy];
+    _service = [service copy];
     _method = [method copy];
   }
   return self;
 }
+
+- (NSString *)HTTPPath {
+  if (_package) {
+    return [NSString stringWithFormat:@"/%@.%@/%@", _package, _service, _method];
+  } else {
+    return [NSString stringWithFormat:@"/%@/%@", _service, _method];
+  }
+}
 @end
diff --git a/src/objective-c/ProtoRPC/ProtoRPC.h b/src/objective-c/ProtoRPC/ProtoRPC.h
index a3833106195f01fd446e9c947f851a974461bea9..fcc0a507feb0528814534057f25a6db9f33b2117 100644
--- a/src/objective-c/ProtoRPC/ProtoRPC.h
+++ b/src/objective-c/ProtoRPC/ProtoRPC.h
@@ -34,10 +34,12 @@
 #import <Foundation/Foundation.h>
 #import <GRPCClient/GRPCCall.h>
 
+#import "ProtoMethod.h"
+
 @interface ProtoRPC : GRPCCall
 
 - (instancetype)initWithHost:(NSString *)host
-                      method:(GRPCMethodName *)method
+                      method:(ProtoMethod *)method
               requestsWriter:(id<GRXWriter>)requestsWriter
                responseClass:(Class)responseClass
           responsesWriteable:(id<GRXWriteable>)responsesWriteable NS_DESIGNATED_INITIALIZER;
diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m
index 4da646d7b453e1ab300c594e1d74b0a84ed6bfec..fe3ccf054139870f96aa8c552d10b12eddca55c2 100644
--- a/src/objective-c/ProtoRPC/ProtoRPC.m
+++ b/src/objective-c/ProtoRPC/ProtoRPC.m
@@ -42,19 +42,20 @@
   id<GRXWriteable> _responseWriteable;
 }
 
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wobjc-designated-initializers"
 - (instancetype)initWithHost:(NSString *)host
-                      method:(GRPCMethodName *)method
+                        path:(NSString *)path
               requestsWriter:(id<GRXWriter>)requestsWriter {
-  return [self initWithHost:host
-                     method:method
-             requestsWriter:requestsWriter
-              responseClass:nil
-        responsesWriteable:nil];
+  [NSException raise:NSInvalidArgumentException
+              format:@"Please use ProtoRPC's designated initializer instead."];
+  return nil;
 }
+#pragma clang diagnostic pop
 
 // Designated initializer
 - (instancetype)initWithHost:(NSString *)host
-                      method:(GRPCMethodName *)method
+                      method:(ProtoMethod *)method
               requestsWriter:(id<GRXWriter>)requestsWriter
                responseClass:(Class)responseClass
           responsesWriteable:(id<GRXWriteable>)responsesWriteable {
@@ -70,7 +71,7 @@
         // sending GPBMessages.
         return [proto data];
       }];
-  if ((self = [super initWithHost:host method:method requestsWriter:bytesWriter])) {
+  if ((self = [super initWithHost:host path:method.HTTPPath requestsWriter:bytesWriter])) {
     // A writeable that parses the proto messages received.
     _responseWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
       [responsesWriteable writeValue:[responseClass parseFromData:value error:NULL]];
diff --git a/src/objective-c/ProtoRPC/ProtoService.m b/src/objective-c/ProtoRPC/ProtoService.m
index 47bdb5dc6e87ae27c6a9332eee6179aeec7ff030..d7c5b6a8501dc0e83fc113fd842b05695facf8d9 100644
--- a/src/objective-c/ProtoRPC/ProtoService.m
+++ b/src/objective-c/ProtoRPC/ProtoService.m
@@ -33,10 +33,10 @@
 
 #import "ProtoService.h"
 
-#import <GRPCClient/GRPCMethodName.h>
 #import <RxLibrary/GRXWriteable.h>
 #import <RxLibrary/GRXWriter.h>
 
+#import "ProtoMethod.h"
 #import "ProtoRPC.h"
 
 @implementation ProtoService {
@@ -69,9 +69,9 @@
            requestsWriter:(id<GRXWriter>)requestsWriter
             responseClass:(Class)responseClass
        responsesWriteable:(id<GRXWriteable>)responsesWriteable {
-  GRPCMethodName *methodName = [[GRPCMethodName alloc] initWithPackage:_packageName
-                                                             interface:_serviceName
-                                                                method:method];
+  ProtoMethod *methodName = [[ProtoMethod alloc] initWithPackage:_packageName
+                                                         service:_serviceName
+                                                          method:method];
   return [[ProtoRPC alloc] initWithHost:_host
                                  method:methodName
                          requestsWriter:requestsWriter
diff --git a/src/objective-c/tests/GRPCClientTests.m b/src/objective-c/tests/GRPCClientTests.m
index e421127ea1ece2fcc168e4d507f4d183f049cf58..f9c2d5d8d6e1445b25891bc38470aaaa84b63a04 100644
--- a/src/objective-c/tests/GRPCClientTests.m
+++ b/src/objective-c/tests/GRPCClientTests.m
@@ -35,7 +35,7 @@
 #import <XCTest/XCTest.h>
 
 #import <GRPCClient/GRPCCall.h>
-#import <GRPCClient/GRPCMethodName.h>
+#import <ProtoRPC/ProtoMethod.h>
 #import <RemoteTest/Messages.pbobjc.h>
 #import <RxLibrary/GRXWriteable.h>
 #import <RxLibrary/GRXWriter+Immediate.h>
@@ -47,9 +47,9 @@ static NSString * const kHostAddress = @"grpc-test.sandbox.google.com";
 static NSString * const kPackage = @"grpc.testing";
 static NSString * const kService = @"TestService";
 
-static GRPCMethodName *kInexistentMethod;
-static GRPCMethodName *kEmptyCallMethod;
-static GRPCMethodName *kUnaryCallMethod;
+static ProtoMethod *kInexistentMethod;
+static ProtoMethod *kEmptyCallMethod;
+static ProtoMethod *kUnaryCallMethod;
 
 @interface GRPCClientTests : XCTestCase
 @end
@@ -58,22 +58,22 @@ static GRPCMethodName *kUnaryCallMethod;
 
 - (void)setUp {
   // This method isn't implemented by the remote server.
-  kInexistentMethod = [[GRPCMethodName alloc] initWithPackage:kPackage
-                                                    interface:kService
-                                                       method:@"Inexistent"];
-  kEmptyCallMethod = [[GRPCMethodName alloc] initWithPackage:kPackage
-                                                   interface:kService
-                                                      method:@"EmptyCall"];
-  kUnaryCallMethod = [[GRPCMethodName alloc] initWithPackage:kPackage
-                                                   interface:kService
-                                                      method:@"UnaryCall"];
+  kInexistentMethod = [[ProtoMethod alloc] initWithPackage:kPackage
+                                                   service:kService
+                                                    method:@"Inexistent"];
+  kEmptyCallMethod = [[ProtoMethod alloc] initWithPackage:kPackage
+                                                  service:kService
+                                                   method:@"EmptyCall"];
+  kUnaryCallMethod = [[ProtoMethod alloc] initWithPackage:kPackage
+                                                  service:kService
+                                                   method:@"UnaryCall"];
 }
 
 - (void)testConnectionToRemoteServer {
   __weak XCTestExpectation *expectation = [self expectationWithDescription:@"Server reachable."];
 
   GRPCCall *call = [[GRPCCall alloc] initWithHost:kHostAddress
-                                           method:kInexistentMethod
+                                             path:kInexistentMethod.HTTPPath
                                    requestsWriter:[GRXWriter writerWithValue:[NSData data]]];
 
   id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
@@ -95,7 +95,7 @@ static GRPCMethodName *kUnaryCallMethod;
   __weak XCTestExpectation *completion = [self expectationWithDescription:@"Empty RPC completed."];
 
   GRPCCall *call = [[GRPCCall alloc] initWithHost:kHostAddress
-                                           method:kEmptyCallMethod
+                                             path:kEmptyCallMethod.HTTPPath
                                    requestsWriter:[GRXWriter writerWithValue:[NSData data]]];
 
   id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
@@ -123,7 +123,7 @@ static GRPCMethodName *kUnaryCallMethod;
   id<GRXWriter> requestsWriter = [GRXWriter writerWithValue:[request data]];
 
   GRPCCall *call = [[GRPCCall alloc] initWithHost:kHostAddress
-                                           method:kUnaryCallMethod
+                                             path:kUnaryCallMethod.HTTPPath
                                    requestsWriter:requestsWriter];
 
   id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
@@ -153,7 +153,7 @@ static GRPCMethodName *kUnaryCallMethod;
   id<GRXWriter> requestsWriter = [GRXWriter writerWithValue:[request data]];
 
   GRPCCall *call = [[GRPCCall alloc] initWithHost:kHostAddress
-                                           method:kUnaryCallMethod
+                                             path:kUnaryCallMethod.HTTPPath
                                    requestsWriter:requestsWriter];
 
   call.requestMetadata[@"Authorization"] = @"Bearer bogusToken";
diff --git a/src/objective-c/tests/LocalClearTextTests.m b/src/objective-c/tests/LocalClearTextTests.m
index 05cc10410a1157bda9e63643dbc24d804a9ef77d..10c9f13ea3bbdf3d885d0677f94248a772ce3b33 100644
--- a/src/objective-c/tests/LocalClearTextTests.m
+++ b/src/objective-c/tests/LocalClearTextTests.m
@@ -35,7 +35,7 @@
 #import <XCTest/XCTest.h>
 
 #import <GRPCClient/GRPCCall.h>
-#import <GRPCClient/GRPCMethodName.h>
+#import <ProtoRPC/ProtoMethod.h>
 #import <RouteGuide/RouteGuide.pbobjc.h>
 #import <RouteGuide/RouteGuide.pbrpc.h>
 #import <RxLibrary/GRXWriteable.h>
@@ -87,14 +87,14 @@ static NSString * const kService = @"RouteGuide";
   __weak XCTestExpectation *response = [self expectationWithDescription:@"Empty response received."];
   __weak XCTestExpectation *completion = [self expectationWithDescription:@"Empty RPC completed."];
 
-  GRPCMethodName *method = [[GRPCMethodName alloc] initWithPackage:kPackage
-                                                         interface:kService
-                                                            method:@"RecordRoute"];
+  ProtoMethod *method = [[ProtoMethod alloc] initWithPackage:kPackage
+                                                     service:kService
+                                                      method:@"RecordRoute"];
 
   id<GRXWriter> requestsWriter = [GRXWriter emptyWriter];
 
   GRPCCall *call = [[GRPCCall alloc] initWithHost:kRouteGuideHost
-                                           method:method
+                                             path:method.HTTPPath
                                    requestsWriter:requestsWriter];
 
   id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
@@ -115,9 +115,9 @@ static NSString * const kService = @"RouteGuide";
   __weak XCTestExpectation *response = [self expectationWithDescription:@"Response received."];
   __weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."];
 
-  GRPCMethodName *method = [[GRPCMethodName alloc] initWithPackage:kPackage
-                                                         interface:kService
-                                                            method:@"GetFeature"];
+  ProtoMethod *method = [[ProtoMethod alloc] initWithPackage:kPackage
+                                                     service:kService
+                                                      method:@"GetFeature"];
 
   RGDPoint *point = [RGDPoint message];
   point.latitude = 28E7;
@@ -125,7 +125,7 @@ static NSString * const kService = @"RouteGuide";
   id<GRXWriter> requestsWriter = [GRXWriter writerWithValue:[point data]];
 
   GRPCCall *call = [[GRPCCall alloc] initWithHost:kRouteGuideHost
-                                           method:method
+                                             path:method.HTTPPath
                                    requestsWriter:requestsWriter];
 
   id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
diff --git a/templates/gRPC.podspec.template b/templates/gRPC.podspec.template
index deea07cee35695fb7b2a9a12f14c2ba6cf57fe83..495ea49c9c229de4f1a2c9e2f1f9405962e4e182 100644
--- a/templates/gRPC.podspec.template
+++ b/templates/gRPC.podspec.template
@@ -111,9 +111,9 @@ Pod::Spec.new do |s|
     BAD_TIME="$DIR_TIME/time.h"
     GOOD_TIME="$DIR_TIME/grpc_time.h"
     grep -rl "$BAD_TIME" grpc src/core src/objective-c/GRPCClient | xargs sed -i '' -e s@$BAD_TIME@$GOOD_TIME@g
-    if [ -f "include/$BAD_TIME" ];
+    if [ -f "$BAD_TIME" ];
     then
-      mv -f "include/$BAD_TIME" "include/$GOOD_TIME"
+      mv -f "$BAD_TIME" "$GOOD_TIME"
     fi
 
     DIR_STRING="src/core/support"
diff --git a/test/cpp/qps/perf_db.proto b/test/cpp/qps/perf_db.proto
new file mode 100644
index 0000000000000000000000000000000000000000..60e038406a8a1a22e91db5c9c19f60c05f906c2d
--- /dev/null
+++ b/test/cpp/qps/perf_db.proto
@@ -0,0 +1,71 @@
+// 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.
+
+syntax = "proto3";
+
+import "test/cpp/qps/qpstest.proto";
+
+package grpc.testing;
+
+service PerfDbTransfer {
+  // Sends client info
+  rpc RecordSingleClientData(SingleUserRecordRequest)
+      returns (SingleUserRecordReply) {
+  }
+}
+
+// Metrics to be stored
+message Metrics {
+  double qps = 1;
+  double qps_per_core = 2;
+  double perc_lat_50 = 3;
+  double perc_lat_90 = 4;
+  double perc_lat_95 = 5;
+  double perc_lat_99 = 6;
+  double perc_lat_99_point_9 = 7;
+  double server_system_time = 8;
+  double server_user_time = 9;
+  double client_system_time = 10;
+  double client_user_time = 11;
+}
+
+// Request for storing a single user's data
+message SingleUserRecordRequest {
+  string hashed_id = 1;
+  string test_name = 2;
+  string sys_info = 3;
+  string tag = 4;
+  Metrics metrics = 5;
+  ClientConfig client_config = 6;
+  ServerConfig server_config = 7;
+}
+
+// Reply to request for storing single user's data
+message SingleUserRecordReply {
+}
diff --git a/test/cpp/qps/perf_db_client.cc b/test/cpp/qps/perf_db_client.cc
new file mode 100644
index 0000000000000000000000000000000000000000..08d20f0b8d809fdfbc52c754b0af2065d30278a5
--- /dev/null
+++ b/test/cpp/qps/perf_db_client.cc
@@ -0,0 +1,143 @@
+/*
+ *
+ * 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/perf_db_client.h"
+
+namespace grpc {
+namespace testing {
+
+// sets the client and server config information
+void PerfDbClient::setConfigs(const ClientConfig& client_config,
+                              const ServerConfig& server_config) {
+  client_config_ = client_config;
+  server_config_ = server_config;
+}
+
+// sets the QPS
+void PerfDbClient::setQps(double qps) {
+  qps_ = qps;
+}
+
+// sets the QPS per core
+void PerfDbClient::setQpsPerCore(double qps_per_core) {
+  qps_per_core_ = qps_per_core;
+}
+
+// sets the 50th, 90th, 95th, 99th and 99.9th percentile latency
+void PerfDbClient::setLatencies(double perc_lat_50,
+                                double perc_lat_90,
+                                double perc_lat_95,
+                                double perc_lat_99,
+                                double perc_lat_99_point_9) {
+  perc_lat_50_ = perc_lat_50;
+  perc_lat_90_ = perc_lat_90;
+  perc_lat_95_ = perc_lat_95;
+  perc_lat_99_ = perc_lat_99;
+  perc_lat_99_point_9_ = perc_lat_99_point_9;
+}
+
+// sets the server and client, user and system times
+void PerfDbClient::setTimes(double server_system_time, double server_user_time,
+                            double client_system_time, double client_user_time) {
+  server_system_time_ = server_system_time;
+  server_user_time_ = server_user_time;
+  client_system_time_ = client_system_time;
+  client_user_time_ = client_user_time;
+}
+
+// sends the data to the performance database server
+bool PerfDbClient::sendData(std::string hashed_id, std::string test_name,
+                            std::string sys_info, std::string tag) {
+  // Data record request object
+  SingleUserRecordRequest single_user_record_request;
+
+  // setting access token, name of the test and the system information
+  single_user_record_request.set_hashed_id(hashed_id);
+  single_user_record_request.set_test_name(test_name);
+  single_user_record_request.set_sys_info(sys_info);
+  single_user_record_request.set_tag(tag);
+
+  // setting configs
+  *(single_user_record_request.mutable_client_config()) = client_config_;
+  *(single_user_record_request.mutable_server_config()) = server_config_;
+
+  Metrics* metrics = single_user_record_request.mutable_metrics();
+
+  // setting metrcs in data record request
+  if (qps_ != DBL_MIN) {
+    metrics->set_qps(qps_);
+  }
+  if (qps_per_core_ != DBL_MIN) {
+    metrics->set_qps_per_core(qps_per_core_);
+  }
+  if (perc_lat_50_ != DBL_MIN) {
+    metrics->set_perc_lat_50(perc_lat_50_);
+  }
+  if (perc_lat_90_ != DBL_MIN) {
+    metrics->set_perc_lat_90(perc_lat_90_);
+  }
+  if (perc_lat_95_ != DBL_MIN) {
+    metrics->set_perc_lat_95(perc_lat_95_);
+  }
+  if (perc_lat_99_ != DBL_MIN) {
+    metrics->set_perc_lat_99(perc_lat_99_);
+  }
+  if (perc_lat_99_point_9_ != DBL_MIN) {
+    metrics->set_perc_lat_99_point_9(perc_lat_99_point_9_);
+  }
+  if (server_system_time_ != DBL_MIN) {
+    metrics->set_server_system_time(server_system_time_);
+  }
+  if (server_user_time_ != DBL_MIN) {
+    metrics->set_server_user_time(server_user_time_);
+  }
+  if (client_system_time_ != DBL_MIN) {
+    metrics->set_client_system_time(client_system_time_);
+  }
+  if (client_user_time_ != DBL_MIN) {
+    metrics->set_client_user_time(client_user_time_);
+  }
+
+  SingleUserRecordReply single_user_record_reply;
+  ClientContext context;
+
+  Status status = stub_->RecordSingleClientData(
+      &context, single_user_record_request, &single_user_record_reply);
+  if (status.ok()) {
+    return true;  // data sent to database successfully
+  } else {
+    return false;  // error in data sending
+  }
+}
+}  // testing
+}  // grpc
diff --git a/test/cpp/qps/perf_db_client.h b/test/cpp/qps/perf_db_client.h
new file mode 100644
index 0000000000000000000000000000000000000000..ce7a88bbff04b178f5c5ed3dc361a4972a269da2
--- /dev/null
+++ b/test/cpp/qps/perf_db_client.h
@@ -0,0 +1,115 @@
+/*
+ *
+ * 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 <iostream>
+#include <memory>
+#include <string>
+#include <cfloat>
+
+#include <grpc/grpc.h>
+#include <grpc++/channel_arguments.h>
+#include <grpc++/channel_interface.h>
+#include <grpc++/client_context.h>
+#include <grpc++/create_channel.h>
+#include <grpc++/credentials.h>
+#include <grpc++/status.h>
+#include "test/cpp/qps/perf_db.grpc.pb.h"
+
+namespace grpc {
+namespace testing {
+
+// Manages data sending to performance database server
+class PerfDbClient {
+ public:
+  PerfDbClient() {
+    qps_ = DBL_MIN;
+    qps_per_core_ = DBL_MIN;
+    perc_lat_50_ = DBL_MIN;
+    perc_lat_90_ = DBL_MIN;
+    perc_lat_95_ = DBL_MIN;
+    perc_lat_99_ = DBL_MIN;
+    perc_lat_99_point_9_ = DBL_MIN;
+    server_system_time_ = DBL_MIN;
+    server_user_time_ = DBL_MIN;
+    client_system_time_ = DBL_MIN;
+    client_user_time_ = DBL_MIN;
+  }
+
+  void init(std::shared_ptr<ChannelInterface> channel) {
+    stub_ = PerfDbTransfer::NewStub(channel);
+  }
+
+  ~PerfDbClient() {}
+
+  // sets the client and server config information
+  void setConfigs(const ClientConfig& client_config,
+                  const ServerConfig& server_config);
+
+  // sets the qps
+  void setQps(double qps);
+
+  // sets the qps per core
+  void setQpsPerCore(double qps_per_core);
+
+  // sets the 50th, 90th, 95th, 99th and 99.9th percentile latency
+  void setLatencies(double perc_lat_50, double perc_lat_90,
+                    double perc_lat_95, double perc_lat_99,
+                    double perc_lat_99_point_9);
+
+  // sets the server and client, user and system times
+  void setTimes(double server_system_time, double server_user_time,
+                double client_system_time, double client_user_time);
+
+  // sends the data to the performance database server
+  bool sendData(std::string hashed_id, std::string test_name,
+                std::string sys_info, std::string tag);
+
+ private:
+  std::unique_ptr<PerfDbTransfer::Stub> stub_;
+  ClientConfig client_config_;
+  ServerConfig server_config_;
+  double qps_;
+  double qps_per_core_;
+  double perc_lat_50_;
+  double perc_lat_90_;
+  double perc_lat_95_;
+  double perc_lat_99_;
+  double perc_lat_99_point_9_;
+  double server_system_time_;
+  double server_user_time_;
+  double client_system_time_;
+  double client_user_time_;
+};
+
+}  // namespace testing
+}  // namespace grpc
diff --git a/test/cpp/qps/report.cc b/test/cpp/qps/report.cc
index 94aacdbd1c8bbc267d3385d937a79af0b557af13..ff01ec150144dac34f52400cbfbac4604f8584f0 100644
--- a/test/cpp/qps/report.cc
+++ b/test/cpp/qps/report.cc
@@ -67,7 +67,6 @@ void CompositeReporter::ReportTimes(const ScenarioResult& result) {
   }
 }
 
-
 void GprLogReporter::ReportQPS(const ScenarioResult& result) {
   gpr_log(GPR_INFO, "QPS: %.1f",
           result.latencies.Count() /
@@ -76,10 +75,9 @@ void GprLogReporter::ReportQPS(const ScenarioResult& result) {
 }
 
 void GprLogReporter::ReportQPSPerCore(const ScenarioResult& result) {
-  auto qps =
-      result.latencies.Count() /
-      average(result.client_resources,
-          [](ResourceUsage u) { return u.wall_time; });
+  auto qps = result.latencies.Count() /
+             average(result.client_resources,
+                     [](ResourceUsage u) { return u.wall_time; });
 
   gpr_log(GPR_INFO, "QPS: %.1f (%.1f/server core)", qps,
           qps / result.server_config.threads());
@@ -118,5 +116,71 @@ void GprLogReporter::ReportTimes(const ScenarioResult& result) {
                   [](ResourceUsage u) { return u.wall_time; }));
 }
 
+void PerfDbReporter::ReportQPS(const ScenarioResult& result) {
+  auto qps = result.latencies.Count() /
+             average(result.client_resources,
+                     [](ResourceUsage u) { return u.wall_time; });
+
+  perf_db_client_.setQps(qps);
+  perf_db_client_.setConfigs(result.client_config, result.server_config);
+}
+
+void PerfDbReporter::ReportQPSPerCore(const ScenarioResult& result) {
+  auto qps = result.latencies.Count() /
+             average(result.client_resources,
+                     [](ResourceUsage u) { return u.wall_time; });
+
+  auto qpsPerCore = qps / result.server_config.threads();
+
+  perf_db_client_.setQps(qps);
+  perf_db_client_.setQpsPerCore(qpsPerCore);
+  perf_db_client_.setConfigs(result.client_config, result.server_config);
+}
+
+void PerfDbReporter::ReportLatency(const ScenarioResult& result) {
+  perf_db_client_.setLatencies(result.latencies.Percentile(50) / 1000,
+                             result.latencies.Percentile(90) / 1000,
+                             result.latencies.Percentile(95) / 1000,
+                             result.latencies.Percentile(99) / 1000,
+                             result.latencies.Percentile(99.9) / 1000);
+  perf_db_client_.setConfigs(result.client_config, result.server_config);
+}
+
+void PerfDbReporter::ReportTimes(const ScenarioResult& result) {
+  double server_system_time =
+      100.0 * sum(result.server_resources,
+                  [](ResourceUsage u) { return u.system_time; }) /
+      sum(result.server_resources, [](ResourceUsage u) { return u.wall_time; });
+  double server_user_time =
+      100.0 * sum(result.server_resources,
+                  [](ResourceUsage u) { return u.user_time; }) /
+      sum(result.server_resources, [](ResourceUsage u) { return u.wall_time; });
+  double client_system_time =
+      100.0 * sum(result.client_resources,
+                  [](ResourceUsage u) { return u.system_time; }) /
+      sum(result.client_resources, [](ResourceUsage u) { return u.wall_time; });
+  double client_user_time =
+      100.0 * sum(result.client_resources,
+                  [](ResourceUsage u) { return u.user_time; }) /
+      sum(result.client_resources, [](ResourceUsage u) { return u.wall_time; });
+
+  perf_db_client_.setTimes(server_system_time, server_user_time, client_system_time,
+                         client_user_time);
+  perf_db_client_.setConfigs(result.client_config, result.server_config);
+}
+
+void PerfDbReporter::SendData() {
+  // send data to performance database
+  bool data_state =
+      perf_db_client_.sendData(hashed_id_, test_name_, sys_info_, tag_);
+
+  // check state of data sending
+  if (data_state) {
+    gpr_log(GPR_INFO, "Data sent to performance database successfully");
+  } else {
+    gpr_log(GPR_INFO, "Data could not be sent to performance database");
+  }
+}
+
 }  // namespace testing
 }  // namespace grpc
diff --git a/test/cpp/qps/report.h b/test/cpp/qps/report.h
index b1cf83fc23a997ee1cd3bf270cfbbc3299065aa1..aec3cbe80a35366b281a023abfbc2d36aede8550 100644
--- a/test/cpp/qps/report.h
+++ b/test/cpp/qps/report.h
@@ -41,6 +41,7 @@
 
 #include "test/cpp/qps/driver.h"
 #include "test/cpp/qps/qpstest.grpc.pb.h"
+#include "test/cpp/qps/perf_db_client.h"
 
 namespace grpc {
 namespace testing {
@@ -103,6 +104,35 @@ class GprLogReporter : public Reporter {
   void ReportTimes(const ScenarioResult& result) GRPC_OVERRIDE;
 };
 
+/** Reporter for performance database tool */
+class PerfDbReporter : public Reporter {
+ public:
+  PerfDbReporter(const string& name, const string& hashed_id,
+                 const string& test_name, const string& sys_info,
+                 const string& server_address, const string& tag)
+      : Reporter(name),
+        hashed_id_(hashed_id),
+        test_name_(test_name),
+        sys_info_(sys_info),
+        tag_(tag) {
+    perf_db_client_.init(grpc::CreateChannel(
+        server_address, grpc::InsecureCredentials(), ChannelArguments()));
+  }
+  ~PerfDbReporter() GRPC_OVERRIDE { SendData(); };
+
+ private:
+  PerfDbClient perf_db_client_;
+  std::string hashed_id_;
+  std::string test_name_;
+  std::string sys_info_;
+  std::string tag_;
+  void ReportQPS(const ScenarioResult& result) GRPC_OVERRIDE;
+  void ReportQPSPerCore(const ScenarioResult& result) GRPC_OVERRIDE;
+  void ReportLatency(const ScenarioResult& result) GRPC_OVERRIDE;
+  void ReportTimes(const ScenarioResult& result) GRPC_OVERRIDE;
+  void SendData();
+};
+
 }  // namespace testing
 }  // namespace grpc
 
diff --git a/test/cpp/util/benchmark_config.cc b/test/cpp/util/benchmark_config.cc
index 5b3c1daf5db50f2ee3f653b30f00aed4701de6c7..91fbbf96771edf21f67d8aa97c31cd60a8b11837 100644
--- a/test/cpp/util/benchmark_config.cc
+++ b/test/cpp/util/benchmark_config.cc
@@ -37,6 +37,18 @@
 DEFINE_bool(enable_log_reporter, true,
             "Enable reporting of benchmark results through GprLog");
 
+DEFINE_bool(report_metrics_db, false, "True if metrics to be reported to performance database");
+
+DEFINE_string(hashed_id, "", "Hash of the user id");
+
+DEFINE_string(test_name, "", "Name of the test being executed");
+
+DEFINE_string(sys_info, "", "System information");
+
+DEFINE_string(server_address, "localhost:50052", "Address of the performance database server");
+
+DEFINE_string(tag, "", "Optional tag for the test");
+
 // In some distros, gflags is in the namespace google, and in some others,
 // in gflags. This hack is enabling us to find both.
 namespace google {}
@@ -57,6 +69,12 @@ static std::shared_ptr<Reporter> InitBenchmarkReporters() {
     composite_reporter->add(
         std::unique_ptr<Reporter>(new GprLogReporter("LogReporter")));
   }
+  if(FLAGS_report_metrics_db) {
+    composite_reporter->add(
+      std::unique_ptr<Reporter>(new PerfDbReporter("PerfDbReporter", FLAGS_hashed_id, FLAGS_test_name, 
+        FLAGS_sys_info, FLAGS_server_address, FLAGS_tag)));
+  }
+
   return std::shared_ptr<Reporter>(composite_reporter);
 }
 
diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json
index 3a858277fa8a3c41dd22be631bc2a8c4c915c419..b228aaa66cdb8b505301c931d602fd2de7c0ba30 100644
--- a/tools/run_tests/sources_and_headers.json
+++ b/tools/run_tests/sources_and_headers.json
@@ -9881,6 +9881,9 @@
       "test/cpp/qps/driver.h", 
       "test/cpp/qps/histogram.h", 
       "test/cpp/qps/interarrival.h", 
+      "test/cpp/qps/perf_db.grpc.pb.h", 
+      "test/cpp/qps/perf_db.pb.h", 
+      "test/cpp/qps/perf_db_client.h", 
       "test/cpp/qps/qps_worker.h", 
       "test/cpp/qps/qpstest.grpc.pb.h", 
       "test/cpp/qps/qpstest.pb.h", 
@@ -9900,6 +9903,8 @@
       "test/cpp/qps/driver.h", 
       "test/cpp/qps/histogram.h", 
       "test/cpp/qps/interarrival.h", 
+      "test/cpp/qps/perf_db_client.cc", 
+      "test/cpp/qps/perf_db_client.h", 
       "test/cpp/qps/qps_worker.cc", 
       "test/cpp/qps/qps_worker.h", 
       "test/cpp/qps/report.cc",