diff --git a/CMakeLists.txt b/CMakeLists.txt index cc5d56f..80c5fd8 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -124,6 +124,16 @@ if(BUILD_CODE_GEN) add_subdirectory("${CMAKE_SOURCE_DIR}/stub-generator") endif() +#---------------------------------- +# PERFORMANCE TESTS +#---------------------------------- + +option(ENABLE_PERFTESTS "Build and install performance tests (default OFF)" OFF) + +if(ENABLE_PERFTESTS) + add_subdirectory("${CMAKE_SOURCE_DIR}/perftest") +endif() + #---------------------------------- # DOCUMENTATION #---------------------------------- diff --git a/perftest/CMakeLists.txt b/perftest/CMakeLists.txt new file mode 100644 index 0000000..99b1755 --- /dev/null +++ b/perftest/CMakeLists.txt @@ -0,0 +1,26 @@ +#------------------------------- +# GENERAL COMPILER CONFIGURATION +#------------------------------- + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) + +#---------------------------------- +# BUILD INFORMATION +#---------------------------------- + +# Turn off -isystem gcc option that CMake uses for imported +# targets even when INTERFACE_INCLUDE_DIRECTORIES is used. +#set(CMAKE_NO_SYSTEM_FROM_IMPORTED "1") + +add_executable(perftestclient client.cpp perftest-proxy.h) +target_link_libraries(perftestclient sdbus-c++) + +add_executable(perftestserver server.cpp perftest-adaptor.h) +target_link_libraries(perftestserver sdbus-c++) + +#---------------------------------- +# INSTALLATION +#---------------------------------- + +install(TARGETS perftestclient DESTINATION /opt/test/bin) +install(TARGETS perftestserver DESTINATION /opt/test/bin) diff --git a/perftest/client.cpp b/perftest/client.cpp new file mode 100644 index 0000000..8ef4414 --- /dev/null +++ b/perftest/client.cpp @@ -0,0 +1,137 @@ +#include "perftest-proxy.h" +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std::chrono_literals; + +class PerftestClient : public sdbus::ProxyInterfaces +{ +public: + PerftestClient(std::string destination, std::string objectPath) + : sdbus::ProxyInterfaces(std::move(destination), std::move(objectPath)) + { + } + +protected: + virtual void onDataSignal(const std::string& data) override + { + static unsigned int counter = 0; + static std::chrono::time_point startTime; + + assert(data.size() == m_msgSize); + + ++counter; + + if (counter == 1) + startTime = std::chrono::steady_clock::now(); + else if (counter == m_msgCount) + { + auto stopTime = std::chrono::steady_clock::now(); + std::cout << "Received " << m_msgCount << " signals in: " << std::chrono::duration_cast(stopTime - startTime).count() << " ms" << std::endl; + counter = 0; + } + } + +public: + unsigned int m_msgSize{}; + unsigned int m_msgCount{}; +}; + +std::string createRandomString(size_t length) +{ + auto randchar = []() -> char + { + const char charset[] = + "0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz"; + const size_t max_index = (sizeof(charset) - 1); + return charset[ rand() % max_index ]; + }; + std::string str(length, 0); + std::generate_n(str.begin(), length, randchar); + return str; +} + + +//----------------------------------------- +int main(int /*argc*/, char */*argv*/[]) +{ + const char* destinationName = "org.sdbuscpp.perftest"; + const char* objectPath = "/org/sdbuscpp/perftest"; + PerftestClient client(destinationName, objectPath); + + const unsigned int repetitions{20}; + unsigned int msgCount = 1000; + unsigned int msgSize{}; + + msgSize = 20; + std::cout << "** Measuring signals of size " << msgSize << " bytes (" << repetitions << " repetitions)..." << std::endl << std::endl; + client.m_msgCount = msgCount; client.m_msgSize = msgSize; + for (unsigned int r = 0; r < repetitions; ++r) + { + client.sendDataSignals(msgCount, msgSize); + + std::this_thread::sleep_for(1000ms); + } + + msgSize = 1000; + std::cout << std::endl << "** Measuring signals of size " << msgSize << " bytes (" << repetitions << " repetitions)..." << std::endl << std::endl; + client.m_msgCount = msgCount; client.m_msgSize = msgSize; + for (unsigned int r = 0; r < repetitions; ++r) + { + client.sendDataSignals(msgCount, msgSize); + + std::this_thread::sleep_for(1000ms); + } + + msgSize = 20; + std::cout << std::endl << "** Measuring method calls of size " << msgSize << " bytes (" << repetitions << " repetitions)..." << std::endl << std::endl; + for (unsigned int r = 0; r < repetitions; ++r) + { + auto str1 = createRandomString(msgSize/2); + auto str2 = createRandomString(msgSize/2); + + auto startTime = std::chrono::steady_clock::now(); + for (unsigned int i = 0; i < msgCount; i++) + { + auto result = client.concatenateTwoStrings(str1, str2); + + assert(result.size() == str1.size() + str2.size()); + assert(result.size() == msgSize); + } + auto stopTime = std::chrono::steady_clock::now(); + std::cout << "Called " << msgCount << " methods in: " << std::chrono::duration_cast(stopTime - startTime).count() << " ms" << std::endl; + + std::this_thread::sleep_for(1000ms); + } + + msgSize = 1000; + std::cout << std::endl << "** Measuring method calls of size " << msgSize << " bytes (" << repetitions << " repetitions)..." << std::endl << std::endl; + for (unsigned int r = 0; r < repetitions; ++r) + { + auto str1 = createRandomString(msgSize/2); + auto str2 = createRandomString(msgSize/2); + + auto startTime = std::chrono::steady_clock::now(); + for (unsigned int i = 0; i < msgCount; i++) + { + auto result = client.concatenateTwoStrings(str1, str2); + + assert(result.size() == str1.size() + str2.size()); + assert(result.size() == msgSize); + } + auto stopTime = std::chrono::steady_clock::now(); + std::cout << "Called " << msgCount << " methods in: " << std::chrono::duration_cast(stopTime - startTime).count() << " ms" << std::endl; + + std::this_thread::sleep_for(1000ms); + } + + return 0; +} diff --git a/perftest/org.sdbuscpp.perftest.conf b/perftest/org.sdbuscpp.perftest.conf new file mode 100644 index 0000000..c5bae6e --- /dev/null +++ b/perftest/org.sdbuscpp.perftest.conf @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + diff --git a/perftest/org.sdbuscpp.perftest.xml b/perftest/org.sdbuscpp.perftest.xml new file mode 100644 index 0000000..cb0f363 --- /dev/null +++ b/perftest/org.sdbuscpp.perftest.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/perftest/perftest-adaptor.h b/perftest/perftest-adaptor.h new file mode 100644 index 0000000..e06c0ed --- /dev/null +++ b/perftest/perftest-adaptor.h @@ -0,0 +1,46 @@ + +/* + * This file was automatically generated by sdbuscpp-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__perftest_adaptor_h__adaptor__H__ +#define __sdbuscpp__perftest_adaptor_h__adaptor__H__ + +#include +#include +#include + +namespace org { +namespace sdbuscpp { + +class perftest_adaptor +{ +public: + static constexpr const char* interfaceName = "org.sdbuscpp.perftest"; + +protected: + perftest_adaptor(sdbus::IObject& object) + : object_(object) + { + object_.registerMethod("sendDataSignals").onInterface(interfaceName).implementedAs([this](const uint32_t& numberOfSignals, const uint32_t& signalMsgSize){ return this->sendDataSignals(numberOfSignals, signalMsgSize); }); + object_.registerMethod("concatenateTwoStrings").onInterface(interfaceName).implementedAs([this](const std::string& string1, const std::string& string2){ return this->concatenateTwoStrings(string1, string2); }); + object_.registerSignal("dataSignal").onInterface(interfaceName).withParameters(); + } + +public: + void dataSignal(const std::string& data) + { + object_.emitSignal("dataSignal").onInterface(interfaceName).withArguments(data); + } + +private: + virtual void sendDataSignals(const uint32_t& numberOfSignals, const uint32_t& signalMsgSize) = 0; + virtual std::string concatenateTwoStrings(const std::string& string1, const std::string& string2) = 0; + +private: + sdbus::IObject& object_; +}; + +}} // namespaces + +#endif diff --git a/perftest/perftest-proxy.h b/perftest/perftest-proxy.h new file mode 100644 index 0000000..16b80ed --- /dev/null +++ b/perftest/perftest-proxy.h @@ -0,0 +1,49 @@ + +/* + * This file was automatically generated by sdbuscpp-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__perftest_proxy_h__proxy__H__ +#define __sdbuscpp__perftest_proxy_h__proxy__H__ + +#include +#include +#include + +namespace org { +namespace sdbuscpp { + +class perftest_proxy +{ +public: + static constexpr const char* interfaceName = "org.sdbuscpp.perftest"; + +protected: + perftest_proxy(sdbus::IObjectProxy& object) + : object_(object) + { + object_.uponSignal("dataSignal").onInterface(interfaceName).call([this](const std::string& data){ this->onDataSignal(data); }); + } + + virtual void onDataSignal(const std::string& data) = 0; + +public: + void sendDataSignals(const uint32_t& numberOfSignals, const uint32_t& signalMsgSize) + { + object_.callMethod("sendDataSignals").onInterface(interfaceName).withArguments(numberOfSignals, signalMsgSize); + } + + std::string concatenateTwoStrings(const std::string& string1, const std::string& string2) + { + std::string result; + object_.callMethod("concatenateTwoStrings").onInterface(interfaceName).withArguments(string1, string2).storeResultsTo(result); + return result; + } + +private: + sdbus::IObjectProxy& object_; +}; + +}} // namespaces + +#endif diff --git a/perftest/server.cpp b/perftest/server.cpp new file mode 100644 index 0000000..aaa1594 --- /dev/null +++ b/perftest/server.cpp @@ -0,0 +1,69 @@ +#include "perftest-adaptor.h" +#include +#include +#include +#include +#include + +using namespace std::chrono_literals; + +std::string createRandomString(size_t length); + +class PerftestServer : public sdbus::Interfaces +{ +public: + PerftestServer(sdbus::IConnection& connection, std::string objectPath) + : sdbus::Interfaces(connection, std::move(objectPath)) + { + } + +protected: + virtual void sendDataSignals(const uint32_t& numberOfSignals, const uint32_t& signalMsgSize) override + { + auto data = createRandomString(signalMsgSize); + char digits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; + + auto start_time = std::chrono::steady_clock::now(); + for (uint32_t i = 0; i < numberOfSignals; ++i) + { + // Emit signal + dataSignal(data); + } + auto stop_time = std::chrono::steady_clock::now(); + std::cout << "Server sent " << numberOfSignals << " signals in: " << std::chrono::duration_cast(stop_time - start_time).count() << " ms" << std::endl; + } + + virtual std::string concatenateTwoStrings(const std::string& string1, const std::string& string2) override + { + return string1 + string2; + } +}; + +std::string createRandomString(size_t length) +{ + auto randchar = []() -> char + { + const char charset[] = + "0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz"; + const size_t max_index = (sizeof(charset) - 1); + return charset[ rand() % max_index ]; + }; + std::string str(length, 0); + std::generate_n(str.begin(), length, randchar); + return str; +} + + +//----------------------------------------- +int main(int /*argc*/, char */*argv*/[]) +{ + const char* serviceName = "org.sdbuscpp.perftest"; + auto connection = sdbus::createSystemBusConnection(serviceName); + + const char* objectPath = "/org/sdbuscpp/perftest"; + PerftestServer server(*connection, objectPath); + + connection->enterProcessingLoop(); +}