Update benchmark tool for testing dbus 89/308589/6
authorjh9216.park <jh9216.park@samsung.com>
Thu, 28 Mar 2024 01:47:12 +0000 (21:47 -0400)
committerjh9216.park <jh9216.park@samsung.com>
Thu, 28 Mar 2024 07:40:31 +0000 (03:40 -0400)
Change-Id: I8c3179af8c3c6a6ea5e89a36592dc04bea894324
Signed-off-by: jh9216.park <jh9216.park@samsung.com>
22 files changed:
CMakeLists.txt
benchmark/server/BenchmarkStub.cc [deleted file]
benchmark/server/BenchmarkStub.h [deleted file]
benchmark/server/CMakeLists.txt
benchmark/server/dbus/CMakeLists.txt [new file with mode: 0644]
benchmark/server/dbus/log-private.hh [new file with mode: 0644]
benchmark/server/dbus/main.cc [new file with mode: 0644]
benchmark/server/dbus/rpc-port-benchmark.conf [new file with mode: 0644]
benchmark/server/log-private.hh [deleted file]
benchmark/server/main.cc [deleted file]
benchmark/server/tidl/BenchmarkStub.cc [new file with mode: 0644]
benchmark/server/tidl/BenchmarkStub.h [new file with mode: 0644]
benchmark/server/tidl/CMakeLists.txt [new file with mode: 0644]
benchmark/server/tidl/log-private.hh [new file with mode: 0644]
benchmark/server/tidl/main.cc [new file with mode: 0644]
benchmark/tool/dbus-proxy.cc [new file with mode: 0644]
benchmark/tool/dbus-proxy.hh [new file with mode: 0644]
benchmark/tool/main.cc
benchmark/tool/options.cc
benchmark/tool/options.hh
packaging/rpc-port.spec
socket_test/tool/main.cc [new file with mode: 0644]

index 9e9387db14416287ebc10e03b1d46a54c4221016..60478482e26132e16ff97093f568c01fedfbfd72 100644 (file)
@@ -29,6 +29,7 @@ SET(TARGET_RPC_PORT "rpc-port")
 SET(TARGET_RPC_PORT_UNITTESTS "rpc-port_unittests")
 SET(TARGET_RPC_PORT_UTIL "rpc-port-util")
 SET(TARGET_BENCHMARK_SERVER "rpc-port-benchmark-server")
+SET(TARGET_BENCHMARK_SERVER_DBUS "rpc-port-benchmark-server-dbus")
 SET(TARGET_BENCHMARK_TOOL "rpc-port-benchmark-tool")
 
 ENABLE_TESTING()
