From: pjh9216 Date: Wed, 4 Sep 2024 23:25:09 +0000 (-0400) Subject: Add benchmark tool X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;p=platform%2Fcore%2Fappfw%2Fmessage-port.git Add benchmark tool Change-Id: Ibf1b47dfa0517f968aadbafe4c811a5b564b27ff Signed-off-by: pjh9216 --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 66d5be3..ba61876 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 index 0000000..fc5d258 --- /dev/null +++ b/benchmark/CMakeLists.txt @@ -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 index 0000000..fc84f6a --- /dev/null +++ b/benchmark/log-private.hh @@ -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 + +#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 index 0000000..cf1882e --- /dev/null +++ b/benchmark/main.cc @@ -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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#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(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 sec = + std::chrono::system_clock::now() - start_; + double t = + size * static_cast(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 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 index 0000000..f48e413 --- /dev/null +++ b/benchmark/options.cc @@ -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 + +#include +#include +#include + +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 + -s, --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::Parse(int argc, char** argv) { + bool cmd[CMD_MAX] = { + false, + }; + bool opt[OPT_MAX] = { + false, + }; + auto options = std::unique_ptr(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(nullptr); + } + + if (cmd[CMD_HELP]) { + options->PrintUsage(); + return std::unique_ptr(nullptr); + } else if (opt[OPT_ALL]) { + return options; + } else if (!opt[OPT_ITER] || !opt[OPT_SIZE]) { + options->PrintSample(); + return std::unique_ptr(nullptr); + } + + return options; +} + +} // namespace benchmark +} // namespace message_port diff --git a/benchmark/options.hh b/benchmark/options.hh new file mode 100644 index 0000000..dfd77f0 --- /dev/null +++ b/benchmark/options.hh @@ -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 +#include + +namespace message_port { +namespace benchmark { + +class Options { + public: + Options(); + ~Options() = default; + + static std::unique_ptr 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 index 0000000..97e8c31 --- /dev/null +++ b/packaging/message-port-benchmark.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/packaging/message-port.spec b/packaging/message-port.spec index ed129c4..e4d4b29 100644 --- a/packaging/message-port.spec +++ b/packaging/message-port.spec @@ -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/*