Add benchmark tool 52/317152/5 tizen
authorpjh9216 <jh9216.park@samsung.com>
Wed, 4 Sep 2024 23:25:09 +0000 (19:25 -0400)
committerpjh9216 <jh9216.park@samsung.com>
Thu, 5 Sep 2024 01:34:17 +0000 (10:34 +0900)
Change-Id: Ibf1b47dfa0517f968aadbafe4c811a5b564b27ff
Signed-off-by: pjh9216 <jh9216.park@samsung.com>
CMakeLists.txt
benchmark/CMakeLists.txt [new file with mode: 0644]
benchmark/log-private.hh [new file with mode: 0644]
benchmark/main.cc [new file with mode: 0644]
benchmark/options.cc [new file with mode: 0644]
benchmark/options.hh [new file with mode: 0644]
packaging/message-port-benchmark.manifest [new file with mode: 0644]
packaging/message-port.spec

index 66d5be3..ba61876 100644 (file)
@@ -16,6 +16,7 @@ SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed,--gc-sections -pie")
 SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules/")
 
 ## Targets
+SET(TARGET_MESSAGE_PORT_BENCHMARK "message-port-benchmark")
 SET(TARGET_MESSAGE_PORT "message-port")
 
 ENABLE_TESTING()
@@ -37,3 +38,4 @@ PKG_CHECK_MODULES(GMOCK_DEPS REQUIRED gmock)
 
 ADD_SUBDIRECTORY(src)
 ADD_SUBDIRECTORY(test)
