forked from Kistler-Group/sdbus-cpp
Compare commits
10 Commits
Author | SHA1 | Date | |
---|---|---|---|
8c76e3ef8b | |||
a6d0b62ff5 | |||
757cc44381 | |||
6dbcbbfa98 | |||
b813680192 | |||
84b15776a3 | |||
8c5c774727 | |||
cd1efd66a5 | |||
fad81e7659 | |||
1dafd6262c |
@ -4,7 +4,7 @@
|
||||
|
||||
cmake_minimum_required(VERSION 3.8)
|
||||
|
||||
project(sdbus-c++ VERSION 0.4.1 LANGUAGES C CXX)
|
||||
project(sdbus-c++ VERSION 0.4.2 LANGUAGES C CXX)
|
||||
|
||||
include(GNUInstallDirs) # Installation directories for `install` command and pkgconfig file
|
||||
|
||||
@ -134,12 +134,15 @@ endif()
|
||||
# CMAKE CONFIG & PACKAGE CONFIG
|
||||
#----------------------------------
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
set(SDBUSCPP_CONFIG_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/sdbus-c++)
|
||||
|
||||
configure_file(sdbus-c++-config.cmake.in sdbus-c++-config.cmake @ONLY)
|
||||
install(FILES ${CMAKE_BINARY_DIR}/sdbus-c++-config.cmake DESTINATION ${SDBUSCPP_CONFIG_INSTALL_DIR} COMPONENT dev)
|
||||
|
||||
configure_file(sdbus-c++-config-version.cmake.in sdbus-c++-config-version.cmake @ONLY)
|
||||
write_basic_package_version_file(sdbus-c++-config-version.cmake
|
||||
VERSION ${PROJECT_VERSION}
|
||||
COMPATIBILITY AnyNewerVersion)
|
||||
install(FILES ${CMAKE_BINARY_DIR}/sdbus-c++-config-version.cmake DESTINATION ${SDBUSCPP_CONFIG_INSTALL_DIR} COMPONENT dev)
|
||||
|
||||
configure_file(sdbus-c++.pc.in sdbus-c++.pc @ONLY)
|
||||
|
91
ChangeLog
91
ChangeLog
@ -1,43 +1,48 @@
|
||||
v0.2.3
|
||||
- Initially published version
|
||||
|
||||
v0.2.4
|
||||
- Fixed closing of file descriptor of event loop's semaphore on exec
|
||||
- Fixed interrupt handling when polling
|
||||
- Improved tutorial
|
||||
- Fixed issue with googlemock
|
||||
- Added object proxy factory overload that takes unique_ptr to a connection
|
||||
- Workaround: Clang compilation error when compiling sdbus::Struct (seems like an issue of Clang)
|
||||
|
||||
v0.2.5
|
||||
- Real fix for issue with sdbus::Struct inherited constructors
|
||||
- Little code refactorings and improvements
|
||||
|
||||
v0.2.6
|
||||
- Fixed memory leak in Message copy operations
|
||||
|
||||
v0.3.0
|
||||
- Introduced support for asynchronous server-side methods
|
||||
- Refactored the concept of Message into distinctive concrete message types
|
||||
- As this release comes with breaking API changes:
|
||||
* if you're using lower-level API, please rename 'Message' to whatever concrete message type (MethodCall, MethodReply, Signal) is needed there,
|
||||
* if you're using higher-level API, please re-compile and re-link your application against sdbus-c++,
|
||||
* if you're using generated stub headers, please re-compile and re-link your application against sdbus-c++.
|
||||
|
||||
v0.3.1
|
||||
- Fixed hogging the CPU by server with async methods (issue #15)
|
||||
|
||||
v0.3.2
|
||||
- Switched from autotools to CMake build system
|
||||
|
||||
v0.3.3
|
||||
- Minor fixes in tutorial examples
|
||||
- Add comment on threading traits of Variant and its const methods
|
||||
- Fix broken invariant of const Variant::peekValueType() method
|
||||
|
||||
v0.4.0
|
||||
- Introduce support and implementation of common D-Bus annotations
|
||||
- Remove hard-coded warning-related compiler options from the build system
|
||||
|
||||
v0.4.1
|
||||
- Change constexpr member into a getter method to be compatible across odr-usage rules of various compiler versions
|
||||
v0.2.3
|
||||
- Initially published version
|
||||
|
||||
v0.2.4
|
||||
- Fixed closing of file descriptor of event loop's semaphore on exec
|
||||
- Fixed interrupt handling when polling
|
||||
- Improved tutorial
|
||||
- Fixed issue with googlemock
|
||||
- Added object proxy factory overload that takes unique_ptr to a connection
|
||||
- Workaround: Clang compilation error when compiling sdbus::Struct (seems like an issue of Clang)
|
||||
|
||||
v0.2.5
|
||||
- Real fix for issue with sdbus::Struct inherited constructors
|
||||
- Little code refactorings and improvements
|
||||
|
||||
v0.2.6
|
||||
- Fixed memory leak in Message copy operations
|
||||
|
||||
v0.3.0
|
||||
- Introduced support for asynchronous server-side methods
|
||||
- Refactored the concept of Message into distinctive concrete message types
|
||||
- As this release comes with breaking API changes:
|
||||
* if you're using lower-level API, please rename 'Message' to whatever concrete message type (MethodCall, MethodReply, Signal) is needed there,
|
||||
* if you're using higher-level API, please re-compile and re-link your application against sdbus-c++,
|
||||
* if you're using generated stub headers, please re-compile and re-link your application against sdbus-c++.
|
||||
|
||||
v0.3.1
|
||||
- Fixed hogging the CPU by server with async methods (issue #15)
|
||||
|
||||
v0.3.2
|
||||
- Switched from autotools to CMake build system
|
||||
|
||||
v0.3.3
|
||||
- Minor fixes in tutorial examples
|
||||
- Add comment on threading traits of Variant and its const methods
|
||||
- Fix broken invariant of const Variant::peekValueType() method
|
||||
|
||||
v0.4.0
|
||||
- Introduce support and implementation of common D-Bus annotations
|
||||
- Remove hard-coded warning-related compiler options from the build system
|
||||
|
||||
v0.4.1
|
||||
- Change constexpr member into a getter method to be compatible across odr-usage rules of various compiler versions
|
||||
|
||||
v0.4.2
|
||||
- Improve documentation
|
||||
- Minor code improvements
|
||||
- Introduce sdbus-c++ performance tests with measurements
|
||||
|
@ -38,6 +38,7 @@ References/documentation
|
||||
* [D-Bus Specification](https://dbus.freedesktop.org/doc/dbus-specification.html)
|
||||
* [sd-bus Overview](http://0pointer.net/blog/the-new-sd-bus-api-of-systemd.html)
|
||||
* [Tutorial: Using sdbus-c++](doc/using-sdbus-c++.md)
|
||||
* [Systemd and dbus configuration](doc/systemd-dbus-config.md)
|
||||
|
||||
Contributing
|
||||
------------
|
||||
|
54
doc/systemd-dbus-config.md
Normal file
54
doc/systemd-dbus-config.md
Normal file
@ -0,0 +1,54 @@
|
||||
Systemd and dbus configuration
|
||||
=======================
|
||||
|
||||
**Table of contents**
|
||||
|
||||
1. [Introduction](#introduction)
|
||||
2. [Systemd configuration](#systemd-configuration)
|
||||
3. [Dbus configuration](#dbus-configuration)
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
To run executable as a systemd service you may need some additional setup. For example, you may need explicitly allow
|
||||
the usage of your service. Following chapters contain template configurations.
|
||||
|
||||
|
||||
Systemd configuration
|
||||
---------------------------------------
|
||||
|
||||
Filename should use `.service` extension. It also must be placed in configuration directory (/etc/systemd/system in
|
||||
Ubuntu 18.04.1 LTS)
|
||||
|
||||
```
|
||||
[Unit]
|
||||
Description=nameOfService
|
||||
|
||||
[Service]
|
||||
ExecStart=/path/to/executable
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
Dbus configuration
|
||||
------------------
|
||||
|
||||
Typical default D-Bus configuration does not allow to register services except explicitly allowed. Filename should
|
||||
contain name of your service, e.g `/etc/dbus-1/system.d/org.sdbuscpp.concatenator.conf`. So, here is template
|
||||
configuration to use dbus interface under root:
|
||||
|
||||
```
|
||||
<!DOCTYPE busconfig PUBLIC
|
||||
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
|
||||
<busconfig>
|
||||
<policy user="root">
|
||||
<allow own="org.sdbuscpp.concatenator"/>
|
||||
<allow send_destination="org.sdbuscpp"/>
|
||||
<allow send_interface="org.sdbuscpp.concatenator"/>
|
||||
</policy>
|
||||
</busconfig>
|
||||
```
|
||||
|
||||
If you need access from other user `root` should be substituted by desired username. For more refer to `man dbus-daemon`.
|
@ -256,9 +256,15 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
```
|
||||
|
||||
The object proxy can be created by either explicitly passing the connection object to it, or without the connection object. In the former case, we have the freedom of creating our own connection (to either system bus or to session bus) and then we can just move that connection object as the first argument of the proxy factory. The latter option is more convenient (no messing with connection for proxy), the proxy will create and manage its own connection, but the limitation is that it will be the connection to the **system** bus only.
|
||||
### Proxy and D-Bus connection
|
||||
|
||||
If there are callbacks for signals, proxy will start listening to the signals upon the connection in a separate thread. That means the `onConcatenated` method is invoked always in the context of a thread different from the main thread.
|
||||
There are three ways of creating the object proxy -- three overloads of `sdbus::createObjectProxy`. They differ from each other as to how the proxy towards the connection will behave upon creation:
|
||||
|
||||
* One that takes no connection as a parameter. This one is for convenience -- if you have a simple application and don't want to bother with connections, call this one. Internally, it will create a connection object, and it will be a *system* bus connection. The proxy will immediately create an internal thread and start a processing loop upon the clone of this connection in this thread as long as there is at least one signal registered, so the signals are correctly received and the callbacks are handled from within this internal thread. If there is no signal, i.e. the proxy just provides methods and/or properties, no connection clone is made, no thread is created and no processing loop is started -- you don't pay for what you don't use.
|
||||
|
||||
* One that takes the connection as an **rvalue unique_ptr**. This one behaves the same as the above one, just that you must create the connection by yourself, and then `std::move` the ownership of it to the proxy. This comes with a flexibility that you can choose connection type (system, session).
|
||||
|
||||
* One that takes the connection as an **lvalue reference**. This one behaves differently. You as a client are the owner of the connection, you take full control of it. The proxy just references the connection. This means the proxy does no async processing on it even when there are signals. It relies on you to manage the processing loop yourself (if you need it for signals).
|
||||
|
||||
Implementing the Concatenator example using convenience sdbus-c++ API layer
|
||||
---------------------------------------------------------------------------
|
||||
@ -630,6 +636,8 @@ protected:
|
||||
|
||||
In the above example, a proxy is created that creates and maintains its own system bus connection. However, there are `ProxyInterfaces` class template constructor overloads that also take the connection from the user as the first parameter, and pass that connection over to the underlying proxy. The connection instance is used for all D-Bus proxy interfaces listed in the `ProxyInterfaces` template parameter list.
|
||||
|
||||
Note however that there are multiple `ProxyInterfaces` constructor overloads, and they differ in how the proxy behaves towards the D-Bus connection. These overloads precisely map the `sdbus::createObjectProxy` overloads, as they are actually implemented on top of them. See [Proxy and D-Bus connection](#Proxy-and-D-Bus-connection) for more info.
|
||||
|
||||
Now let's use this proxy to make remote calls and listen to signals in a real application.
|
||||
|
||||
```cpp
|
||||
|
@ -223,7 +223,11 @@ namespace sdbus {
|
||||
* @return Pointer to the object proxy instance
|
||||
*
|
||||
* The provided connection will be used by the proxy to issue calls against the object,
|
||||
* and signals, if any, will be subscribed to on this connection.
|
||||
* and signals, if any, will be subscribed to on this connection. Since the caller still
|
||||
* remains the owner of the connection (the proxy just keeps reference to it) after the call,
|
||||
* the proxy will not start its own background processing loop for incoming signals (if any),
|
||||
* as it will rely on the client as an owner of the connection to handle processing of
|
||||
* incoming messages on that connection by themselves.
|
||||
*
|
||||
* Code example:
|
||||
* @code
|
||||
@ -244,7 +248,10 @@ namespace sdbus {
|
||||
*
|
||||
* The provided connection will be used by the proxy to issue calls against the object,
|
||||
* and signals, if any, will be subscribed to on this connection. Object proxy becomes
|
||||
* an exclusive owner of this connection.
|
||||
* an exclusive owner of this connection. The effect of this is that when there is at
|
||||
* least one signal in proxy's interface, then the proxy will immediately start its own
|
||||
* processing loop for this connection in a separate internal thread, causing incoming
|
||||
* signals to be correctly received and processed in the context of that internal thread.
|
||||
*
|
||||
* Code example:
|
||||
* @code
|
||||
@ -263,6 +270,9 @@ namespace sdbus {
|
||||
* @return Pointer to the object proxy instance
|
||||
*
|
||||
* This factory overload creates a proxy that manages its own D-Bus connection(s).
|
||||
* When there is at least one signal in proxy's interface, then the proxy will immediately
|
||||
* start its own processing loop for this connection in its own separate thread, causing
|
||||
* incoming signals to be correctly received and processed in the context of that thread.
|
||||
*
|
||||
* Code example:
|
||||
* @code
|
||||
|
@ -100,6 +100,15 @@ namespace sdbus {
|
||||
, public _Interfaces...
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* @brief Creates fully working object proxy instance
|
||||
*
|
||||
* @param[in] destination Bus name that provides a D-Bus object
|
||||
* @param[in] objectPath Path of the D-Bus object
|
||||
*
|
||||
* This constructor overload creates a proxy that manages its own D-Bus connection(s).
|
||||
* For more information on its behavior, consult @ref createObjectProxy(std::string, std::string)
|
||||
*/
|
||||
ProxyInterfaces(std::string destination, std::string objectPath)
|
||||
: ObjectHolder<IObjectProxy>(createObjectProxy(std::move(destination), std::move(objectPath)))
|
||||
, _Interfaces(getObject())...
|
||||
@ -107,6 +116,16 @@ namespace sdbus {
|
||||
getObject().finishRegistration();
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Creates fully working object proxy instance
|
||||
*
|
||||
* @param[in] connection D-Bus connection to be used by the proxy object
|
||||
* @param[in] destination Bus name that provides a D-Bus object
|
||||
* @param[in] objectPath Path of the D-Bus object
|
||||
*
|
||||
* The proxy created this way just references a D-Bus connection owned and managed by the user.
|
||||
* For more information on its behavior, consult @ref createObjectProxy(IConnection&,std::string, std::string)
|
||||
*/
|
||||
ProxyInterfaces(IConnection& connection, std::string destination, std::string objectPath)
|
||||
: ObjectHolder<IObjectProxy>(createObjectProxy(connection, std::move(destination), std::move(objectPath)))
|
||||
, _Interfaces(getObject())...
|
||||
@ -114,6 +133,16 @@ namespace sdbus {
|
||||
getObject().finishRegistration();
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Creates fully working object proxy instance
|
||||
*
|
||||
* @param[in] connection D-Bus connection to be used by the proxy object
|
||||
* @param[in] destination Bus name that provides a D-Bus object
|
||||
* @param[in] objectPath Path of the D-Bus object
|
||||
*
|
||||
* The proxy created this way becomes an owner of the connection.
|
||||
* For more information on its behavior, consult @ref createObjectProxy(std::unique_ptr<sdbus::IConnection>&&,std::string, std::string)
|
||||
*/
|
||||
ProxyInterfaces(std::unique_ptr<sdbus::IConnection>&& connection, std::string destination, std::string objectPath)
|
||||
: ObjectHolder<IObjectProxy>(createObjectProxy(std::move(connection), std::move(destination), std::move(objectPath)))
|
||||
, _Interfaces(getObject())...
|
||||
|
@ -140,6 +140,9 @@ namespace sdbus {
|
||||
public:
|
||||
using std::string::string;
|
||||
using std::string::operator=;
|
||||
ObjectPath(std::string path)
|
||||
: std::string(std::move(path))
|
||||
{}
|
||||
};
|
||||
|
||||
class Signature : public std::string
|
||||
@ -147,6 +150,9 @@ namespace sdbus {
|
||||
public:
|
||||
using std::string::string;
|
||||
using std::string::operator=;
|
||||
Signature(std::string path)
|
||||
: std::string(std::move(path))
|
||||
{}
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -1,11 +0,0 @@
|
||||
set(PACKAGE_VERSION "@SDBUSCPP_VERSION@")
|
||||
|
||||
# Check whether the requested PACKAGE_FIND_VERSION is compatible
|
||||
if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}")
|
||||
set(PACKAGE_VERSION_COMPATIBLE FALSE)
|
||||
else()
|
||||
set(PACKAGE_VERSION_COMPATIBLE TRUE)
|
||||
if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}")
|
||||
set(PACKAGE_VERSION_EXACT TRUE)
|
||||
endif()
|
||||
endif()
|
@ -69,6 +69,15 @@ target_link_libraries(libsdbus-c++_unittests ${SYSTEMD_LIBRARIES} gmock gmock_ma
|
||||
add_executable(libsdbus-c++_integrationtests ${INTEGRATIONTESTS_SRCS})
|
||||
target_link_libraries(libsdbus-c++_integrationtests sdbus-c++ gmock gmock_main)
|
||||
|
||||
# Manual performance tests
|
||||
option(ENABLE_PERFTESTS "Build and install manual performance tests (default OFF)" OFF)
|
||||
if(ENABLE_PERFTESTS)
|
||||
add_executable(libsdbus-c++_perftests_client perftests/client.cpp perftests/perftest-proxy.h)
|
||||
target_link_libraries(libsdbus-c++_perftests_client sdbus-c++)
|
||||
add_executable(libsdbus-c++_perftests_server perftests/server.cpp perftests/perftest-adaptor.h)
|
||||
target_link_libraries(libsdbus-c++_perftests_server sdbus-c++)
|
||||
endif()
|
||||
|
||||
#----------------------------------
|
||||
# INSTALLATION
|
||||
#----------------------------------
|
||||
@ -77,6 +86,12 @@ install(TARGETS libsdbus-c++_unittests DESTINATION /opt/test/bin)
|
||||
install(TARGETS libsdbus-c++_integrationtests DESTINATION /opt/test/bin)
|
||||
install(FILES ${INTEGRATIONTESTS_SOURCE_DIR}/files/libsdbus-cpp-test.conf DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/dbus-1/system.d)
|
||||
|
||||
if(ENABLE_PERFTESTS)
|
||||
install(TARGETS libsdbus-c++_perftests_client DESTINATION /opt/test/bin)
|
||||
install(TARGETS libsdbus-c++_perftests_server DESTINATION /opt/test/bin)
|
||||
install(FILES perftests/files/org.sdbuscpp.perftest.conf DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/dbus-1/system.d)
|
||||
endif()
|
||||
|
||||
#----------------------------------
|
||||
# RUNNING THE TESTS UPON BUILD
|
||||
#----------------------------------
|
||||
|
162
test/perftests/client.cpp
Normal file
162
test/perftests/client.cpp
Normal file
@ -0,0 +1,162 @@
|
||||
/**
|
||||
* (C) 2019 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
*
|
||||
* @file client.cpp
|
||||
*
|
||||
* Created on: Jan 25, 2019
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "perftest-proxy.h"
|
||||
#include <sdbus-c++/sdbus-c++.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <unistd.h>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <cassert>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
class PerftestClient : public sdbus::ProxyInterfaces<org::sdbuscpp::perftest_proxy>
|
||||
{
|
||||
public:
|
||||
PerftestClient(std::string destination, std::string objectPath)
|
||||
: sdbus::ProxyInterfaces<org::sdbuscpp::perftest_proxy>(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<std::chrono::steady_clock> 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<std::chrono::milliseconds>(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<std::chrono::milliseconds>(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<std::chrono::milliseconds>(stopTime - startTime).count() << " ms" << std::endl;
|
||||
|
||||
std::this_thread::sleep_for(1000ms);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
16
test/perftests/files/org.sdbuscpp.perftest.conf
Normal file
16
test/perftests/files/org.sdbuscpp.perftest.conf
Normal file
@ -0,0 +1,16 @@
|
||||
<!-- This configuration file specifies the required security policies
|
||||
for the Kistler DBUS example to run core daemon to work. -->
|
||||
|
||||
<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
|
||||
<busconfig>
|
||||
|
||||
<!-- ../system.conf have denied everything, so we just punch some holes -->
|
||||
|
||||
<policy context="default">
|
||||
<allow own="org.sdbuscpp.perftest"/>
|
||||
<allow send_destination="org.sdbuscpp.perftest"/>
|
||||
<allow send_interface="org.sdbuscpp.perftest"/>
|
||||
</policy>
|
||||
|
||||
</busconfig>
|
18
test/perftests/org.sdbuscpp.perftest.xml
Normal file
18
test/perftests/org.sdbuscpp.perftest.xml
Normal file
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<node name="/org/sdbuscpp/perftest">
|
||||
<interface name="org.sdbuscpp.perftest">
|
||||
<method name="sendDataSignals">
|
||||
<arg type="u" name="numberOfSignals" direction="in" />
|
||||
<arg type="u" name="signalMsgSize" direction="in" />
|
||||
</method>
|
||||
<method name="concatenateTwoStrings">
|
||||
<arg type="s" name="string1" direction="in" />
|
||||
<arg type="s" name="string2" direction="in" />
|
||||
<arg type="s" name="result" direction="out" />
|
||||
</method>
|
||||
<signal name="dataSignal">
|
||||
<arg type="s" name="data" />
|
||||
</signal>
|
||||
</interface>
|
||||
</node>
|
46
test/perftests/perftest-adaptor.h
Normal file
46
test/perftests/perftest-adaptor.h
Normal file
@ -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 <sdbus-c++/sdbus-c++.h>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
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<std::string>();
|
||||
}
|
||||
|
||||
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
|
49
test/perftests/perftest-proxy.h
Normal file
49
test/perftests/perftest-proxy.h
Normal file
@ -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 <sdbus-c++/sdbus-c++.h>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
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
|
94
test/perftests/server.cpp
Normal file
94
test/perftests/server.cpp
Normal file
@ -0,0 +1,94 @@
|
||||
/**
|
||||
* (C) 2019 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
||||
*
|
||||
* @file server.cpp
|
||||
*
|
||||
* Created on: Jan 25, 2019
|
||||
* Project: sdbus-c++
|
||||
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
||||
*
|
||||
* This file is part of sdbus-c++.
|
||||
*
|
||||
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sdbus-c++ is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "perftest-adaptor.h"
|
||||
#include <sdbus-c++/sdbus-c++.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
std::string createRandomString(size_t length);
|
||||
|
||||
class PerftestServer : public sdbus::Interfaces<org::sdbuscpp::perftest_adaptor>
|
||||
{
|
||||
public:
|
||||
PerftestServer(sdbus::IConnection& connection, std::string objectPath)
|
||||
: sdbus::Interfaces<org::sdbuscpp::perftest_adaptor>(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<std::chrono::milliseconds>(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();
|
||||
}
|
@ -212,3 +212,31 @@ TEST(AStruct, CreatesStructFromTuple)
|
||||
ASSERT_THAT(std::get<0>(valueStruct), Eq(std::get<0>(value)));
|
||||
ASSERT_THAT(std::get<1>(valueStruct), Eq(std::get<1>(value)));
|
||||
}
|
||||
|
||||
TEST(AnObjectPath, CanBeConstructedFromCString)
|
||||
{
|
||||
const char* aPath = "/some/path";
|
||||
|
||||
ASSERT_THAT(sdbus::ObjectPath{aPath}, Eq(aPath));
|
||||
}
|
||||
|
||||
TEST(AnObjectPath, CanBeConstructedFromStdString)
|
||||
{
|
||||
std::string aPath{"/some/path"};
|
||||
|
||||
ASSERT_THAT(sdbus::ObjectPath{aPath}, Eq(aPath));
|
||||
}
|
||||
|
||||
TEST(ASignature, CanBeConstructedFromCString)
|
||||
{
|
||||
const char* aSignature = "us";
|
||||
|
||||
ASSERT_THAT(sdbus::Signature{aSignature}, Eq(aSignature));
|
||||
}
|
||||
|
||||
TEST(ASignature, CanBeConstructedFromStdString)
|
||||
{
|
||||
std::string aSignature{"us"};
|
||||
|
||||
ASSERT_THAT(sdbus::Signature{aSignature}, Eq(aSignature));
|
||||
}
|
||||
|
Reference in New Issue
Block a user