From b7f77d40ad9ed91e525ace4ad2fc9809a1ddaae6 Mon Sep 17 00:00:00 2001
From: Teon Banek <teon.banek@memgraph.io>
Date: Wed, 28 Feb 2018 10:52:22 +0100
Subject: [PATCH] Stack allocate the RPC Request

Summary:
There's no need to heap allocate the request which is used only to be
serialized and sent over the network. Unfortunately, this change
complicates the reading a bit, because we need to deserialize the raw
pointer and put it in std::unique_ptr instead of simply deserializing
the unique_ptr.

Heap allocation shows up visibly in perf during benchmarks, so this
change may yield some improvement.

Reviewers: mferencevic, mtomic

Reviewed By: mferencevic

Subscribers: pullbot

Differential Revision: https://phabricator.memgraph.io/D1254
---
 src/communication/rpc/client.cpp   |  6 ++++--
 src/communication/rpc/client.hpp   |  5 ++---
 src/communication/rpc/protocol.cpp | 11 +++++++----
 3 files changed, 13 insertions(+), 9 deletions(-)

diff --git a/src/communication/rpc/client.cpp b/src/communication/rpc/client.cpp
index faf84483e..ea442c4be 100644
--- a/src/communication/rpc/client.cpp
+++ b/src/communication/rpc/client.cpp
@@ -19,7 +19,7 @@ namespace communication::rpc {
 
 Client::Client(const io::network::Endpoint &endpoint) : endpoint_(endpoint) {}
 
-std::unique_ptr<Message> Client::Call(std::unique_ptr<Message> request) {
+std::unique_ptr<Message> Client::Call(const Message &request) {
   std::lock_guard<std::mutex> guard(mutex_);
 
   if (FLAGS_rpc_random_latency) {
@@ -50,7 +50,9 @@ std::unique_ptr<Message> Client::Call(std::unique_ptr<Message> request) {
   std::stringstream request_stream(std::ios_base::out | std::ios_base::binary);
   {
     boost::archive::binary_oarchive request_archive(request_stream);
-    request_archive << request;
+    // Serialize reference as pointer (to serialize the derived class). The
+    // request is read in protocol.cpp.
+    request_archive << &request;
     // Archive destructor ensures everything is written.
   }
 
diff --git a/src/communication/rpc/client.hpp b/src/communication/rpc/client.hpp
index 31ecdb5c5..579b0dedc 100644
--- a/src/communication/rpc/client.hpp
+++ b/src/communication/rpc/client.hpp
@@ -36,8 +36,7 @@ class Client {
                     utils::Demangle(typeid(Req).name()).value_or("unknown"));
     std::unique_ptr<Message> response = nullptr;
     stats::Stopwatch(request_name, [&] {
-      response = Call(std::unique_ptr<Message>(
-          std::make_unique<Req>(std::forward<Args>(args)...)));
+      response = Call(Req(std::forward<Args>(args)...));
     });
     auto *real_response = dynamic_cast<Res *>(response.get());
     if (!real_response && response) {
@@ -55,7 +54,7 @@ class Client {
   void Abort();
 
  private:
-  std::unique_ptr<Message> Call(std::unique_ptr<Message> request);
+  std::unique_ptr<Message> Call(const Message &request);
 
   io::network::Endpoint endpoint_;
   std::experimental::optional<io::network::Socket> socket_;
diff --git a/src/communication/rpc/protocol.cpp b/src/communication/rpc/protocol.cpp
index d586f79d4..9b20d83ba 100644
--- a/src/communication/rpc/protocol.cpp
+++ b/src/communication/rpc/protocol.cpp
@@ -24,15 +24,18 @@ void Session::Execute() {
   buffer_.Resize(request_size);
   if (buffer_.size() < request_size) return;
 
-  std::unique_ptr<Message> request;
-  {
+  // Read the request message.
+  std::unique_ptr<Message> request([this, request_len]() {
+    Message *req_ptr = nullptr;
     std::stringstream stream(std::ios_base::in | std::ios_base::binary);
     stream.str(std::string(
         reinterpret_cast<char *>(buffer_.data() + sizeof(MessageSize)),
         request_len));
     boost::archive::binary_iarchive archive(stream);
-    archive >> request;
-  }
+    // Sent from client.cpp
+    archive >> req_ptr;
+    return req_ptr;
+  }());
   buffer_.Shift(sizeof(MessageSize) + request_len);
 
   auto callbacks_accessor = server_.callbacks_.access();