diff --git a/benchmark/server/BenchmarkStub.cc b/benchmark/server/BenchmarkStub.cc
deleted file mode 100644 (file)
index f1d55d2..0000000
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * Generated by tidlc 2.0.4.
- */
-
-#include <stdlib.h>
-#include <assert.h>
-#include <libgen.h>
-#include <dlog.h>
-
-#include "BenchmarkStub.h"
-
-
-#ifdef LOG_TAG
-#undef LOG_TAG
-#endif
-
-#define LOG_TAG "RPC_PORT_STUB"
-
-#ifdef _E
-#undef _E
-#endif
-
-#ifdef _W
-#undef _W
-#endif
-
-#ifdef _I
-#undef _I
-#endif
-
-#ifdef _D
-#undef _D
-#endif
-
-#define _E(fmt, ...) dlog_print(DLOG_ERROR, LOG_TAG, "%s: %s(%d) > " fmt, basename(const_cast<char*>(__FILE__)), __FUNCTION__, __LINE__, ##__VA_ARGS__)
-#define _W(fmt, ...) dlog_print(DLOG_WARN, LOG_TAG, "%s: %s(%d) > " fmt, basename(const_cast<char*>(__FILE__)), __FUNCTION__, __LINE__, ##__VA_ARGS__)
-#define _I(fmt, ...) dlog_print(DLOG_INFO, LOG_TAG, "%s: %s(%d) > " fmt, basename(const_cast<char*>(__FILE__)), __FUNCTION__, __LINE__, ##__VA_ARGS__)
-#define _D(fmt, ...) dlog_print(DLOG_DEBUG, LOG_TAG, "%s: %s(%d) > " fmt, basename(const_cast<char*>(__FILE__)), __FUNCTION__, __LINE__, ##__VA_ARGS__)
-
-#ifndef TIDL_VERSION
-#define TIDL_VERSION "2.0.4"
-#endif
-
-namespace rpc_port {
-namespace BenchmarkStub {
-
-namespace stub {
-
-Benchmark::ServiceBase::ServiceBase(std::string sender, std::string instance)
-    : sender_(std::move(sender)), instance_(std::move(instance)),
-      active_object_(new ActiveObject()) {}
-
-void Benchmark::ServiceBase::SetPort(rpc_port_h port) {
-  port_ = port;
-}
-
-void Benchmark::ServiceBase::Disconnect() {
-  int ret = rpc_port_disconnect(port_);
-  if (ret == RPC_PORT_ERROR_NONE) {
-    _E("Failed to disconnect the port(%d)", ret);
-    return;
-  }
-
-  port_ = nullptr;
-}
-
-
-std::atomic<int> Benchmark::CallbackBase::seq_num_ { 0 };
-
-Benchmark::CallbackBase::CallbackBase(int delegate_id, bool once)
-    : id_(delegate_id), once_(once) {
-  seq_id_ = seq_num_++;
-}
-
-int Benchmark::CallbackBase::GetId() const {
-  return id_;
-}
-
-int Benchmark::CallbackBase::GetSeqId() const {
-  return seq_id_;
-}
-
-bool Benchmark::CallbackBase::IsOnce() const {
-  return once_;
-}
-
-std::string Benchmark::CallbackBase::GetTag() const {
-  return std::to_string(id_) + "::" + std::to_string(seq_id_);
-}
-
-rpc_port_parcel_h operator << (rpc_port_parcel_h h, const Benchmark::CallbackBase& cb) {
-  rpc_port_parcel_write_int32(h, cb.id_);
-  rpc_port_parcel_write_int32(h, cb.seq_id_);
-  rpc_port_parcel_write_bool(h, cb.once_);
-
-  return h;
-}
-
-rpc_port_parcel_h operator >> (rpc_port_parcel_h h, Benchmark::CallbackBase& cb) {
-  rpc_port_parcel_read_int32(h, &cb.id_);
-  rpc_port_parcel_read_int32(h, &cb.seq_id_);
-  rpc_port_parcel_read_bool(h, &cb.once_);
-
-  return h;
-}
-
-Benchmark::Benchmark() {
-  int r = rpc_port_stub_create(&stub_, "Benchmark");
-  if (r != RPC_PORT_ERROR_NONE) {
-    _E("Failed to create stub handle");
-    throw InvalidIOException();
-  }
-  rpc_port_stub_add_connected_event_cb(stub_, OnConnectedCB, this);
-  rpc_port_stub_add_disconnected_event_cb(stub_, OnDisconnectedCB, this);
-  rpc_port_stub_add_received_event_cb(stub_, OnReceivedCB, this);
-}
-
-Benchmark::~Benchmark() {
-  for (auto& i : services_) {
-    i->OnTerminate();
-  }
-
-  if (stub_) {
-    rpc_port_stub_destroy(stub_);
-  }
-}
-
-void Benchmark::Listen(std::shared_ptr<Benchmark::ServiceBase::Factory> service_factory) {
-  service_factory_ = std::move(service_factory);
-  int r = rpc_port_stub_listen(stub_);
-  if (r != RPC_PORT_ERROR_NONE) {
-    _E("Failed to listen stub");
-    switch (r) {
-      case RPC_PORT_ERROR_INVALID_PARAMETER:
-      case RPC_PORT_ERROR_IO_ERROR:
-        throw InvalidIOException();
-    }
-  }
-}
-
-void Benchmark::OnConnectedCB(const char* sender, const char* instance, void* data) {
-  Benchmark* stub = static_cast<Benchmark*>(data);
-  auto s = stub->service_factory_->CreateService(sender, instance);
-
-  rpc_port_h port;
-  int ret = rpc_port_stub_get_port(stub->stub_, RPC_PORT_PORT_CALLBACK, instance, &port);
-  if (ret != RPC_PORT_ERROR_NONE) {
-    _E("Failed to get the port(%d)", ret);
-    return;
-  }
-
-  s->SetPort(port);
-  s->OnCreate();
-  stub->services_.emplace_back(std::move(s));
-}
-
-void Benchmark::OnDisconnectedCB(const char* sender, const char* instance, void *data) {
-  Benchmark* stub = static_cast<Benchmark*>(data);
-
-  for (auto& i : stub->services_) {
-    if (i->GetInstance() == instance) {
-      i->OnTerminate();
-      stub->services_.remove(i);
-      return;
-    }
-  }
-}
-
-int Benchmark::OnReceivedCB(const char* sender, const char* instance, rpc_port_h port, void *data)
-{
-  auto* cxt = static_cast<Benchmark*>(data);
-  rpc_port_parcel_h p;
-  rpc_port_parcel_h result;
-  rpc_port_parcel_header_h header;
-  int seq_num = -1;
-  int cmd;
-  int ret;
-  std::shared_ptr<ServiceBase> b;
-  rpc_port_h callback_port;
-
-  for (auto& i : cxt->services_) {
-    if (i->GetInstance() == instance) {
-      b = i;
-      break;
-    }
-  }
-
-  if (b.get() == nullptr) {
-    _E("Failed to find Benchmark context(%s)", instance);
-    return -1;
-  }
-
-  ret = rpc_port_stub_get_port(cxt->stub_, RPC_PORT_PORT_CALLBACK, instance,
-      &callback_port);
-  if (ret != 0) {
-    _E("Failed to get callback port");
-  }
-
-  ret = rpc_port_parcel_create_from_port(&p, port);
-  if (ret != 0) {
-    _E("Failed to create parcel from port");
-    return ret;
-  }
-
-  rpc_port_parcel_get_header(p, &header);
-  rpc_port_parcel_header_get_seq_num(header, &seq_num);
-
-  rpc_port_parcel_create(&result);
-  rpc_port_parcel_get_header(result, &header);
-  rpc_port_parcel_header_set_tag(header, TIDL_VERSION);
-  rpc_port_parcel_header_set_seq_num(header, seq_num);
-
-  rpc_port_parcel_read_int32(p, &cmd);
-
-  switch (cmd) {
-    case static_cast<int>(MethodId::Test): {
-      char* param1_raw  = nullptr;
-      rpc_port_parcel_read_string(p, &param1_raw);
-      std::string param1(param1_raw);
-      free(param1_raw);
-      auto retVal = b->Test(std::move(param1));
-      rpc_port_parcel_write_int32(result, static_cast<int>(MethodId::__Result));
-      rpc_port_parcel_write_int32(result, retVal);
-      rpc_port_parcel_send(result, port);
-      break;
-    }
-
-    default:
-      _E("Unknown command(%d)", cmd);
-      rpc_port_parcel_destroy(p);
-      rpc_port_parcel_destroy(result);
-      return -1;
-  }
-
-  rpc_port_parcel_destroy(p);
-  rpc_port_parcel_destroy(result);
-
-  return ret;
-}
-
-}  // namespace stub
-}  // namespace BenchmarkStub
-}  // namespace rpc_port
diff --git a/benchmark/server/BenchmarkStub.h b/benchmark/server/BenchmarkStub.h
deleted file mode 100644 (file)
index ce6e039..0000000
+++ /dev/null
@@ -1,369 +0,0 @@
-/*
- * Generated by tidlc 2.0.4.
- */
-
-#pragma once
-
-#include <bundle.h>
-#include <rpc-port-parcel.h>
-#include <rpc-port.h>
-
-#include <memory>
-#include <string>
-#include <vector>
-#include <list>
-#include <atomic>
-#include <condition_variable>
-#include <mutex>
-#include <deque>
-#include <thread>
-
-namespace rpc_port {
-namespace BenchmarkStub {
-
-class Bundle final {
- public:
-  Bundle() {
-    raw_ = bundle_create();
-  }
-
-  Bundle(bundle* b) {
-    raw_ = b;
-  }
-
-  ~Bundle() {
-    if (raw_)
-      bundle_free(raw_);
-  }
-
-  Bundle(Bundle&& b) : raw_(b.raw_) {
-    b.raw_ = nullptr;
-  }
-
-  Bundle& operator = (Bundle&& b) {
-    if (this != &b) {
-      if (raw_)
-        bundle_free(raw_);
-
-      raw_ = b.raw_;
-      b.raw_ = nullptr;
-    }
-    return *this;
-  }
-
-  Bundle(const Bundle& b) : raw_(bundle_dup(b.GetHandle())) {}
-
-  Bundle& operator = (const Bundle& b) {
-    if (this != &b) {
-      if (raw_)
-        bundle_free(raw_);
-
-      raw_ = bundle_dup(b.GetHandle());
-    }
-    return *this;
-  }
-
-  bundle* GetHandle() const {
-    return raw_;
-  }
-
- private:
-  bundle* raw_;
-};
-
-class File final {
- public:
-  File() {
-  }
-
-  File(std::string filename) {
-    filename_ = filename;
-  }
-
-  std::string GetFileName() const {
-    return filename_;
-  }
-
- private:
-  std::string filename_;
-};
-
-namespace stub {
-
-class Exception {};
-class NotConnectedSocketException : public Exception {};
-class InvalidProtocolException : public Exception {};
-class InvalidIOException : public Exception {};
-class InvalidCallbackException : public Exception {};
-class Job {
- public:
-  class IEvent {
-   public:
-    virtual ~IEvent() = default;
-    virtual void Run() = 0;
-  };
-
-  Job() : handler_(nullptr) {
-  }
-
-  Job(IEvent* handler) : handler_(handler) {
-  }
-  virtual ~Job() = default;
-
-  Job(const Job& job) {
-    handler_ = job.handler_;
-  }
-
-  Job& operator = (const Job& job) {
-    if (this != &job)
-      handler_ = job.handler_;
-    return *this;
-  }
-  Job(Job&& job) noexcept {
-    handler_ = job.handler_;
-    job.handler_ = nullptr;
-  }
-
-  Job& operator = (Job&& job) noexcept {
-    if (this != &job) {
-      handler_ = job.handler_;
-      job.handler_ = nullptr;
-    }
-    return *this;
-  }
-
-  void Invoke() {
-    if (handler_)
-      handler_->Run();
-  }
-
- private:
-  IEvent* handler_;
-};
-
-
-template <class T>
-class SharedQueue {
- public:
-  SharedQueue() = default;
-  virtual ~SharedQueue() = default;
-
-  void Push(T item) {
-    std::lock_guard<std::mutex> lock(mutex_);
-    queue_.push_back(item);
-    cond_var_.notify_one();
-  }
-
-  void PushFront(T item) {
-    std::lock_guard<std::mutex> lock(mutex_);
-    queue_.push_front(item);
-    cond_var_.notify_one();
-  }
-
-  bool TryAndPop(T& item) {
-    std::lock_guard<std::mutex> lock(mutex_);
-    if (queue_.empty())
-       return false;
-
-    item = queue_.front();
-    queue_.pop_front();
-
-    return true;
-  }
-
-  void WaitAndPop(T& item) {
-    std::unique_lock<std::mutex> lock(mutex_);
-    while (queue_.empty())
-      cond_var_.wait(lock);
-
-    item = queue_.front();
-    queue_.pop_front();
-  }
-
-  bool Empty() {
-    std::lock_guard<std::mutex> lock(mutex_);
-    return queue_.empty();
-  }
-
-  int Size() {
-    std::lock_guard<std::mutex> lock(mutex_);
-    return queue_.size();
-  }
-
- private:
-  std::deque<T> queue_;
-  mutable std::mutex mutex_;
-  std::condition_variable cond_var_;
-};
-
-class ActiveObject : public Job::IEvent {
- public:
-  ActiveObject() {
-    thread_ = std::thread([&]{
-          do {
-            std::shared_ptr<Job> item;
-            queue_.WaitAndPop(item);
-            item->Invoke();
-          } while (!done_);
-        });
-  }
-  virtual ~ActiveObject() {
-    Quit();
-    thread_.join();
-  }
-
- public:
-  void Send(std::shared_ptr<Job> job) {
-    queue_.Push(std::move(job));
-  }
-
- private:
-  void Quit() {
-    Send(std::shared_ptr<Job>(new (std::nothrow) Job(this)));
-  }
-  void Run() override {
-    done_ = true;
-  }
-
- private:
-  std::thread thread_;
-  bool done_ = false;
-  SharedQueue<std::shared_ptr<Job>> queue_;
-};
-
-
-class Benchmark final {
- public:
-  class ServiceBase;
-
-  class CallbackBase {
-   public:
-    CallbackBase(int delegate_id, bool once);
-    virtual ~CallbackBase() = default;
-
-    int GetId() const;
-    int GetSeqId() const;
-    bool IsOnce() const;
-    std::string GetTag() const;
-
-   private:
-    friend rpc_port_parcel_h operator << (rpc_port_parcel_h h, const CallbackBase& cb);
-    friend rpc_port_parcel_h operator >> (rpc_port_parcel_h h, CallbackBase& cb);
-
-    static std::atomic<int> seq_num_;
-    int id_;
-    int seq_id_;
-    bool once_;
-  };
-
-  class ServiceBase {
-   public:
-    class Factory {
-     public:
-      virtual ~Factory() = default;
-
-      /// <summary>
-      /// The method for making service instances
-      /// </summary>
-      /// <param name="sender">The client app ID</param>
-      /// <param name="instance">The client instance ID</param>
-      virtual std::unique_ptr<ServiceBase> CreateService(std::string sender, std::string instance) = 0;
-    };
-
-    virtual ~ServiceBase() = default;
-
-    /// <summary>
-    /// Gets client app ID
-    /// </summary>
-    const std::string& GetSender() const {
-      return sender_;
-    }
-
-    /// <summary>
-    /// Gets client instance ID
-    /// </summary>
-    const std::string& GetInstance() const {
-      return instance_;
-    }
-
-    /// <summary>
-    /// Sets the client app port
-    /// </summary>
-    /// <param name="port">The port of the client</param>
-    void SetPort(rpc_port_h port);
-
-    /// <summary>
-    /// Disconnects from the client app
-    /// </summary>
-    /// <exception cref="InvalidIOException">
-    /// Thrown when internal I/O error happen.
-    /// </exception>
-    void Disconnect();
-
-    /// <summary>
-    /// This method will be called when the client is connected
-    /// </summary>
-    virtual void OnCreate() = 0;
-
-    /// <summary>
-    /// This method will be called when the client is disconnected
-    /// </summary>
-    virtual void OnTerminate() = 0;
-
-    void Dispatch(rpc_port_h port, rpc_port_h callback_port,
-        rpc_port_parcel_h parcel, std::shared_ptr<ServiceBase> service);
-
-    virtual int Test(std::string data) = 0;
-
-   protected:
-    ServiceBase(std::string sender, std::string instance);
-
-   private:
-    std::string sender_;
-    std::string instance_;
-    rpc_port_h port_ = nullptr;
-    std::unique_ptr<ActiveObject> active_object_;
-  };
-
-  Benchmark();
-  ~Benchmark();
-
-  /// <summary>
-  /// Listens to client apps
-  /// </summary>
-  /// <param name="service_factory">The factory object for making service instances</param>
-  /// <exception cref="InvalidIOException">
-  /// Thrown when internal I/O error happen.
-  /// </exception>
-  void Listen(std::shared_ptr<ServiceBase::Factory> service_factory);
-
-  /// <summary>
-  /// Gets service objects which are connected
-  /// </summary>
-  /// <returns>The list of service objects which are connected</returns>
-  const std::list<std::shared_ptr<ServiceBase>>& GetServices() const {
-    return services_;
-  }
-
- private:
-  enum class MethodId : int {
-    __Result = 0,
-    __Callback = 1,
-    Test = 2,
-
-  };
-
-  enum class DelegateId : int {
-
-  };
-  static void OnConnectedCB(const char* sender, const char* instance, void* data);
-  static void OnDisconnectedCB(const char* sender, const char* instance, void* data);
-  static int OnReceivedCB(const char* sender, const char* instance, rpc_port_h port, void* data);
-
-  rpc_port_stub_h stub_ = nullptr;
-  std::shared_ptr<ServiceBase::Factory> service_factory_;
-  std::list<std::shared_ptr<ServiceBase>> services_;
-};
-}  // namespace stub
-}  // namespace BenchmarkStub
-}  // namespace rpc_port
index cff54c121089441faed45e58620ce72e1065ffbc..015cdef4d4c1f2911630e15e7856eb7ffdb36c93 100644 (file)
@@ -1,22 +1,2 @@
-AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} BENCHMARK_SERVER_SRCS)
-
-ADD_EXECUTABLE(${TARGET_BENCHMARK_SERVER} ${BENCHMARK_SERVER_SRCS})
-
-TARGET_INCLUDE_DIRECTORIES(${TARGET_BENCHMARK_SERVER} PUBLIC
-  ${CMAKE_CURRENT_SOURCE_DIR}
-  ${CMAKE_CURRENT_SOURCE_DIR}/../../include/)
-
-APPLY_PKG_CONFIG(${TARGET_BENCHMARK_SERVER} PUBLIC
-  AUL_DEPS
-  DLOG_DEPS
-  GLIB_DEPS
-)
-
-TARGET_LINK_LIBRARIES(${TARGET_BENCHMARK_SERVER} PUBLIC
-  ${TARGET_RPC_PORT} "-lpthread")
-SET_TARGET_PROPERTIES(${TARGET_BENCHMARK_SERVER} PROPERTIES
-  COMPILE_FLAGS "-fPIE")
-SET_TARGET_PROPERTIES(${TARGET_BENCHMARK_SERVER} PROPERTIES
-  LINK_FLAGS "-pie")
-
-INSTALL(TARGETS ${TARGET_BENCHMARK_SERVER} DESTINATION bin)
+ADD_SUBDIRECTORY(tidl)
+ADD_SUBDIRECTORY(dbus)
diff --git a/benchmark/server/dbus/CMakeLists.txt b/benchmark/server/dbus/CMakeLists.txt
new file mode 100644 (file)
index 0000000..509fe88
--- /dev/null
@@ -0,0 +1,23 @@
+AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} BENCHMARK_SERVER_DBUS_SRCS)
+
+ADD_EXECUTABLE(${TARGET_BENCHMARK_SERVER_DBUS} ${BENCHMARK_SERVER_DBUS_SRCS})
+
+TARGET_INCLUDE_DIRECTORIES(${TARGET_BENCHMARK_SERVER_DBUS} PUBLIC
+  ${CMAKE_CURRENT_SOURCE_DIR}
+  ${CMAKE_CURRENT_SOURCE_DIR}/../../../include/)
+
+APPLY_PKG_CONFIG(${TARGET_BENCHMARK_SERVER_DBUS} PUBLIC
+  DLOG_DEPS
+  GLIB_DEPS
+  GIO_DEPS
+)
+
+TARGET_LINK_LIBRARIES(${TARGET_BENCHMARK_SERVER_DBUS} PUBLIC
+  ${TARGET_RPC_PORT} "-lpthread")
+SET_TARGET_PROPERTIES(${TARGET_BENCHMARK_SERVER_DBUS} PROPERTIES
+  COMPILE_FLAGS "-fPIE")
+SET_TARGET_PROPERTIES(${TARGET_BENCHMARK_SERVER_DBUS} PROPERTIES
+  LINK_FLAGS "-pie")
+
+INSTALL(TARGETS ${TARGET_BENCHMARK_SERVER_DBUS} DESTINATION bin)
+INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/rpc-port-benchmark.conf DESTINATION /etc/dbus-1/system.d)
diff --git a/benchmark/server/dbus/log-private.hh b/benchmark/server/dbus/log-private.hh
new file mode 100644 (file)
index 0000000..98ffafa
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LOG_PRIVATE_HH_
+#define LOG_PRIVATE_HH_
+
+#include <dlog.h>
+
+#undef LOG_TAG
+#define LOG_TAG "RPC_PORT_BENCHMARK_SERVER_DBUS"
+
+#undef _E
+#define _E LOGE
+
+#undef _W
+#define _W LOGW
+
+#undef _I
+#define _I LOGI
+
+#undef _D
+#define _D LOGD
+
+#endif  // LOG_PRIVATE_HH_
diff --git a/benchmark/server/dbus/main.cc b/benchmark/server/dbus/main.cc
new file mode 100644 (file)
index 0000000..fc2390e
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <glib.h>
+#include <gio/gio.h>
+
+#include <string_view>
+#include <string>
+
+#include "log-private.hh"
+
+namespace {
+
+constexpr const char BUS_NAME[] = "tizen.appfw.rpcport.benchmark.dbus";
+constexpr const char OBJECT_PATH[] = "/tizen/appfw/rpcport/benchmark/dbus";
+
+constexpr const char INTROSPECTION_XML[] = R"__dbus(
+<node>
+  <interface name='tizen.appfw.rpcport.benchmark.dbus'>
+    <method name='Test'>
+      <arg type='s' name='data' direction='in'/>
+      <arg type='i' name='ret' direction='out'/>
+      </method>
+  </interface>
+</node>
+)__dbus";
+
+class MainLoop {
+ public:
+  MainLoop() {
+    loop_ = g_main_loop_new(nullptr, FALSE);
+  }
+
+  ~MainLoop() {
+    g_main_loop_unref(loop_);
+    if (introspection_data_)
+      g_dbus_node_info_unref(introspection_data_);
+  }
+
+  int OnTest(std::string data) {
+    return 0;
+  }
+
+  void OnBusAcquired(GDBusConnection* connection, const gchar* name) {
+    _I("bus acquired(%s)", name);
+
+    static const GDBusInterfaceVTable interface_vtable = {
+      [](GDBusConnection *connection,
+          const gchar *sender, const gchar *object_path,
+          const gchar *interface_name, const gchar *method_name,
+          GVariant *parameters, GDBusMethodInvocation *invocation,
+          gpointer user_data) {
+        if (std::string_view(method_name) == "Test") {
+          char* data = nullptr;
+          g_variant_get(parameters, "(&s)", &data);
+          auto* obj = static_cast<MainLoop*>(user_data);
+          int ret = obj->OnTest(data);
+
+          GVariant* param = g_variant_new("(i)", ret);
+          g_dbus_method_invocation_return_value(invocation, param);
+        }
+      },
+      nullptr,
+      nullptr
+    };
+
+    GError* error = nullptr;
+    guint reg_id = g_dbus_connection_register_object(connection,
+        OBJECT_PATH,
+        introspection_data_->interfaces[0],
+        &interface_vtable,
+        this, nullptr, &error);
+    if (reg_id == 0) {
+      _E("g_dbus_connection_register_object error(%s)", error ? error->message : "");
+      g_error_free(error);
+    }
+  }
+
+  void Run() {
+    GError* error = nullptr;
+    introspection_data_ = g_dbus_node_info_new_for_xml(INTROSPECTION_XML,
+        &error);
+    if (!introspection_data_) {
+      _E("g_dbus_node_info_new_for_xml error(%s)", error ? error->message : "");
+      g_error_free(error);
+      return;
+    }
+
+    guint owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
+        BUS_NAME,
+        G_BUS_NAME_OWNER_FLAGS_NONE,
+        [](GDBusConnection* connection, const gchar* name,
+            gpointer user_data) {
+          auto* obj = static_cast<MainLoop*>(user_data);
+          obj->OnBusAcquired(connection, name);
+        },
+        [](GDBusConnection* connection,
+            const gchar* name, gpointer user_data) {
+          _I("name acquired(%s)", name);
+        },
+        [](GDBusConnection* connection,
+            const gchar* name, gpointer user_data) {
+          _I("name lost(%s)", name);
+        },
+        this, nullptr);
+    if (!owner_id) {
+      _E("g_bus_own_name error");
+      g_dbus_node_info_unref(introspection_data_);
+      return;
+    }
+
+    g_main_loop_run(loop_);
+  }
+
+  void Quit() {
+    g_main_loop_quit(loop_);
+  }
+
+ private:
+  GMainLoop* loop_ = nullptr;
+  GDBusNodeInfo* introspection_data_ = nullptr;
+};
+
+}  // namespace
+
+int main(int argc, char** argv) {
+  MainLoop loop;
+  loop.Run();
+  return 0;
+}
diff --git a/benchmark/server/dbus/rpc-port-benchmark.conf b/benchmark/server/dbus/rpc-port-benchmark.conf
new file mode 100644 (file)
index 0000000..43c9b55
--- /dev/null
@@ -0,0 +1,11 @@
+<!DOCTYPE busconfig PUBLIC
+"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+
+<busconfig>
+       <policy context="default">
+               <allow own="tizen.appfw.rpcport.benchmark.dbus" />
+               <allow send_destination="tizen.appfw.rpcport.benchmark.dbus"
+     send_interface="tizen.appfw.rpcport.benchmark.dbus" send_type="method_call" />
+       </policy>
+</busconfig>
diff --git a/benchmark/server/log-private.hh b/benchmark/server/log-private.hh
deleted file mode 100644 (file)
index 2f507b4..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef LOG_PRIVATE_HH_
-#define LOG_PRIVATE_HH_
-
-#include <dlog.h>
-
-#undef LOG_TAG
-#define LOG_TAG "RPC_PORT_BENCHMARK_SERVER"
-
-#undef _E
-#define _E LOGE
-
-#undef _W
-#define _W LOGW
-
-#undef _I
-#define _I LOGI
-
-#undef _D
-#define _D LOGD
-
-#endif  // LOG_PRIVATE_HH_
diff --git a/benchmark/server/main.cc b/benchmark/server/main.cc
deleted file mode 100644 (file)
index daac54c..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <glib.h>
-
-#include <aul_proc.h>
-
-#include "BenchmarkStub.h"
-#include "log-private.hh"
-
-namespace {
-constexpr const char SERVER_PROC_NAME[] = "org.tizen.appfw.rpc_port.benchmark";
-
-namespace bs = rpc_port::BenchmarkStub::stub;
-
-class TestService : public bs::Benchmark::ServiceBase {
- public:
-  class Factory : public bs::Benchmark::ServiceBase::Factory {
-   public:
-    virtual ~Factory() = default;
-
-    std::unique_ptr<bs::Benchmark::ServiceBase>
-        CreateService(std::string sender, std::string instance) {
-      return std::unique_ptr<bs::Benchmark::ServiceBase>(
-          new TestService(std::move(sender), std::move(instance)));
-    }
-  };
-
-  TestService(std::string sender, std::string instance) :
-      bs::Benchmark::ServiceBase(std::move(sender), std::move(instance)) {}
-
-  virtual ~TestService() = default;
-
-  void OnCreate() override {
-  }
-
-  void OnTerminate() override {
-  }
-
-  int Test(std::string data) override {
-    return 0;
-  }
-};
-
-class MainLoop {
- public:
-  MainLoop() {
-    loop_ = g_main_loop_new(nullptr, FALSE);
-  }
-
-  ~MainLoop() {
-    g_main_loop_unref(loop_);
-  }
-
-  void Run() {
-    int ret = aul_proc_register(SERVER_PROC_NAME, nullptr);
-    if (ret != AUL_R_OK) {
-      _E("aul_proc_register() failed (%d)", ret);
-      return;
-    }
-
-    try {
-      stub_.Listen(std::shared_ptr<bs::Benchmark::ServiceBase::Factory>(
-          new TestService::Factory()));
-    } catch (const bs::Exception&) {
-      _E("stub listen is failed");
-    }
-
-    g_main_loop_run(loop_);
-  }
-
-  void Quit() {
-    g_main_loop_quit(loop_);
-  }
-
- private:
-  GMainLoop* loop_;
-  bs::Benchmark stub_;
-};
-
-}  // namespace
-
-int main(int argc, char** argv) {
-  MainLoop loop;
-  loop.Run();
-  return 0;
-}
diff --git a/benchmark/server/tidl/BenchmarkStub.cc b/benchmark/server/tidl/BenchmarkStub.cc
new file mode 100644 (file)
index 0000000..f1d55d2
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * Generated by tidlc 2.0.4.
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <libgen.h>
+#include <dlog.h>
+
+#include "BenchmarkStub.h"
+
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "RPC_PORT_STUB"
+
+#ifdef _E
+#undef _E
+#endif
+
+#ifdef _W
+#undef _W
+#endif
+
+#ifdef _I
+#undef _I
+#endif
+
+#ifdef _D
+#undef _D
+#endif
+
+#define _E(fmt, ...) dlog_print(DLOG_ERROR, LOG_TAG, "%s: %s(%d) > " fmt, basename(const_cast<char*>(__FILE__)), __FUNCTION__, __LINE__, ##__VA_ARGS__)
+#define _W(fmt, ...) dlog_print(DLOG_WARN, LOG_TAG, "%s: %s(%d) > " fmt, basename(const_cast<char*>(__FILE__)), __FUNCTION__, __LINE__, ##__VA_ARGS__)
+#define _I(fmt, ...) dlog_print(DLOG_INFO, LOG_TAG, "%s: %s(%d) > " fmt, basename(const_cast<char*>(__FILE__)), __FUNCTION__, __LINE__, ##__VA_ARGS__)
+#define _D(fmt, ...) dlog_print(DLOG_DEBUG, LOG_TAG, "%s: %s(%d) > " fmt, basename(const_cast<char*>(__FILE__)), __FUNCTION__, __LINE__, ##__VA_ARGS__)
+
+#ifndef TIDL_VERSION
+#define TIDL_VERSION "2.0.4"
+#endif
+
+namespace rpc_port {
+namespace BenchmarkStub {
+
+namespace stub {
+
+Benchmark::ServiceBase::ServiceBase(std::string sender, std::string instance)
+    : sender_(std::move(sender)), instance_(std::move(instance)),
+      active_object_(new ActiveObject()) {}
+
+void Benchmark::ServiceBase::SetPort(rpc_port_h port) {
+  port_ = port;
+}
+
+void Benchmark::ServiceBase::Disconnect() {
+  int ret = rpc_port_disconnect(port_);
+  if (ret == RPC_PORT_ERROR_NONE) {
+    _E("Failed to disconnect the port(%d)", ret);
+    return;
+  }
+
+  port_ = nullptr;
+}
+
+
+std::atomic<int> Benchmark::CallbackBase::seq_num_ { 0 };
+
+Benchmark::CallbackBase::CallbackBase(int delegate_id, bool once)
+    : id_(delegate_id), once_(once) {
+  seq_id_ = seq_num_++;
+}
+
+int Benchmark::CallbackBase::GetId() const {
+  return id_;
+}
+
+int Benchmark::CallbackBase::GetSeqId() const {
+  return seq_id_;
+}
+
+bool Benchmark::CallbackBase::IsOnce() const {
+  return once_;
+}
+
+std::string Benchmark::CallbackBase::GetTag() const {
+  return std::to_string(id_) + "::" + std::to_string(seq_id_);
+}
+
+rpc_port_parcel_h operator << (rpc_port_parcel_h h, const Benchmark::CallbackBase& cb) {
+  rpc_port_parcel_write_int32(h, cb.id_);
+  rpc_port_parcel_write_int32(h, cb.seq_id_);
+  rpc_port_parcel_write_bool(h, cb.once_);
+
+  return h;
+}
+
+rpc_port_parcel_h operator >> (rpc_port_parcel_h h, Benchmark::CallbackBase& cb) {
+  rpc_port_parcel_read_int32(h, &cb.id_);
+  rpc_port_parcel_read_int32(h, &cb.seq_id_);
+  rpc_port_parcel_read_bool(h, &cb.once_);
+
+  return h;
+}
+
+Benchmark::Benchmark() {
+  int r = rpc_port_stub_create(&stub_, "Benchmark");
+  if (r != RPC_PORT_ERROR_NONE) {
+    _E("Failed to create stub handle");
+    throw InvalidIOException();
+  }
+  rpc_port_stub_add_connected_event_cb(stub_, OnConnectedCB, this);
+  rpc_port_stub_add_disconnected_event_cb(stub_, OnDisconnectedCB, this);
+  rpc_port_stub_add_received_event_cb(stub_, OnReceivedCB, this);
+}
+
+Benchmark::~Benchmark() {
+  for (auto& i : services_) {
+    i->OnTerminate();
+  }
+
+  if (stub_) {
+    rpc_port_stub_destroy(stub_);
+  }
+}
+
+void Benchmark::Listen(std::shared_ptr<Benchmark::ServiceBase::Factory> service_factory) {
+  service_factory_ = std::move(service_factory);
+  int r = rpc_port_stub_listen(stub_);
+  if (r != RPC_PORT_ERROR_NONE) {
+    _E("Failed to listen stub");
+    switch (r) {
+      case RPC_PORT_ERROR_INVALID_PARAMETER:
+      case RPC_PORT_ERROR_IO_ERROR:
+        throw InvalidIOException();
+    }
+  }
+}
+
+void Benchmark::OnConnectedCB(const char* sender, const char* instance, void* data) {
+  Benchmark* stub = static_cast<Benchmark*>(data);
+  auto s = stub->service_factory_->CreateService(sender, instance);
+
+  rpc_port_h port;
+  int ret = rpc_port_stub_get_port(stub->stub_, RPC_PORT_PORT_CALLBACK, instance, &port);
+  if (ret != RPC_PORT_ERROR_NONE) {
+    _E("Failed to get the port(%d)", ret);
+    return;
+  }
+
+  s->SetPort(port);
+  s->OnCreate();
+  stub->services_.emplace_back(std::move(s));
+}
+
+void Benchmark::OnDisconnectedCB(const char* sender, const char* instance, void *data) {
+  Benchmark* stub = static_cast<Benchmark*>(data);
+
+  for (auto& i : stub->services_) {
+    if (i->GetInstance() == instance) {
+      i->OnTerminate();
+      stub->services_.remove(i);
+      return;
+    }
+  }
+}
+
+int Benchmark::OnReceivedCB(const char* sender, const char* instance, rpc_port_h port, void *data)
+{
+  auto* cxt = static_cast<Benchmark*>(data);
+  rpc_port_parcel_h p;
+  rpc_port_parcel_h result;
+  rpc_port_parcel_header_h header;
+  int seq_num = -1;
+  int cmd;
+  int ret;
+  std::shared_ptr<ServiceBase> b;
+  rpc_port_h callback_port;
+
+  for (auto& i : cxt->services_) {
+    if (i->GetInstance() == instance) {
+      b = i;
+      break;
+    }
+  }
+
+  if (b.get() == nullptr) {
+    _E("Failed to find Benchmark context(%s)", instance);
+    return -1;
+  }
+
+  ret = rpc_port_stub_get_port(cxt->stub_, RPC_PORT_PORT_CALLBACK, instance,
+      &callback_port);
+  if (ret != 0) {
+    _E("Failed to get callback port");
+  }
+
+  ret = rpc_port_parcel_create_from_port(&p, port);
+  if (ret != 0) {
+    _E("Failed to create parcel from port");
+    return ret;
+  }
+
+  rpc_port_parcel_get_header(p, &header);
+  rpc_port_parcel_header_get_seq_num(header, &seq_num);
+
+  rpc_port_parcel_create(&result);
+  rpc_port_parcel_get_header(result, &header);
+  rpc_port_parcel_header_set_tag(header, TIDL_VERSION);
+  rpc_port_parcel_header_set_seq_num(header, seq_num);
+
+  rpc_port_parcel_read_int32(p, &cmd);
+
+  switch (cmd) {
+    case static_cast<int>(MethodId::Test): {
+      char* param1_raw  = nullptr;
+      rpc_port_parcel_read_string(p, &param1_raw);
+      std::string param1(param1_raw);
+      free(param1_raw);
+      auto retVal = b->Test(std::move(param1));
+      rpc_port_parcel_write_int32(result, static_cast<int>(MethodId::__Result));
+      rpc_port_parcel_write_int32(result, retVal);
+      rpc_port_parcel_send(result, port);
+      break;
+    }
+
+    default:
+      _E("Unknown command(%d)", cmd);
+      rpc_port_parcel_destroy(p);
+      rpc_port_parcel_destroy(result);
+      return -1;
+  }
+
+  rpc_port_parcel_destroy(p);
+  rpc_port_parcel_destroy(result);
+
+  return ret;
+}
+
+}  // namespace stub
+}  // namespace BenchmarkStub
+}  // namespace rpc_port
diff --git a/benchmark/server/tidl/BenchmarkStub.h b/benchmark/server/tidl/BenchmarkStub.h
new file mode 100644 (file)
index 0000000..ce6e039
--- /dev/null
@@ -0,0 +1,369 @@
+/*
+ * Generated by tidlc 2.0.4.
+ */
+
+#pragma once
+
+#include <bundle.h>
+#include <rpc-port-parcel.h>
+#include <rpc-port.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+#include <list>
+#include <atomic>
+#include <condition_variable>
+#include <mutex>
+#include <deque>
+#include <thread>
+
+namespace rpc_port {
+namespace BenchmarkStub {
+
+class Bundle final {
+ public:
+  Bundle() {
+    raw_ = bundle_create();
+  }
+
+  Bundle(bundle* b) {
+    raw_ = b;
+  }
+
+  ~Bundle() {
+    if (raw_)
+      bundle_free(raw_);
+  }
+
+  Bundle(Bundle&& b) : raw_(b.raw_) {
+    b.raw_ = nullptr;
+  }
+
+  Bundle& operator = (Bundle&& b) {
+    if (this != &b) {
+      if (raw_)
+        bundle_free(raw_);
+
+      raw_ = b.raw_;
+      b.raw_ = nullptr;
+    }
+    return *this;
+  }
+
+  Bundle(const Bundle& b) : raw_(bundle_dup(b.GetHandle())) {}
+
+  Bundle& operator = (const Bundle& b) {
+    if (this != &b) {
+      if (raw_)
+        bundle_free(raw_);
+
+      raw_ = bundle_dup(b.GetHandle());
+    }
+    return *this;
+  }
+
+  bundle* GetHandle() const {
+    return raw_;
+  }
+
+ private:
+  bundle* raw_;
+};
+
+class File final {
+ public:
+  File() {
+  }
+
+  File(std::string filename) {
+    filename_ = filename;
+  }
+
+  std::string GetFileName() const {
+    return filename_;
+  }
+
+ private:
+  std::string filename_;
+};
+
+namespace stub {
+
+class Exception {};
+class NotConnectedSocketException : public Exception {};
+class InvalidProtocolException : public Exception {};
+class InvalidIOException : public Exception {};
+class InvalidCallbackException : public Exception {};
+class Job {
+ public:
+  class IEvent {
+   public:
+    virtual ~IEvent() = default;
+    virtual void Run() = 0;
+  };
+
+  Job() : handler_(nullptr) {
+  }
+
+  Job(IEvent* handler) : handler_(handler) {
+  }
+  virtual ~Job() = default;
+
+  Job(const Job& job) {
+    handler_ = job.handler_;
+  }
+
+  Job& operator = (const Job& job) {
+    if (this != &job)
+      handler_ = job.handler_;
+    return *this;
+  }
+  Job(Job&& job) noexcept {
+    handler_ = job.handler_;
+    job.handler_ = nullptr;
+  }
+
+  Job& operator = (Job&& job) noexcept {
+    if (this != &job) {
+      handler_ = job.handler_;
+      job.handler_ = nullptr;
+    }
+    return *this;
+  }
+
+  void Invoke() {
+    if (handler_)
+      handler_->Run();
+  }
+
+ private:
+  IEvent* handler_;
+};
+
+
+template <class T>
+class SharedQueue {
+ public:
+  SharedQueue() = default;
+  virtual ~SharedQueue() = default;
+
+  void Push(T item) {
+    std::lock_guard<std::mutex> lock(mutex_);
+    queue_.push_back(item);
+    cond_var_.notify_one();
+  }
+
+  void PushFront(T item) {
+    std::lock_guard<std::mutex> lock(mutex_);
+    queue_.push_front(item);
+    cond_var_.notify_one();
+  }
+
+  bool TryAndPop(T& item) {
+    std::lock_guard<std::mutex> lock(mutex_);
+    if (queue_.empty())
+       return false;
+
+    item = queue_.front();
+    queue_.pop_front();
+
+    return true;
+  }
+
+  void WaitAndPop(T& item) {
+    std::unique_lock<std::mutex> lock(mutex_);
+    while (queue_.empty())
+      cond_var_.wait(lock);
+
+    item = queue_.front();
+    queue_.pop_front();
+  }
+
+  bool Empty() {
+    std::lock_guard<std::mutex> lock(mutex_);
+    return queue_.empty();
+  }
+
+  int Size() {
+    std::lock_guard<std::mutex> lock(mutex_);
+    return queue_.size();
+  }
+
+ private:
+  std::deque<T> queue_;
+  mutable std::mutex mutex_;
+  std::condition_variable cond_var_;
+};
+
+class ActiveObject : public Job::IEvent {
+ public:
+  ActiveObject() {
+    thread_ = std::thread([&]{
+          do {
+            std::shared_ptr<Job> item;
+            queue_.WaitAndPop(item);
+            item->Invoke();
+          } while (!done_);
+        });
+  }
+  virtual ~ActiveObject() {
+    Quit();
+    thread_.join();
+  }
+
+ public:
+  void Send(std::shared_ptr<Job> job) {
+    queue_.Push(std::move(job));
+  }
+
+ private:
+  void Quit() {
+    Send(std::shared_ptr<Job>(new (std::nothrow) Job(this)));
+  }
+  void Run() override {
+    done_ = true;
+  }
+
+ private:
+  std::thread thread_;
+  bool done_ = false;
+  SharedQueue<std::shared_ptr<Job>> queue_;
+};
+
+
+class Benchmark final {
+ public:
+  class ServiceBase;
+
+  class CallbackBase {
+   public:
+    CallbackBase(int delegate_id, bool once);
+    virtual ~CallbackBase() = default;
+
+    int GetId() const;
+    int GetSeqId() const;
+    bool IsOnce() const;
+    std::string GetTag() const;
+
+   private:
+    friend rpc_port_parcel_h operator << (rpc_port_parcel_h h, const CallbackBase& cb);
+    friend rpc_port_parcel_h operator >> (rpc_port_parcel_h h, CallbackBase& cb);
+
+    static std::atomic<int> seq_num_;
+    int id_;
+    int seq_id_;
+    bool once_;
+  };
+
+  class ServiceBase {
+   public:
+    class Factory {
+     public:
+      virtual ~Factory() = default;
+
+      /// <summary>
+      /// The method for making service instances
+      /// </summary>
+      /// <param name="sender">The client app ID</param>
+      /// <param name="instance">The client instance ID</param>
+      virtual std::unique_ptr<ServiceBase> CreateService(std::string sender, std::string instance) = 0;
+    };
+
+    virtual ~ServiceBase() = default;
+
+    /// <summary>
+    /// Gets client app ID
+    /// </summary>
+    const std::string& GetSender() const {
+      return sender_;
+    }
+
+    /// <summary>
+    /// Gets client instance ID
+    /// </summary>
+    const std::string& GetInstance() const {
+      return instance_;
+    }
+
+    /// <summary>
+    /// Sets the client app port
+    /// </summary>
+    /// <param name="port">The port of the client</param>
+    void SetPort(rpc_port_h port);
+
+    /// <summary>
+    /// Disconnects from the client app
+    /// </summary>
+    /// <exception cref="InvalidIOException">
+    /// Thrown when internal I/O error happen.
+    /// </exception>
+    void Disconnect();
+
+    /// <summary>
+    /// This method will be called when the client is connected
+    /// </summary>
+    virtual void OnCreate() = 0;
+
+    /// <summary>
+    /// This method will be called when the client is disconnected
+    /// </summary>
+    virtual void OnTerminate() = 0;
+
+    void Dispatch(rpc_port_h port, rpc_port_h callback_port,
+        rpc_port_parcel_h parcel, std::shared_ptr<ServiceBase> service);
+
+    virtual int Test(std::string data) = 0;
+
+   protected:
+    ServiceBase(std::string sender, std::string instance);
+
+   private:
+    std::string sender_;
+    std::string instance_;
+    rpc_port_h port_ = nullptr;
+    std::unique_ptr<ActiveObject> active_object_;
+  };
+
+  Benchmark();
+  ~Benchmark();
+
+  /// <summary>
+  /// Listens to client apps
+  /// </summary>
+  /// <param name="service_factory">The factory object for making service instances</param>
+  /// <exception cref="InvalidIOException">
+  /// Thrown when internal I/O error happen.
+  /// </exception>
+  void Listen(std::shared_ptr<ServiceBase::Factory> service_factory);
+
+  /// <summary>
+  /// Gets service objects which are connected
+  /// </summary>
+  /// <returns>The list of service objects which are connected</returns>
+  const std::list<std::shared_ptr<ServiceBase>>& GetServices() const {
+    return services_;
+  }
+
+ private:
+  enum class MethodId : int {
+    __Result = 0,
+    __Callback = 1,
+    Test = 2,
+
+  };
+
+  enum class DelegateId : int {
+
+  };
+  static void OnConnectedCB(const char* sender, const char* instance, void* data);
+  static void OnDisconnectedCB(const char* sender, const char* instance, void* data);
+  static int OnReceivedCB(const char* sender, const char* instance, rpc_port_h port, void* data);
+
+  rpc_port_stub_h stub_ = nullptr;
+  std::shared_ptr<ServiceBase::Factory> service_factory_;
+  std::list<std::shared_ptr<ServiceBase>> services_;
+};
+}  // namespace stub
+}  // namespace BenchmarkStub
+}  // namespace rpc_port
diff --git a/benchmark/server/tidl/CMakeLists.txt b/benchmark/server/tidl/CMakeLists.txt
new file mode 100644 (file)
index 0000000..ae94d6e
--- /dev/null
@@ -0,0 +1,22 @@
+AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} BENCHMARK_SERVER_SRCS)
+
+ADD_EXECUTABLE(${TARGET_BENCHMARK_SERVER} ${BENCHMARK_SERVER_SRCS})
+
+TARGET_INCLUDE_DIRECTORIES(${TARGET_BENCHMARK_SERVER} PUBLIC
+  ${CMAKE_CURRENT_SOURCE_DIR}
+  ${CMAKE_CURRENT_SOURCE_DIR}/../../../include/)
+
+APPLY_PKG_CONFIG(${TARGET_BENCHMARK_SERVER} PUBLIC
+  AUL_DEPS
+  DLOG_DEPS
+  GLIB_DEPS
+)
+
+TARGET_LINK_LIBRARIES(${TARGET_BENCHMARK_SERVER} PUBLIC
+  ${TARGET_RPC_PORT} "-lpthread")
+SET_TARGET_PROPERTIES(${TARGET_BENCHMARK_SERVER} PROPERTIES
+  COMPILE_FLAGS "-fPIE")
+SET_TARGET_PROPERTIES(${TARGET_BENCHMARK_SERVER} PROPERTIES
+  LINK_FLAGS "-pie")
+
+INSTALL(TARGETS ${TARGET_BENCHMARK_SERVER} DESTINATION bin)
diff --git a/benchmark/server/tidl/log-private.hh b/benchmark/server/tidl/log-private.hh
new file mode 100644 (file)
index 0000000..2f507b4
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LOG_PRIVATE_HH_
+#define LOG_PRIVATE_HH_
+
+#include <dlog.h>
+
+#undef LOG_TAG
+#define LOG_TAG "RPC_PORT_BENCHMARK_SERVER"
+
+#undef _E
+#define _E LOGE
+
+#undef _W
+#define _W LOGW
+
+#undef _I
+#define _I LOGI
+
+#undef _D
+#define _D LOGD
+
+#endif  // LOG_PRIVATE_HH_
diff --git a/benchmark/server/tidl/main.cc b/benchmark/server/tidl/main.cc
new file mode 100644 (file)
index 0000000..daac54c
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <glib.h>
+
+#include <aul_proc.h>
+
+#include "BenchmarkStub.h"
+#include "log-private.hh"
+
+namespace {
+constexpr const char SERVER_PROC_NAME[] = "org.tizen.appfw.rpc_port.benchmark";
+
+namespace bs = rpc_port::BenchmarkStub::stub;
+
+class TestService : public bs::Benchmark::ServiceBase {
+ public:
+  class Factory : public bs::Benchmark::ServiceBase::Factory {
+   public:
+    virtual ~Factory() = default;
+
+    std::unique_ptr<bs::Benchmark::ServiceBase>
+        CreateService(std::string sender, std::string instance) {
+      return std::unique_ptr<bs::Benchmark::ServiceBase>(
+          new TestService(std::move(sender), std::move(instance)));
+    }
+  };
+
+  TestService(std::string sender, std::string instance) :
+      bs::Benchmark::ServiceBase(std::move(sender), std::move(instance)) {}
+
+  virtual ~TestService() = default;
+
+  void OnCreate() override {
+  }
+
+  void OnTerminate() override {
+  }
+
+  int Test(std::string data) override {
+    return 0;
+  }
+};
+
+class MainLoop {
+ public:
+  MainLoop() {
+    loop_ = g_main_loop_new(nullptr, FALSE);
+  }
+
+  ~MainLoop() {
+    g_main_loop_unref(loop_);
+  }
+
+  void Run() {
+    int ret = aul_proc_register(SERVER_PROC_NAME, nullptr);
+    if (ret != AUL_R_OK) {
+      _E("aul_proc_register() failed (%d)", ret);
+      return;
+    }
+
+    try {
+      stub_.Listen(std::shared_ptr<bs::Benchmark::ServiceBase::Factory>(
+          new TestService::Factory()));
+    } catch (const bs::Exception&) {
+      _E("stub listen is failed");
+    }
+
+    g_main_loop_run(loop_);
+  }
+
+  void Quit() {
+    g_main_loop_quit(loop_);
+  }
+
+ private:
+  GMainLoop* loop_;
+  bs::Benchmark stub_;
+};
+
+}  // namespace
+
+int main(int argc, char** argv) {
+  MainLoop loop;
+  loop.Run();
+  return 0;
+}
diff --git a/benchmark/tool/dbus-proxy.cc b/benchmark/tool/dbus-proxy.cc
new file mode 100644 (file)
index 0000000..82f5b23
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "dbus-proxy.hh"
+#include "log-private.hh"
+
+namespace rpc_port {
+namespace benchmark {
+
+namespace {
+
+constexpr const char BUS_NAME[] = "tizen.appfw.rpcport.benchmark.dbus";
+constexpr const char OBJECT_PATH[] = "/tizen/appfw/rpcport/benchmark/dbus";
+constexpr const char INTERFACE_NAME[] = "tizen.appfw.rpcport.benchmark.dbus";
+
+}
+
+DbusProxy::DbusProxy() {
+}
+
+void DbusProxy::Connect() {
+  if (system_conn_ != nullptr)
+    return;
+
+  GError* error = nullptr;
+  system_conn_ = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, &error);
+  if (system_conn_ == nullptr) {
+    _E("g_bus_get_sync() is failed. error(%s)",
+        error ? error->message : "Unknown");
+    g_clear_error(&error);
+  }
+}
+
+int DbusProxy::Test(std::string data) const {
+  auto* msg = g_dbus_message_new_method_call(BUS_NAME,
+        OBJECT_PATH, INTERFACE_NAME, "Test");
+  if (msg == nullptr) {
+    _E("g_dbus_message_new_method_call() is failed");
+    return -1;
+  }
+  std::unique_ptr<GDBusMessage, decltype(g_object_unref)*> msg_auto(
+      msg, g_object_unref);
+
+  g_dbus_message_set_body(msg, g_variant_new("(s)", data.c_str()));
+  GError* error = nullptr;
+  auto* reply = g_dbus_connection_send_message_with_reply_sync(system_conn_, msg,
+      G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, nullptr, nullptr, &error);
+  if (reply == nullptr || error != nullptr) {
+    _E("g_dbus_connection_send_message_with_reply_sync() is failed. error(%s)",
+        error ? error->message : "Unknown");
+    g_clear_error(&error);
+    return -1;
+  }
+  std::unique_ptr<GDBusMessage, decltype(g_object_unref)*> reply_auto(
+      reply, g_object_unref);
+
+  auto* body = g_dbus_message_get_body(reply);
+  if (body == nullptr) {
+    _E("g_dbus_message_get_body() is failed");
+    return -1;
+  }
+
+  int ret = -1;
+  g_variant_get(body, "(i)", &ret);
+  return ret;
+}
+
+}  // namespace benchmark
+}  // namespace rpc_port
diff --git a/benchmark/tool/dbus-proxy.hh b/benchmark/tool/dbus-proxy.hh
new file mode 100644 (file)
index 0000000..7c5f4c4
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DBUS_PROXY_HH_
+#define DBUS_PROXY_HH_
+
+#include <string>
+#include <memory>
+
+#include <gio/gio.h>
+#include <glib.h>
+
+namespace rpc_port {
+namespace benchmark {
+
+class DbusProxy {
+ public:
+  DbusProxy();
+
+  void Connect();
+  int Test(std::string data) const;
+
+ private:
+  GDBusConnection* system_conn_ = nullptr;
+};
+
+}  // namespace benchmark
+}  // namespace rpc_port
+
+#endif  // DBUS_PROXY_HH_
index 1fae0e294477ebf7f09ef896176ad63b0e1db38b..d21d15037e58467f5943dc53a1e61ffb8477181b 100644 (file)
 #include "log-private.hh"
 #include "options.hh"
 #include "BenchmarkProxy.h"