+ADD_SUBDIRECTORY(benchmark)
diff --git a/benchmark/CMakeLists.txt b/benchmark/CMakeLists.txt
new file mode 100644 (file)
index 0000000..fc5d258
--- /dev/null
@@ -0,0 +1,26 @@
+ADD_DEFINITIONS("-DFULLVER=\"${FULLVER}\"")
+AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} BENCHMARK_SRCS)
+
+ADD_EXECUTABLE(${TARGET_MESSAGE_PORT_BENCHMARK}
+  ${BENCHMARK_SRCS}
+)
+
+TARGET_INCLUDE_DIRECTORIES(${TARGET_MESSAGE_PORT_BENCHMARK} PUBLIC
+  ${CMAKE_CURRENT_SOURCE_DIR}
+  ${CMAKE_CURRENT_SOURCE_DIR}/../include/)
+
+APPLY_PKG_CONFIG(${TARGET_MESSAGE_PORT_BENCHMARK} PUBLIC
+  AUL_DEPS
+  BUNDLE_DEPS
+  DLOG_DEPS
+  GLIB_DEPS
+)
+
+TARGET_LINK_LIBRARIES(${TARGET_MESSAGE_PORT_BENCHMARK} PUBLIC
+  ${TARGET_MESSAGE_PORT})
+SET_TARGET_PROPERTIES(${TARGET_MESSAGE_PORT_BENCHMARK} PROPERTIES
+  COMPILE_FLAGS "-fPIE")
+SET_TARGET_PROPERTIES(${TARGET_MESSAGE_PORT_BENCHMARK} PROPERTIES
+  LINK_FLAGS "-pie")
+
+INSTALL(TARGETS ${TARGET_MESSAGE_PORT_BENCHMARK} DESTINATION bin)
diff --git a/benchmark/log-private.hh b/benchmark/log-private.hh
new file mode 100644 (file)
index 0000000..fc84f6a
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * 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 LOG_PRIVATE_HH_
+#define LOG_PRIVATE_HH_
+
+#include <dlog.h>
+
+#undef LOG_TAG
+#define LOG_TAG "MESSAGE_PORT_BENCHMARK"
+
+#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/main.cc b/benchmark/main.cc
new file mode 100644 (file)
index 0000000..cf1882e
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * 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 <bundle_cpp.h>
+#include <glib.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <chrono>
+#include <ctime>
+#include <fstream>
+#include <iostream>
+#include <sstream>
+#include <string>
+
+#include "log-private.hh"
+#include "message_port.h"
+#include "options.hh"
+
+namespace {
+
+class Tester {
+ public:
+  Tester() {
+    setenv("AUL_APPID", "messageport.benchmark", 1);
+    setenv(
+        "DBUS_SESSION_BUS_ADDRESS",
+        "kernel:path=/sys/fs/kdbus/5001-user/bus;unix:path=/run/user/5001/bus",
+        1);
+    loop_ = g_main_loop_new(nullptr, FALSE);
+  }
+
+  ~Tester() { g_main_loop_unref(loop_); }
+
+  void Run(int argc, char** argv) {
+    options_ = message_port::benchmark::Options::Parse(argc, argv);
+    if (!options_) {
+      std::cerr << "options is unllptr" << std::endl;
+      return;
+    }
+
+    if (options_->ShouldPrintTime()) PrintStartTime();
+
+    printf("%15s\t%15s\t%15s\t\t%15s\t\t%15s\n", "Iterations", "Data size",
+           "Time", "Throughput", "Latency");
+
+    try {
+      if (options_->IsAll()) {
+        DoTest(4000, 10);
+        DoTest(4000, 20);
+        DoTest(4000, 100);
+        DoTest(4000, 200);
+        DoTest(2000, 1000);
+        DoTest(2000, 2000);
+        DoTest(1000, 10000);
+      } else {
+        DoTest(options_->GetIters(), options_->GetSize());
+      }
+    } catch (...) {
+      std::cerr << "test failed" << std::endl;
+    }
+  }
+
+ private:
+  void DoTest(int iters, int size) {
+    StartTime();
+    static int g_iters;
+    static int g_iters_org;
+    static int g_size;
+
+    g_iters = iters;
+    g_iters_org = iters;
+    g_size = size;
+    port_id_ = message_port_register_local_port(
+        "TestPort",
+        [](int local_port_id, const char* remote_app_id,
+           const char* remote_port, bool trusted_remote_port, bundle* message,
+           void* user_data) {
+          auto* tester = static_cast<Tester*>(user_data);
+          g_iters--;
+          if (g_iters <= 0) {
+            g_main_loop_quit(tester->loop_);
+            tester->EndTime(g_iters_org, g_size);
+          } else {
+            tizen_base::Bundle d = {{"ITER", std::to_string(g_iters)},
+                                    {"DATA", std::string(g_size, 'a')}};
+            message_port_send_message("messageport.benchmark", "TestPort",
+                                      d.GetHandle());
+          }
+        },
+        this);
+
+    tizen_base::Bundle d = {{"ITER", std::to_string(g_iters)},
+                            {"DATA", std::string(size, 'a')}};
+    message_port_send_message("messageport.benchmark", "TestPort",
+                              d.GetHandle());
+    g_main_loop_run(loop_);
+    message_port_unregister_local_port(port_id_);
+  }
+
+  int FakeFunction(std::string str) { return 0; }
+
+  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 * static_cast<double>(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 PrintStartTime() {
+    std::ifstream stat_file("/proc/self/stat");
+    if (!stat_file) {
+      _E("Failed to open stat");
+      return;
+    }
+
+    std::string line;
+    getline(stat_file, line);
+    std::istringstream iss(line);
+
+    std::string value;
+    int pos = 21;
+    for (int i = 0; i < pos; ++i) iss >> value;
+
+    iss >> value;
+    stat_file.close();
+
+    long start_time = std::stol(value) / sysconf(_SC_CLK_TCK);
+    time_t start_time_seconds = start_time;
+    long start_time_microseconds = (start_time - start_time_seconds) * 1000000;
+
+    std::time_t start_time_utc = std::time(nullptr) - start_time_seconds;
+    std::tm* start_time_tm = std::localtime(&start_time_utc);
+
+    char buffer[26];
+    std::strftime(buffer, sizeof(buffer), "%Y-%m %H:%M:%S", start_time_tm);
+
+    std::string result = buffer;
+    result += ".";
+    result += std::to_string(start_time_microseconds);
+    result += " UTC";
+
+    std::cout << "Program start time: [" << value << "] " << result
+              << std::endl;
+  }
+
+ private:
+  std::unique_ptr<message_port::benchmark::Options> options_;
+  std::chrono::system_clock::time_point start_;
+  int port_id_ = -1;
+  GMainLoop* loop_ = nullptr;
+};
+
+}  // namespace
+
+int main(int argc, char** argv) {
+  try {
+    Tester tester;
+    tester.Run(argc, argv);
+  } catch (...) {
+    _E("Exception occurs");
+    return -1;
+  }
+
+  return 0;
+}
diff --git a/benchmark/options.cc b/benchmark/options.cc
new file mode 100644 (file)
index 0000000..f48e413
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * 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 "options.hh"
+
+#include <getopt.h>
+
+#include <cstring>
+#include <iostream>
+#include <memory>
+
+namespace message_port {
+namespace benchmark {
+
+Options::Options() {
+  help_ = R"__option_cb(
+Usage:
+  message-port-benchmark [OPTION...]
+
+Help Options:
+  -h, --help                  Show help options
+
+Additional Options:
+  -a, --all                           Test pre-defined test-cases
+  -i, --interations=<Iterations>      Iterations
+  -s, --size=<Data size>              Data size (byte)
+  -t, --time                          Print starting time of this tool
+
+Application Options:
+  -v, --version               Show version information
+)__option_cb";
+}
+
+void Options::PrintUsage() { std::cerr << help_ << std::endl; }
+
+void Options::PrintVersion() {
+  std::cerr << "message-port-benchmark " << FULLVER << std::endl;
+}
+
+void Options::PrintSample() {
+  std::cerr << "message-port-benchmark -i 1000 -s 10000" << std::endl;
+}
+
+std::unique_ptr<Options> Options::Parse(int argc, char** argv) {
+  bool cmd[CMD_MAX] = {
+      false,
+  };
+  bool opt[OPT_MAX] = {
+      false,
+  };
+  auto options = std::unique_ptr<Options>(new Options());
+  int option_index = 0;
+
+  struct option long_options[] = {
+      {"version", no_argument, nullptr, 'v'},
+      {"help", no_argument, nullptr, 'h'},
+      {"iterations", required_argument, nullptr, 'i'},
+      {"size", required_argument, nullptr, 's'},
+      {"all", no_argument, nullptr, 'a'},
+      {"time", no_argument, nullptr, 't'},
+      {0, 0, 0, 0}};
+
+  while (true) {
+    int c = getopt_long(argc, argv, "vhati:s:", long_options, &option_index);
+    if (c == -1) break;
+
+    switch (c) {
+      case 0:
+        break;
+
+      case 'v':
+        cmd[CMD_VERSION] = true;
+        break;
+
+      case 'h':
+        cmd[CMD_HELP] = true;
+        break;
+
+      case 'i':
+        opt[OPT_ITER] = true;
+        options->iters_ = std::stoi(optarg);
+        break;
+
+      case 's':
+        opt[OPT_SIZE] = true;
+        options->size_ = std::stoi(optarg);
+        break;
+
+      case 'a':
+        opt[OPT_ALL] = true;
+        options->is_all_ = true;
+        break;
+
+      case 't':
+        opt[OPT_TIME] = true, options->should_print_time_ = true;
+        break;
+
+      default:
+        cmd[CMD_HELP] = true;
+    }
+  }
+
+  if (cmd[CMD_VERSION]) {
+    options->PrintVersion();
+    return std::unique_ptr<Options>(nullptr);
+  }
+
+  if (cmd[CMD_HELP]) {
+    options->PrintUsage();
+    return std::unique_ptr<Options>(nullptr);
+  } else if (opt[OPT_ALL]) {
+    return options;
+  } else if (!opt[OPT_ITER] || !opt[OPT_SIZE]) {
+    options->PrintSample();
+    return std::unique_ptr<Options>(nullptr);
+  }
+
+  return options;
+}
+
+}  // namespace benchmark
+}  // namespace message_port
diff --git a/benchmark/options.hh b/benchmark/options.hh
new file mode 100644 (file)
index 0000000..dfd77f0
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * 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 OPTIONS_HH_
+#define OPTIONS_HH_
+
+#include <memory>
+#include <string>
+
+namespace message_port {
+namespace benchmark {
+
+class Options {
+ public:
+  Options();
+  ~Options() = default;
+
+  static std::unique_ptr<Options> Parse(int argc, char** argv);
+
+  int GetIters() const { return iters_; }
+  int GetSize() const { return size_; }
+  bool IsAll() const { return is_all_; }
+  bool ShouldPrintTime() const { return should_print_time_; }
+
+ private:
+  enum Cmd { CMD_VERSION, CMD_HELP, CMD_MAX };
+  enum Opt { OPT_ITER, OPT_SIZE, OPT_ALL, OPT_TIME, OPT_MAX };
+
+  void PrintUsage();
+  void PrintVersion();
+  void PrintSample();
+
+ private:
+  int iters_ = 0;
+  int size_ = 0;
+  std::string help_;
+  bool is_function_ = false;
+  bool is_all_ = false;
+  bool should_print_time_ = false;
+};
+
+}  // namespace benchmark
+}  // namespace message_port
+
+#endif  // OPTIONS_HH_
diff --git a/packaging/message-port-benchmark.manifest b/packaging/message-port-benchmark.manifest
new file mode 100644 (file)
index 0000000..97e8c31
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>
+       <request>
+               <domain name="_"/>
+       </request>
+</manifest>
index ed129c4..e4d4b29 100644 (file)
@@ -6,6 +6,7 @@ Group:      Application Framework/Libraries
 License:    Apache-2.0
 Source0:    %{name}-%{version}.tar.gz
 Source1001: %{name}.manifest
+Source1002: %{name}-benchmark.manifest
 BuildRequires:  cmake
 BuildRequires:  pkgconfig(dlog)
 BuildRequires:  pkgconfig(bundle)
@@ -52,9 +53,18 @@ Summary:    %{name} unittests binary
 %description unittests
 unittests binary
 
+%package -n %{name}-benchmark
+Summary:    Benchmark for message-port API
+Group:      Application Framework/Testing
+Requires:   %{name}
+
+%description -n %{name}-benchmark
+Benchmark for message-port API
+
 %prep
 %setup -q
 cp %{SOURCE1001} .
+cp %{SOURCE1002} .
 
 %build
 %if 0%{?gcov:1}
@@ -137,6 +147,10 @@ genhtml %{name}.info -o out --legend --show-details
 %attr(0755,root,root) %{_bindir}/message-port-unit-test
 %attr(0755,root,root) %{_bindir}/tizen-unittests/%{name}/run-unittest.sh
 
+%files -n %{name}-benchmark
+%manifest %{name}-benchmark.manifest
+%{_bindir}/%{name}-benchmark
+
 %if 0%{?gcov:1}
 %files gcov
 %{_datadir}/gcov/*