+#include "dbus-proxy.hh"
 
 namespace {
 
 #define SERVER_PROC_NAME "org.tizen.appfw.rpc_port.benchmark"
 #define SERVER_BIN "/usr/bin/rpc-port-benchmark-server"
+#define SERVER_BIN_DBUS "/usr/bin/rpc-port-benchmark-server-dbus"
 
 namespace bp = rpc_port::BenchmarkProxy::proxy;
 
@@ -69,17 +71,21 @@ class Tester {
       return;
     }
 
-    ExecuteServer();
-    proxy_.reset(new bp::Benchmark(&listener_, SERVER_PROC_NAME));
-
-    try {
-      proxy_->Connect(true);
-    } catch (const bp::Exception& e) {
-      std::cerr << "Connect() failed" << std::endl;
-      return;
-    } catch (const std::exception& e) {
-      std::cerr << "Connect() failed. " << e.what() << std::endl;
-      return;
+    ExecuteServer(options_->IsDbus());
+    if (options_->IsDbus()) {
+      dbus_proxy_.Connect();
+    } else {
+      proxy_.reset(new bp::Benchmark(&listener_, SERVER_PROC_NAME));
+
+      try {
+        proxy_->Connect(true);
+      } catch (const bp::Exception& e) {
+        std::cerr << "Connect() failed" << std::endl;
+        return;
+      } catch (const std::exception& e) {
+        std::cerr << "Connect() failed. " << e.what() << std::endl;
+        return;
+      }
     }
 
     printf("%15s\t%15s\t%15s\t\t%15s\t\t%15s\n", "Iterations", "Data size",
@@ -111,6 +117,7 @@ class Tester {
  private:
   void DoTest(int iters, int size) {
     bool is_func = options_->IsFunction();
+    bool is_dbus = options_->IsDbus();
 
     StartTime();
     for (int i = 0; i < iters; i++) {
@@ -124,6 +131,16 @@ class Tester {
         continue;
       }
 
+      if (is_dbus) {
+        int ret = dbus_proxy_.Test(std::string(size, 'a'));
+        if (ret != 0) {
+          _E("Invalid return");
+          break;
+        }
+
+        continue;
+      }
+
       int ret = proxy_->Test(std::string(size, 'a'));
       if (ret != 0) {
         _E("Invalid return");
@@ -151,14 +168,20 @@ class Tester {
         sec.count(), t, l);
   }
 
-  void ExecuteServer() {
+  void ExecuteServer(bool is_dbus) {
     server_pid_ = fork();
     if (server_pid_ == 0) {
       setsid();
-
-      char bin[] = { SERVER_BIN };
-      char* argv[] = { bin, nullptr, nullptr };
-      int ret = execv(argv[0], argv);
+      int ret;
+      if (is_dbus) {
+        char bin[] = { SERVER_BIN_DBUS };
+        char* argv[] = { bin, nullptr, nullptr };
+        ret = execv(argv[0], argv);
+      } else {
+        char bin[] = { SERVER_BIN };
+        char* argv[] = { bin, nullptr, nullptr };
+        ret = execv(argv[0], argv);
+      }
       if (ret < 0) {
         std::cerr << "execv() is failed. errno: " << errno << std::endl;
         exit(-1);
@@ -178,6 +201,7 @@ class Tester {
   ConnectionListener listener_;
   std::chrono::system_clock::time_point start_;
   pid_t server_pid_ = -1;
+  rpc_port::benchmark::DbusProxy dbus_proxy_;
 };
 
 }  // namespace
index 38d9166d75e0cae1683938f401e94d5177581998..e4ab4b4afbf071f354334e9e96c58db1a6092391 100644 (file)
@@ -35,6 +35,7 @@ Help Options:
 
 Additional Options:
   -f, --funcation                     Use function call instead of RPC
+  -d, --dbus                          Use Dbus method instead of TIDL RPC
   -a, --all                           Test pre-defined test-cases
   -i, --interations=<Iterations>      Iterations
   -s, --size=<Data size>              Data size (byte)
@@ -68,12 +69,13 @@ std::unique_ptr<Options> Options::Parse(int argc, char** argv) {
     {"iterations", required_argument, nullptr, 'i'},
     {"size", required_argument, nullptr, 's'},
     {"function", no_argument, nullptr, 'f'},
+    {"dbus", no_argument, nullptr, 'd'},
     {"all", no_argument, nullptr, 'a'},
     {0, 0, 0, 0}
   };
 
   while (true) {
-    int c = getopt_long(argc, argv, "vhfai:s:", long_options,
+    int c = getopt_long(argc, argv, "vhfdai:s:", long_options,
         &option_index);
     if (c == -1)
       break;
@@ -105,6 +107,11 @@ std::unique_ptr<Options> Options::Parse(int argc, char** argv) {
         options->is_function_ = true;
         break;
 
+      case 'd':
+        opt[OPT_DBUS] = true;
+        options->is_dbus_ = true;
+        break;
+
       case 'a':
         opt[OPT_ALL] = true;
         options->is_all_ = true;
index 3b8fd4cf851b3e47c8a01eb2cbbffc3508e6cbbd..1a560f54bdc518adb0e9ff610ac4cb76b9dfc10e 100644 (file)
@@ -46,6 +46,10 @@ class Options {
     return is_all_;
   }
 
+  bool IsDbus() const {
+    return is_dbus_;
+  }
+
  private:
   enum Cmd {
     CMD_VERSION,
@@ -58,6 +62,7 @@ class Options {
     OPT_SIZE,
     OPT_ALL,
     OPT_FUNCTION,
+    OPT_DBUS,
     OPT_MAX
   };
 
@@ -71,6 +76,7 @@ class Options {
   std::string help_;
   bool is_function_ = false;
   bool is_all_ = false;
+  bool is_dbus_ = false;
 };
 
 }  // namespace benchmark
index 3da2551432bbcb3ae8167b6e35b66cda4709aeb4..998234b0c4de37ed3fb7b295d92b7205f35386b4 100644 (file)
@@ -153,10 +153,12 @@ install -m 0755 run-unittest.sh %{buildroot}%{_bindir}/tizen-unittests/%{name}/
 
 %files
 %manifest %{name}.manifest
+%config %{_sysconfdir}/dbus-1/system.d/rpc-port-benchmark.conf
 %attr(0644,root,root) %{_libdir}/lib%{name}.so.*
 %license LICENSE.APLv2
 %{_bindir}/rpc-port-util
 %{_bindir}/rpc-port-benchmark-server
+%{_bindir}/rpc-port-benchmark-server-dbus
 %{_bindir}/rpc-port-benchmark-tool
 %config %{_sysconfdir}/dbus-1/system.d/rpc-port.conf
 
diff --git a/socket_test/tool/main.cc b/socket_test/tool/main.cc
new file mode 100644 (file)
index 0000000..7241d29
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <chrono>
+#include <iostream>
+#include <rpc-port-parcel.h>
+
+#include "log-private.hh"
+
+namespace {
+
+constexpr const char SOCKET_PATH[] = "/run/.socket_test";
+
+class ClientSocket {
+ public:
+  ClientSocket() {
+    fd_ = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
+  }
+
+  ~ClientSocket() {
+    if (!IsClosed())
+      Close();
+  }
+
+  void Close() {
+    if (fd_ > -1) {
+      close(fd_);
+      fd_ = -1;
+    }
+  }
+
+  int Connect(const std::string& endpoint) {
+    struct sockaddr_un sockaddr = { 0, };
+    sockaddr.sun_family = AF_UNIX;
+    snprintf(sockaddr.sun_path, sizeof(sockaddr.sun_path), "%s",
+        endpoint.c_str());
+    struct sockaddr* sockaddr_ptr = reinterpret_cast<struct sockaddr*>(&sockaddr);
+    socklen_t len = sizeof(sockaddr);
+    int ret = connect(fd_, sockaddr_ptr, len);
+    if (ret < 0) {
+      ret = -errno;
+      _E("connect() is failed. errno(%d)", errno);
+      return ret;
+    }
+
+    return 0;
+  }
+
+  int Send(const void* buf, unsigned int size) {
+    const unsigned char* buffer = static_cast<const unsigned char*>(buf);
+    size_t len = size;
+    while (len) {
+      ssize_t bytes = send(fd_, buffer, len, MSG_NOSIGNAL);
+      if (bytes < 0) {
+        int ret = -errno;
+        _E("send() is failed. fd(%d), errno(%d)", fd_, errno);
+        return ret;
+      }
+
+      len -= bytes;
+      buffer += bytes;
+    }
+
+    return 0;
+  }
+
+  int Receive(void* buf, unsigned int size) {
+    unsigned char* buffer = static_cast<unsigned char*>(buf);
+    size_t len = size;
+    while (len) {
+      ssize_t bytes = read(fd_, buffer, len);
+      if (bytes == 0) {
+        _W("EOF. fd(%d)", fd_);
+        return -EIO;
+      }
+
+      if (bytes < 0)
+        return -errno;
+
+      len -= bytes;
+      buffer += bytes;
+    }
+
+    return 0;
+  }
+
+  bool IsClosed() {
+    return fd_ < 0 ? true : false;
+  }
+
+ private:
+  int fd_ = -1;
+};
+
+std::chrono::system_clock::time_point start_;
+
+void StartTime() {
+  start_ = std::chrono::system_clock::now();
+}
+
+void EndTime(int iters, int size) {
+  std::chrono::duration<double> sec = std::chrono::system_clock::now() - start_;
+  double t = size * iters * 8 / sec.count() / 1024 / 1024;
+  double l = sec.count() * 1000 / iters;
+
+  printf("%10d\t%10dByte\t%15.4fs\t%15.4fMb/s\t%15.4fms\n", iters, size,
+      sec.count(), t, l);
+}
+
+void DoTest(ClientSocket& sk, int iters, int size) {
+  StartTime();
+  rpc_port_parcel_h p;
+  rpc_port_parcel_create(&p);
+  for (int i = 0; i < iters; i++) {
+    
+    
+    std::string data(size, 'a');
+    rpc_port_parcel_write_string(p, data.c_str());
+
+    int ret = -1;
+    sk.Send(&size, sizeof(size));
+    sk.Send(data.c_str(), size);
+    sk.Receive(&ret, sizeof(ret));
+    if (ret != 9216) {
+      _E("Invalid return");
+      exit(1);
+    }
+  }
+  rpc_port_parcel_destroy(p);
+  EndTime(iters, size);
+}
+
+}
+
+int main(int argc, char** argv) {
+  ClientSocket sk;
+  sk.Connect(SOCKET_PATH);
+
+  printf("%15s\t%15s\t%15s\t\t%15s\t\t%15s\n", "Iterations", "Data size",
+      "Time", "Throughput", "Latency");
+  DoTest(sk, 4000, 10);
+  DoTest(sk, 4000, 20);
+  DoTest(sk, 4000, 100);
+  DoTest(sk, 4000, 200);
+  DoTest(sk, 2000, 1000);
+  DoTest(sk, 2000, 2000);
+  DoTest(sk, 1000, 10000);
+  DoTest(sk, 1000, 20000);
+  DoTest(sk, 1000, 30000);
+  DoTest(sk, 1000, 40000);
+  DoTest(sk, 1000, 50000);
+  DoTest(sk, 1000, 60000);
+  DoTest(sk, 500, 100000);
+
+  return 0;
+}