Reorganize repository

* Move the project top-level CMakeLists.txt to the root of the project;
  this allows building Cyclone as part of ROS2 without any special
  tricks;

* Clean up the build options:

  ENABLE_SSL:    whether to check for and include OpenSSL support if a
                 library can be found (default = ON); this used to be
                 called DDSC_ENABLE_OPENSSL, the old name is deprecated
                 but still works
  BUILD_DOCS:    whether to build docs (default = OFF)
  BUILD_TESTING: whether to build test (default = OFF)

* Collect all documentation into top-level "docs" directory;

* Move the examples to the top-level directory;

* Remove the unused and somewhat misleading pseudo-default
  cyclonedds.xml;

* Remove unused cmake files

Signed-off-by: Erik Boasson <eb@ilities.com>
This commit is contained in:
Erik Boasson 2019-07-26 09:43:53 +02:00 committed by eboasson
parent 4e80559763
commit 9cf4b97f1a
102 changed files with 627 additions and 1925 deletions

105
examples/CMakeLists.txt Normal file
View file

@ -0,0 +1,105 @@
#
# Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License v. 2.0 which is available at
# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
# v. 1.0 which is available at
# http://www.eclipse.org/org/documents/edl-v10.php.
#
# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
#
set(CMAKE_INSTALL_EXAMPLESDIR "${CMAKE_INSTALL_DATADIR}/${CMAKE_PROJECT_NAME}/examples")
add_subdirectory(helloworld)
add_subdirectory(roundtrip)
add_subdirectory(throughput)
if (BUILD_DOCS)
message(STATUS "${CMAKE_PROJECT_NAME} Examples documentation: Success (build)")
set(EXAMPLES_HTML_ARCHIVE "${CMAKE_PROJECT_NAME}ExamplesHTML.tar.gz")
# Process sphinx configuration file
set(sph_conf_author "Eclipse Cyclone DDS project")
string(TIMESTAMP sph_conf_copyright "%Y")
set(sph_conf_version "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
set(sph_conf_release "${PROJECT_VERSION}")
configure_file(sphinx-conf.py.in conf.py @ONLY)
set(builder_output "examples_html_output")
set(builder_log "sphinx-examples-html.log")
add_custom_command(OUTPUT ${builder_output}
COMMAND ${SPHINX_EXECUTABLE}
-b html
-d ${CMAKE_CURRENT_BINARY_DIR}/cache
-c ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR} > ${builder_log}
COMMENT "Running Sphinx for examples html output"
VERBATIM)
# OUTPUT is a fake target / symbolic name, not an actual file
set_property(SOURCE ${builder_output} PROPERTY SYMBOLIC 1)
add_custom_target(examples_docs ALL DEPENDS ${builder_output})
# Archive the output html files, will become a jenkins artifact for use in other jobs
# TODO this hardcoded list and archiving should be replaced by ExternalData refs
set(html_outputs
"_static"
"search.html"
"searchindex.js"
"genindex.html"
"examples.html"
"helloworld/readme.html"
"roundtrip/readme.html"
"throughput/readme.html")
add_custom_command(OUTPUT ${builder_output}
COMMAND ${CMAKE_COMMAND}
-E tar "zcf"
"${EXAMPLES_HTML_ARCHIVE}"
${html_outputs}
APPEND
VERBATIM)
# Remove generated files when cleaning the build tree
set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES
"cache"
"${builder_log}"
"objects.inv"
${html_outputs}
"_sources"
"${EXAMPLES_HTML_ARCHIVE}")
endif()
if(CMAKE_SYSTEM_NAME MATCHES "Windows")
set(platform_exclude "examples/helloworld/Makefile")
elseif(CMAKE_SYSTEM_NAME MATCHES "Linux")
set(platform_exclude "examples/helloworld/vs|examples/helloworld/HelloWorld\.sln")
else()
set(platform_exclude "this_is_a_placeholder")
endif()
# Install example source-files
install(
DIRECTORY "${PROJECT_SOURCE_DIR}/examples/"
DESTINATION "${CMAKE_INSTALL_EXAMPLESDIR}"
COMPONENT dev
PATTERN "CMakeLists.export" EXCLUDE
PATTERN "examples/CMakeLists.txt" EXCLUDE
REGEX ${platform_exclude} EXCLUDE
REGEX "\.rst|\.py" EXCLUDE)
# Install example html docs files
# TODO this should be replaced by install commands that use ExternalData refs (preferably in examples' CMakeLists.txt)
install(
DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
DESTINATION "${CMAKE_INSTALL_EXAMPLESDIR}"
COMPONENT dev
FILES_MATCHING
PATTERN "CMakeFiles" EXCLUDE
PATTERN "cache" EXCLUDE
PATTERN "_sources" EXCLUDE
PATTERN "*.html"
PATTERN "*.js"
PATTERN "_static/*")

48
examples/examples.rst Normal file
View file

@ -0,0 +1,48 @@
..
Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
This program and the accompanying materials are made available under the
terms of the Eclipse Public License v. 2.0 which is available at
http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
v. 1.0 which is available at
http://www.eclipse.org/org/documents/edl-v10.php.
SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
Examples
========
.. toctree::
:maxdepth: 1
:caption: Contents:
helloworld/readme
roundtrip/readme
throughput/readme
Configuration
*************
Eclipse Cyclone DDS has various configuration parameters and comes with a default built-in
configuration. To run an example, or any application that uses Eclipse Cyclone DDS for its data
exchange, this default configuration is usually fine and no further action is required.
Configuration parameters for Eclipse CycloneDDS are expressed in XML and grouped together in a
single XML file. To use a custom XML configuration in an application, the ``CYCLONEDDS_URI``
environment variable needs to be set prior to starting the application and pointed to the location
of the configuration file to be used.
| *Example*
| **Windows:** ``set CYCLONEDDS_URI=file://%USERPROFILE%/CycloneDDS/my-config.xml``
| **Linux:** ``export CYCLONEDDS_URI="file://$HOME/CycloneDDS/my-config.xml"``
The Eclipse CycloneDDS installation comes with a configuration file that corresponds to the default
behaviour. You can modify it or add your using any text or XML editor, or using by using the
Eclipse CycloneDDS Configurator tool, which provides context-sensitive help on available
configuration parameters and their applicability.
One very important part of the configuration settings are the "tracing" settings: these allow
letting Eclipse Cyclone DDS trace very detailed information to a file, and this includes the actual
configuration settings in use, including all those that are set at the default. When editing
configuration files by hand, this overview can be very useful. Increasing the Verbosity from
"warning" to, e.g., "config" already suffices for getting this information written to the log.

View file

@ -0,0 +1,22 @@
cmake_minimum_required(VERSION 3.5)
if (NOT TARGET CycloneDDS::ddsc)
# Find the CycloneDDS package. If it is not in a default location, try
# finding it relative to the example where it most likely resides.
find_package(CycloneDDS REQUIRED PATHS "${CMAKE_SOURCE_DIR}/../../")
endif()
# This is a convenience function, provided by the CycloneDDS package,
# that will supply a library target related the the given idl file.
# In short, it takes the idl file, generates the source files with
# the proper data types and compiles them into a library.
idlc_generate(HelloWorldData_lib "HelloWorldData.idl")
# Both executables have only one related source file.
add_executable(HelloworldPublisher publisher.c)
add_executable(HelloworldSubscriber subscriber.c)
# Both executables need to be linked to the idl data type library and
# the ddsc API library.
target_link_libraries(HelloworldPublisher HelloWorldData_lib CycloneDDS::ddsc)
target_link_libraries(HelloworldSubscriber HelloWorldData_lib CycloneDDS::ddsc)

View file

@ -0,0 +1,58 @@
#
# Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License v. 2.0 which is available at
# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
# v. 1.0 which is available at
# http://www.eclipse.org/org/documents/edl-v10.php.
#
# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
#
cmake_minimum_required(VERSION 3.5)
if (NOT TARGET CycloneDDS::ddsc)
# Find the CycloneDDS package. If it is not in a default location, try
# finding it relative to the example where it most likely resides.
find_package(CycloneDDS REQUIRED PATHS ../../)
endif()
# This is a convenience function, provided by the CycloneDDS package,
# that will supply a library target related the the given idl file.
# In short, it takes the idl file, generates the source files with
# the proper data types and compiles them into a library.
idlc_generate(HelloWorldData_lib "HelloWorldData.idl")
# Both executables have only one related source file.
add_executable(HelloworldPublisher publisher.c)
add_executable(HelloworldSubscriber subscriber.c)
# Both executables need to be linked to the idl data type library and
# the ddsc API library.
target_link_libraries(HelloworldPublisher HelloWorldData_lib CycloneDDS::ddsc)
target_link_libraries(HelloworldSubscriber HelloWorldData_lib CycloneDDS::ddsc)
#
# The helloworld example is the only example to have a different CMakeLists.txt
# for building in source and install environments. This is because it has to
# do some specific installations to support the Getting Started Guide.
# The CMakelists.export will be used for the install environments.
#
install(
TARGETS HelloworldSubscriber HelloworldPublisher
DESTINATION "${CMAKE_INSTALL_EXAMPLESDIR}/helloworld/bin"
COMPONENT dev)
install(
FILES "CMakeLists.export"
DESTINATION "${CMAKE_INSTALL_EXAMPLESDIR}/helloworld"
COMPONENT dev
RENAME "CMakeLists.txt")
get_target_property(GENERATED_FILES HelloWorldData_lib INTERFACE_SOURCES)
install(
FILES ${GENERATED_FILES}
DESTINATION "${CMAKE_INSTALL_EXAMPLESDIR}/helloworld/generated"
COMPONENT dev)

View file

@ -0,0 +1,54 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25123.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HelloWorldSubscriber", "vs\HelloWorldSubscriber.vcxproj", "{D8B2F285-EB03-4657-A0DC-603172553BEA}"
ProjectSection(ProjectDependencies) = postProject
{28A7A97B-3CEF-4FD7-8DC5-A7586D6DAE1D} = {28A7A97B-3CEF-4FD7-8DC5-A7586D6DAE1D}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HelloWorldPublisher", "vs\HelloWorldPublisher.vcxproj", "{D8B2F285-EB03-4657-ACDC-603172553BEA}"
ProjectSection(ProjectDependencies) = postProject
{28A7A97B-3CEF-4FD7-8DC5-A7586D6DAE1D} = {28A7A97B-3CEF-4FD7-8DC5-A7586D6DAE1D}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HelloWorldType", "vs\HelloWorldType.vcxproj", "{28A7A97B-3CEF-4FD7-8DC5-A7586D6DAE1D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D8B2F285-EB03-4657-A0DC-603172553BEA}.Debug|x64.ActiveCfg = Debug|x64
{D8B2F285-EB03-4657-A0DC-603172553BEA}.Debug|x64.Build.0 = Debug|x64
{D8B2F285-EB03-4657-A0DC-603172553BEA}.Debug|x86.ActiveCfg = Debug|Win32
{D8B2F285-EB03-4657-A0DC-603172553BEA}.Debug|x86.Build.0 = Debug|Win32
{D8B2F285-EB03-4657-A0DC-603172553BEA}.Release|x64.ActiveCfg = Release|x64
{D8B2F285-EB03-4657-A0DC-603172553BEA}.Release|x64.Build.0 = Release|x64
{D8B2F285-EB03-4657-A0DC-603172553BEA}.Release|x86.ActiveCfg = Release|Win32
{D8B2F285-EB03-4657-A0DC-603172553BEA}.Release|x86.Build.0 = Release|Win32
{D8B2F285-EB03-4657-ACDC-603172553BEA}.Debug|x64.ActiveCfg = Debug|x64
{D8B2F285-EB03-4657-ACDC-603172553BEA}.Debug|x64.Build.0 = Debug|x64
{D8B2F285-EB03-4657-ACDC-603172553BEA}.Debug|x86.ActiveCfg = Debug|Win32
{D8B2F285-EB03-4657-ACDC-603172553BEA}.Debug|x86.Build.0 = Debug|Win32
{D8B2F285-EB03-4657-ACDC-603172553BEA}.Release|x64.ActiveCfg = Release|x64
{D8B2F285-EB03-4657-ACDC-603172553BEA}.Release|x64.Build.0 = Release|x64
{D8B2F285-EB03-4657-ACDC-603172553BEA}.Release|x86.ActiveCfg = Release|Win32
{D8B2F285-EB03-4657-ACDC-603172553BEA}.Release|x86.Build.0 = Release|Win32
{28A7A97B-3CEF-4FD7-8DC5-A7586D6DAE1D}.Debug|x64.ActiveCfg = Debug|x64
{28A7A97B-3CEF-4FD7-8DC5-A7586D6DAE1D}.Debug|x64.Build.0 = Debug|x64
{28A7A97B-3CEF-4FD7-8DC5-A7586D6DAE1D}.Debug|x86.ActiveCfg = Debug|Win32
{28A7A97B-3CEF-4FD7-8DC5-A7586D6DAE1D}.Debug|x86.Build.0 = Debug|Win32
{28A7A97B-3CEF-4FD7-8DC5-A7586D6DAE1D}.Release|x64.ActiveCfg = Release|x64
{28A7A97B-3CEF-4FD7-8DC5-A7586D6DAE1D}.Release|x64.Build.0 = Release|x64
{28A7A97B-3CEF-4FD7-8DC5-A7586D6DAE1D}.Release|x86.ActiveCfg = Release|Win32
{28A7A97B-3CEF-4FD7-8DC5-A7586D6DAE1D}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View file

@ -0,0 +1,9 @@
module HelloWorldData
{
struct Msg
{
long userID;
string message;
};
#pragma keylist Msg userID
};

View file

@ -0,0 +1,54 @@
publisher_NAME := HelloworldPublisher
publisher_SRCS := publisher.c generated/HelloWorldData.c
publisher_OBJS := ${publisher_SRCS:.c=.o}
subscriber_NAME := HelloworldSubscriber
subscriber_SRCS := subscriber.c generated/HelloWorldData.c
subscriber_OBJS := ${subscriber_SRCS:.c=.o}
# Make sure that the location where dds.h is installed is known to the
# compiler. If dds.h is not installed in a system default spot, then
# it can be introduced by adding it to the CFLAGS, like:
#CFLAGS += -I../../../../include
# Make sure that the location where libddsc.so is installed is known
# to the compiler. If the lib is not installed in a system default
# location, then it can be introduced by adding it to the LDFLAGS:
#LDFLAGS += -L../../../../lib
CFLAGS += -Igenerated
LDFLAGS += -lddsc
.PHONY: all clean distclean
all: $(publisher_NAME) $(subscriber_NAME)
$(publisher_NAME): $(publisher_OBJS)
gcc $(CFLAGS) $(publisher_OBJS) $(LDFLAGS) -o $(publisher_NAME)
$(subscriber_NAME): $(subscriber_OBJS)
gcc $(CFLAGS) $(subscriber_OBJS) $(LDFLAGS) -o $(subscriber_NAME)
clean:
@- $(RM) $(publisher_NAME)
@- $(RM) $(publisher_OBJS)
@- $(RM) $(subscriber_NAME)
@- $(RM) $(subscriber_OBJS)
distclean: clean
# Make sure that the idlc jar file is available and java can find its
# location. In this example, it is assumed that the jar is located at
# a specific relative directory. Change the classpath variable if
# this is not the case on your system.
classpath:= ../../idlc/idlc-jar-with-dependencies.jar
ifneq ($(CLASSPATH),)
classpath:= $(CLASSPATH):$(classpath)
endif
export CLASSPATH:=$(classpath)
datatype:
java org.eclipse.cyclonedds.compilers.Idlc HelloWorldData.idl

View file

@ -0,0 +1,68 @@
#include "dds/dds.h"
#include "HelloWorldData.h"
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char ** argv)
{
dds_entity_t participant;
dds_entity_t topic;
dds_entity_t writer;
dds_return_t rc;
HelloWorldData_Msg msg;
uint32_t status = 0;
(void)argc;
(void)argv;
/* Create a Participant. */
participant = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL);
if (participant < 0)
DDS_FATAL("dds_create_participant: %s\n", dds_strretcode(-participant));
/* Create a Topic. */
topic = dds_create_topic (
participant, &HelloWorldData_Msg_desc, "HelloWorldData_Msg", NULL, NULL);
if (topic < 0)
DDS_FATAL("dds_create_topic: %s\n", dds_strretcode(-topic));
/* Create a Writer. */
writer = dds_create_writer (participant, topic, NULL, NULL);
if (writer < 0)
DDS_FATAL("dds_create_write: %s\n", dds_strretcode(-writer));
printf("=== [Publisher] Waiting for a reader to be discovered ...\n");
fflush (stdout);
rc = dds_set_status_mask(writer, DDS_PUBLICATION_MATCHED_STATUS);
if (rc != DDS_RETCODE_OK)
DDS_FATAL("dds_set_status_mask: %s\n", dds_strretcode(-rc));
while(!(status & DDS_PUBLICATION_MATCHED_STATUS))
{
rc = dds_get_status_changes (writer, &status);
if (rc != DDS_RETCODE_OK)
DDS_FATAL("dds_get_status_changes: %s\n", dds_strretcode(-rc));
/* Polling sleep. */
dds_sleepfor (DDS_MSECS (20));
}
/* Create a message to write. */
msg.userID = 1;
msg.message = "Hello World";
printf ("=== [Publisher] Writing : ");
printf ("Message (%"PRId32", %s)\n", msg.userID, msg.message);
fflush (stdout);
rc = dds_write (writer, &msg);
if (rc != DDS_RETCODE_OK)
DDS_FATAL("dds_write: %s\n", dds_strretcode(-rc));
/* Deleting the participant will delete all its children recursively as well. */
rc = dds_delete (participant);
if (rc != DDS_RETCODE_OK)
DDS_FATAL("dds_delete: %s\n", dds_strretcode(-rc));
return EXIT_SUCCESS;
}

View file

@ -0,0 +1,46 @@
..
Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
This program and the accompanying materials are made available under the
terms of the Eclipse Public License v. 2.0 which is available at
http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
v. 1.0 which is available at
http://www.eclipse.org/org/documents/edl-v10.php.
SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
HelloWorld
==========
Description
***********
The basic HelloWorld example is used to illustrate the necessary steps to setup DCPS entities.
Note it is also used in the Getting Started Guide to explain the usage of Eclipse Cyclone DDS.
Design
******
It consists of 2 units:
- HelloworldPublisher: implements the publisher's main
- HelloworldSubscriber: implements the subscriber's main
Scenario
********
The publisher sends a single HelloWorld sample. The sample contains two fields:
- a userID field (long type)
- a message field (string type)
When it receives the sample, the subscriber displays the userID and the message field.
Running the example
*******************
It is recommended that you run the subscriber and publisher in separate terminals to avoid mixing the output.
- Open 2 terminals.
- In the first terminal start the subscriber by running HelloWorldSubscriber
- In the second terminal start the publisher by running HelloWorldPublisher

View file

@ -0,0 +1,84 @@
#include "dds/dds.h"
#include "HelloWorldData.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/* An array of one message (aka sample in dds terms) will be used. */
#define MAX_SAMPLES 1
int main (int argc, char ** argv)
{
dds_entity_t participant;
dds_entity_t topic;
dds_entity_t reader;
HelloWorldData_Msg *msg;
void *samples[MAX_SAMPLES];
dds_sample_info_t infos[MAX_SAMPLES];
dds_return_t rc;
dds_qos_t *qos;
(void)argc;
(void)argv;
/* Create a Participant. */
participant = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL);
if (participant < 0)
DDS_FATAL("dds_create_participant: %s\n", dds_strretcode(-participant));
/* Create a Topic. */
topic = dds_create_topic (
participant, &HelloWorldData_Msg_desc, "HelloWorldData_Msg", NULL, NULL);
if (topic < 0)
DDS_FATAL("dds_create_topic: %s\n", dds_strretcode(-topic));
/* Create a reliable Reader. */
qos = dds_create_qos ();
dds_qset_reliability (qos, DDS_RELIABILITY_RELIABLE, DDS_SECS (10));
reader = dds_create_reader (participant, topic, qos, NULL);
if (reader < 0)
DDS_FATAL("dds_create_reader: %s\n", dds_strretcode(-reader));
dds_delete_qos(qos);
printf ("\n=== [Subscriber] Waiting for a sample ...\n");
fflush (stdout);
/* Initialize sample buffer, by pointing the void pointer within
* the buffer array to a valid sample memory location. */
samples[0] = HelloWorldData_Msg__alloc ();
/* Poll until data has been read. */
while (true)
{
/* Do the actual read.
* The return value contains the number of read samples. */
rc = dds_read (reader, samples, infos, MAX_SAMPLES, MAX_SAMPLES);
if (rc < 0)
DDS_FATAL("dds_read: %s\n", dds_strretcode(-rc));
/* Check if we read some data and it is valid. */
if ((rc > 0) && (infos[0].valid_data))
{
/* Print Message. */
msg = (HelloWorldData_Msg*) samples[0];
printf ("=== [Subscriber] Received : ");
printf ("Message (%"PRId32", %s)\n", msg->userID, msg->message);
fflush (stdout);
break;
}
else
{
/* Polling sleep. */
dds_sleepfor (DDS_MSECS (20));
}
}
/* Free the data location. */
HelloWorldData_Msg_free (samples[0], DDS_FREE_ALL);
/* Deleting the participant will delete all its children recursively as well. */
rc = dds_delete (participant);
if (rc != DDS_RETCODE_OK)
DDS_FATAL("dds_delete: %s\n", dds_strretcode(-rc));
return EXIT_SUCCESS;
}

View file

@ -0,0 +1,142 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{D8B2F285-EB03-4657-ACDC-603172553BEA}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<ProjectName>HelloWorldPublisher</ProjectName>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="directories.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="directories.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="directories.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="directories.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<IntDir>$(Platform)\$(Configuration)\Publisher\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Platform)'=='Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(CycloneDDS_inc_dir);..\generated;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<TargetMachine>MachineX86</TargetMachine>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<SubSystem>Console</SubSystem>
<AdditionalLibraryDirectories>$(CycloneDDS_lib_dir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>ddsc.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<AdditionalIncludeDirectories>$(CycloneDDS_inc_dir);..\generated;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>ddsc.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(CycloneDDS_lib_dir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<SubSystem>Console</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<AdditionalIncludeDirectories>$(CycloneDDS_inc_dir);..\generated;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>ddsc.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(CycloneDDS_lib_dir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<SubSystem>Console</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\generated\HelloWorldData.c" />
<ClCompile Include="..\publisher.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\generated\HelloWorldData.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions>
</Filter>
</ItemGroup>
</Project>

View file

@ -0,0 +1,142 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{D8B2F285-EB03-4657-A0DC-603172553BEA}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<ProjectName>HelloWorldSubscriber</ProjectName>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="directories.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="directories.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="directories.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="directories.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<IntDir>$(Platform)\$(Configuration)\Subscriber\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Platform)'=='Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(CycloneDDS_inc_dir);..\generated;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<TargetMachine>MachineX86</TargetMachine>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<SubSystem>Console</SubSystem>
<AdditionalLibraryDirectories>$(CycloneDDS_lib_dir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>ddsc.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<AdditionalIncludeDirectories>$(CycloneDDS_inc_dir);..\generated;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>ddsc.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(CycloneDDS_lib_dir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<SubSystem>Console</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<AdditionalIncludeDirectories>$(CycloneDDS_inc_dir);..\generated;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>ddsc.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(CycloneDDS_lib_dir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<SubSystem>Console</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\generated\HelloWorldData.c" />
<ClCompile Include="..\subscriber.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\generated\HelloWorldData.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions>
</Filter>
</ItemGroup>
</Project>

View file

@ -0,0 +1,86 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{28A7A97B-3CEF-4FD7-8DC5-A7586D6DAE1D}</ProjectGuid>
<RootNamespace>HelloWorldType</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="directories.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="directories.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="directories.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="directories.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemGroup>
<CustomBuild Include="..\HelloWorldData.idl">
<Command>java -classpath "$(CycloneDDS_idlc_dir)\idlc-jar-with-dependencies.jar" org.eclipse.cyclonedds.compilers.Idlc -d "$(SolutionDir)generated" "%(FullPath)"</Command>
<Message>Generating source files from IDL into "$(SolutionDir)generated"</Message>
<Outputs>HelloWorldData.h;HelloWorldData.c</Outputs>
</CustomBuild>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros">
<CycloneDDS_lib_dir>C:/Program Files/ADLINK/Cyclone DDS/lib</CycloneDDS_lib_dir>
<CycloneDDS_inc_dir>C:/Program Files/ADLINK/Cyclone DDS/include</CycloneDDS_inc_dir>
<CycloneDDS_idlc_dir>C:/Program Files/ADLINK/Cyclone DDS/share/CycloneDDS/idlc</CycloneDDS_idlc_dir>
</PropertyGroup>
<PropertyGroup />
<ItemGroup>
<BuildMacro Include="CycloneDDS_lib_dir">
<Value>$(CycloneDDS_lib_dir)</Value>
</BuildMacro>
<BuildMacro Include="CycloneDDS_inc_dir">
<Value>$(CycloneDDS_inc_dir)</Value>
</BuildMacro>
<BuildMacro Include="CycloneDDS_idlc_dir">
<Value>$(CycloneDDS_idlc_dir)</Value>
</BuildMacro>
</ItemGroup>
<PropertyGroup Label="Configuration">
<!-->
User macros are not expanded when starting the build applications in VS.
The path is extended with a possible Cyclone DLL location when they are not
installed in a system default location.
<-->
<LocalDebuggerEnvironment>PATH=../../../../../bin;%PATH%
$(LocalDebuggerEnvironment)</LocalDebuggerEnvironment>
</PropertyGroup>
</Project>

48
examples/perfscript/ethload Executable file
View file

@ -0,0 +1,48 @@
#!/usr/bin/perl -w
use strict;
use bignum;
use Time::HiRes qw (time);
if (@ARGV != 2) {
print STDERR "usage: $0 device {100|1000}\n";
exit 1;
}
my $devname = $ARGV[0];
my $speed = $ARGV[1] * 1e6;
$| = 1;
my ($lt, $t, $lrecv, $lxmit);
while (1) {
open FH, "< /proc/net/dev" or die "can't open /proc/net/dev";
$t = time;
my $info = undef;
while (<FH>) {
chomp;
if (s/^\s+$devname\s*:\s*//) {
$info = $_;
last;
}
}
close FH;
die "can't locate info for $devname" unless defined $info;
my @info = split ' ', $info;
my $recv = $info[0] + 0;
my $xmit = $info[8] + 0;
if (defined $lt) {
my $dr = $recv - $lrecv;
my $dx = $xmit - $lxmit;
my $dt = $t - $lt;
my $ur = 100 * (8 * $dr) / ($dt * $speed);
my $xr = 100 * (8 * $dx) / ($dt * $speed);
printf "r %5.1f x %5.1f (%8d %8d)\n", $ur, $xr, $dr, $dx;
}
$lt = $t;
$lrecv = $recv;
$lxmit = $xmit;
sleep 1;
}

View file

@ -0,0 +1,30 @@
export CYCLONEDDS_URI='<Internal><MinimumSocketReceiveBufferSize>250kB</></><General><MaxMessageSize>65500B</><FragmentSize>65000B</>'
set -x
gen/ddsperf -D20 -L ping pon
for x in 16 32 64 128 1024 4096 16384 ; do
gen/ddsperf -D20 -TKS -z$x -L ping pong
done
gen/ddsperf -D20 -L pub sub
for x in 16 32 64 128 1024 4096 16384 ; do
gen/ddsperf -D20 -TKS -z$x -L pub sub
done
gen/ddsperf pong & pid=$!
gen/ddsperf -D20 ping
kill $pid
wait
gen/ddsperf -TKS pong & pid=$!
for x in 16 32 64 128 1024 4096 16384 ; do
gen/ddsperf -D20 -TKS -z$x ping
done
kill $pid
wait
gen/ddsperf sub & pid=$!
gen/ddsperf -D20 pub
kill $pid
wait
gen/ddsperf -TKS sub & pid=$!
for x in 16 32 64 128 1024 4096 16384 ; do
gen/ddsperf -D20 -TKS -z$x pub
done
kill $pid
wait

View file

@ -0,0 +1,73 @@
#!/bin/bash
usage () {
cat >&2 <<EOF
usage: $0 [OPTIONS] user@remote [user@remote...]
OPTIONS
-i IF use network interface IF (default: eth0)
-b 100|1000 network bandwidth (100Mbps/1000Gbps) for calculating load
% given load in bytes/second (default: 1000)
-d DIR use DIR on remote (default: PWD)
-p provision required binaries in DIR (default: false)
first ssh's in to try mkdir -p DIR, then follows up with scp
-t DUR run for DUR seconds per size (default 20)
-a ASYNCLIST run for delivery async settings ASYNCLIST (default: "0 1")
-m MODELIST run with subscriber mode settings MODELIST (default: "-1 0 1")
-s SIZELIST run for sizes in SIZELIST (default: "0 16 32 64 128 256")
-l LOOPBACK enable multicast loopback (true/false, default: true)
-o DIR store results in dir.N where N is number of nodes
Runs throughput-test with the specified options for each prefix of remote nodes.
EOF
exit 1
}
export nwif=eth0
bandwidth=1000
remotedir="$PWD"
provision=false
asynclist="0 1"
modelist="-1 0 1"
sizelist="0 16 32 64 128 256"
timeout=20
loopback=true
resultdir="throughput-result"
while getopts "i:b:d:pa:m:s:t:o:l:" opt ; do
case $opt in
i) nwif="$OPTARG" ;;
b) bandwidth="$OPTARG" ;;
d) remotedir="$OPTARG" ;;
p) provision=true ;;
a) asynclist="$OPTARG" ;;
m) modelist="$OPTARG" ;;
s) sizelist="$OPTARG" ;;
l) loopback="OPTARG" ;;
t) timeout="$OPTARG" ;;
o) resultdir="$OPTARG" ;;
h) usage ;;
esac
done
shift $((OPTIND-1))
if [ $# -lt 1 ] ; then usage ; fi
pubremote=$1
shift
popt=
$provision && popt=-p
n=0
while [[ $n -le $# ]] ; do
out=$resultdir.$(( $n + 1 ))
mkdir $out
otherhosts=""
j=1
while [[ $j -le $n ]] ; do
hostJ=`eval echo "\\$$j"`
otherhosts="$otherhosts $hostJ"
j=$(( $j + 1 ))
done
`dirname $0`/throughput-test -i "$nwif" -b "$bandwidth" -d "$remotedir" $popt -a "$asynclist" -m "$modelist" -s "$sizelist" -t "$timeout" -o $out $pubremote $otherhosts
n=$(( $n + 1 ))
done

View file

@ -0,0 +1,159 @@
#!/bin/bash
usage () {
cat >&2 <<EOF
usage: $0 [OPTIONS] user@remote [user@remote...]
OPTIONS
-i IF use network interface IF (default: eth0)
-b 100|1000 network bandwidth (100Mbps/1000Gbps) for calculating load
% given load in bytes/second (default: 1000)
-d DIR use DIR on remote (default: PWD)
-p provision required binaries in DIR (default: false)
first ssh's in to try mkdir -p DIR, then follows up with scp
-t DUR run for DUR seconds per size (default 20)
-a ASYNCLIST run for delivery async settings ASYNCLIST (default: "0 1")
-m MODELIST run with subscriber mode settings MODELIST (default: "-1 0 1")
-s SIZELIST run for sizes in SIZELIST (default: "0 16 32 64 128 256")
-l LOOPBACK enable/disable multicast loopback (true/false, default: true)
-o DIR store results in dir (default: throughput-result)
Local host runs ThroughputSubscriber, first remote runs ThroughputPublisher,
further remotes also run ThroughputSubscriber. It assumes these are
available in DIR/bin. It also assumes that ssh user@remote works without
requiring a password.
EOF
exit 1
}
export nwif=eth0
bandwidth=1000
remotedir="$PWD"
provision=false
asynclist="0 1"
modelist="-1 0 1"
sizelist="0 16 32 64 128 256"
timeout=20
loopback=true
resultdir="throughput-result"
while getopts "i:b:d:pa:m:s:t:o:l:" opt ; do
case $opt in
i) nwif="$OPTARG" ;;
b) bandwidth="$OPTARG" ;;
d) remotedir="$OPTARG" ;;
p) provision=true ;;
a) asynclist="$OPTARG" ;;
m) modelist="$OPTARG" ;;
s) sizelist="$OPTARG" ;;
l) loopback="OPTARG" ;;
t) timeout="$OPTARG" ;;
o) resultdir="$OPTARG" ;;
h) usage ;;
esac
done
shift $((OPTIND-1))
if [ $# -lt 1 ] ; then usage ; fi
ethload=`dirname $0`/ethload
pubremote=$1
shift
cfg=cdds-simple.xml
cat >$cfg <<EOF
<CycloneDDS>
<Domain>
<Id>17</Id>
</Domain>
<DDSI2E>
<General>
<NetworkInterfaceAddress>$nwif</NetworkInterfaceAddress>
<EnableMulticastLoopback>$loopback</EnableMulticastLoopback>
</General>
<Internal>
<Watermarks>
<WhcHigh>500kB</WhcHigh>
</Watermarks>
<SynchronousDeliveryPriorityThreshold>${async:-0}</SynchronousDeliveryPriorityThreshold>
<LeaseDuration>3s</LeaseDuration>
</Internal>
</DDSI2E>
</CycloneDDS>
EOF
if [ ! -x bin/ThroughputPublisher -o ! -x bin/ThroughputSubscriber -o ! -x $ethload ] ; then
echo "some check for existence of a file failed on the local machine" >&2
exit 1
fi
[ -d $resultdir ] || { echo "output directory $resultdir doesn't exist" >&2 ; exit 1 ; }
if $provision ; then
echo "provisioning ..."
for r in $pubremote "$@" ; do
ssh $r mkdir -p $remotedir $remotedir/bin $remotedir/lib
scp lib/libddsc.so.0 $r:$remotedir/lib
scp bin/ThroughputPublisher bin/ThroughputSubscriber $r:$remotedir/bin
done
fi
export CYCLONEDDS_URI=file://$PWD/$cfg
for r in $pubremote "$@" ; do
scp $cfg $r:$remotedir || { echo "failed to copy $cfg to $remote:$PWD" >&2 ; exit 1 ; }
done
for async in $asynclist ; do
export async
for mode in $modelist ; do
echo "======== ASYNC $async MODE $mode ========="
cat > run-publisher.tmp <<EOF
export CYCLONEDDS_URI=file://$remotedir/$cfg
export async=$async
cd $remotedir
rm -f pub-top.log
for size in $sizelist ; do
echo "size \$size"
bin/ThroughputPublisher \$size > pub.log & ppid=\$!
top -b -d1 -p \$ppid >> pub-top.log & tpid=\$!
sleep $timeout
kill \$tpid
kill -2 \$ppid
wait \$ppid
sleep 5
done
wait
EOF
scp run-publisher.tmp $pubremote:$remotedir || { echo "failed to copy $cfg to $remote:$PWD" >&2 ; exit 2 ; }
killremotesubs=""
if [ $# -gt 0 ] ; then
cat > run-subscriber.tmp <<EOF
export CYCLONEDDS_URI=file://$remotedir/$cfg
export async=$async
cd $remotedir
nohup bin/ThroughputSubscriber 0 $mode > /dev/null &
echo \$!
EOF
for r in "$@" ; do
scp run-subscriber.tmp $r:$remotedir
rsubpid=`ssh $r ". $remotedir/run-subscriber.tmp"`
killremotesubs="$killremotesubs ssh $r kill -9 $rsubpid &"
done
fi
outdir=$resultdir/data-async$async-mode$mode
mkdir $outdir
rm -f sub-top.log
$ethload $nwif $bandwidth > $outdir/sub-ethload.log & lpid=$!
bin/ThroughputSubscriber 0 $mode > $outdir/sub.log & spid=$!
top -b -d1 -p $spid >> $outdir/sub-top.log & tpid=$!
tail -f $outdir/sub.log & xpid=$!
ssh $pubremote ". $remotedir/run-publisher.tmp"
kill $tpid
kill -2 $spid
eval $killremotesubs
sleep 1
kill $lpid $xpid
wait
scp $pubremote:$remotedir/{pub-top.log,pub.log} $outdir
done
done

View file

@ -0,0 +1,59 @@
#!/usr/bin/perl -w
use strict;
my @dirs = ("async0-mode-1", "async0-mode0", "async0-mode1",
"async1-mode-1", "async1-mode0", "async1-mode1");
my $dataset = 0;
my $basedir = "throughput-result";
$basedir = $ARGV[0] if @ARGV== 1;
my $load_threshold = 20;
for my $dir (@dirs) {
my @loads = ();
{
open LH, "< $basedir/data-$dir/sub-ethload.log" or next; # die "can't open $basedir/data-$dir/sub-ethload.log";
my @curload = ();
while (<LH>) {
next unless /^r +([0-9.]+).*\( *(\d+)/;
push @curload, $2 if $1 > $load_threshold;
if (@curload && $1 < $load_threshold) {
push @loads, median (@curload);
@curload = ();
}
}
push @loads, median (@curload) if @curload;
close LH;
}
open FH, "< $basedir/data-$dir/sub.log" or next; # die "can't open $basedir/data-$dir/sub.log";
print "\n\n" if $dataset++;
print "# mode $dir\n";
print "# payloadsize rate[samples/s] appl.bandwidth[Mb/s] raw.bandwidth[Mb/s]\n";
my $psz;
my @rate = ();
while (<FH>) {
next unless /Payload size: ([0-9]+).*Transfer rate: ([0-9.]+)/;
my $psz_cur = $1; my $rate_cur = $2;
$psz = $psz_cur unless defined $psz;
if ($psz != $psz_cur) {
my $load = shift @loads;
my $rate = median (@rate);
printf "%d %f %f %f\n", $psz, $rate, $rate * (8 + $psz) / 125e3, $load / 125e3;
@rate = ();
}
$psz = $psz_cur;
push @rate, ($rate_cur + 0.0);
}
my $load = shift @loads;
my $rate = median (@rate);
printf "%d %f %f %f\n", $psz, $rate, $rate * (8 + $psz) / 125e3, $load / 125e3;
close FH;
}
sub median {
my @xs = sort { $a <=> $b } @_;
return (@xs % 2) ? $xs[(@xs - 1) / 2] : ($xs[@xs/2 - 1] + $xs[@xs/2]) / 2;
}

View file

@ -0,0 +1,14 @@
#!/bin/bash
`dirname $0`/throughput-test-extract > data.txt
gnuplot <<\EOF
set term png size 1024,768
set output "throughput-polling.png"
set st d l
set title "Throughput (polling with 1ms sleeps)"
set ylabel "M sample/s"
set y2label "Mbps"
set y2tics
set xlabel "payload size [bytes]"
p "data.txt" i 5 u 1:($2/1e6) ti "rate [M sample/s]", "" i 5 u 1:3 axes x1y2 ti "app bandwidth [Mbps]", "" i 5 u 1:4 axes x1y2 ti "GbE bandwidth [Mbps]"
EOF

View file

@ -0,0 +1,33 @@
#
# Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License v. 2.0 which is available at
# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
# v. 1.0 which is available at
# http://www.eclipse.org/org/documents/edl-v10.php.
#
# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
#
cmake_minimum_required(VERSION 3.5)
if (NOT TARGET CycloneDDS::ddsc)
# Find the CycloneDDS package. If it is not in a default location, try
# finding it relative to the example where it most likely resides.
find_package(CycloneDDS REQUIRED PATHS "${CMAKE_SOURCE_DIR}/../../")
endif()
# This is a convenience function, provided by the CycloneDDS package,
# that will supply a library target related the the given idl file.
# In short, it takes the idl file, generates the source files with
# the proper data types and compiles them into a library.
idlc_generate(RoundTrip_lib RoundTrip.idl)
# Both executables have only one related source file.
add_executable(RoundtripPing ping.c)
add_executable(RoundtripPong pong.c)
# Both executables need to be linked to the idl data type library and
# the ddsc API library.
target_link_libraries(RoundtripPing RoundTrip_lib CycloneDDS::ddsc)
target_link_libraries(RoundtripPong RoundTrip_lib CycloneDDS::ddsc)

View file

@ -0,0 +1,8 @@
module RoundTripModule
{
struct DataType
{
sequence<octet> payload;
};
#pragma keylist DataType
};

513
examples/roundtrip/ping.c Normal file
View file

@ -0,0 +1,513 @@
#include "dds/dds.h"
#include "RoundTrip.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <inttypes.h>
#define TIME_STATS_SIZE_INCREMENT 50000
#define MAX_SAMPLES 100
#define US_IN_ONE_SEC 1000000LL
/* Forward declaration */
static dds_entity_t prepare_dds(dds_entity_t *writer, dds_entity_t *reader, dds_entity_t *readCond, dds_listener_t *listener);
static void finalize_dds(dds_entity_t participant);
typedef struct ExampleTimeStats
{
dds_time_t * values;
unsigned long valuesSize;
unsigned long valuesMax;
double average;
dds_time_t min;
dds_time_t max;
unsigned long count;
} ExampleTimeStats;
static void exampleInitTimeStats (ExampleTimeStats *stats)
{
stats->values = (dds_time_t*) malloc (TIME_STATS_SIZE_INCREMENT * sizeof (dds_time_t));
stats->valuesSize = 0;
stats->valuesMax = TIME_STATS_SIZE_INCREMENT;
stats->average = 0;
stats->min = 0;
stats->max = 0;
stats->count = 0;
}
static void exampleResetTimeStats (ExampleTimeStats *stats)
{
memset (stats->values, 0, stats->valuesMax * sizeof (dds_time_t));
stats->valuesSize = 0;
stats->average = 0;
stats->min = 0;
stats->max = 0;
stats->count = 0;
}
static void exampleDeleteTimeStats (ExampleTimeStats *stats)
{
free (stats->values);
}
static ExampleTimeStats *exampleAddTimingToTimeStats
(ExampleTimeStats *stats, dds_time_t timing)
{
if (stats->valuesSize > stats->valuesMax)
{
dds_time_t * temp = (dds_time_t*) realloc (stats->values, (stats->valuesMax + TIME_STATS_SIZE_INCREMENT) * sizeof (dds_time_t));
stats->values = temp;
stats->valuesMax += TIME_STATS_SIZE_INCREMENT;
}
if (stats->values != NULL && stats->valuesSize < stats->valuesMax)
{
stats->values[stats->valuesSize++] = timing;
}
stats->average = ((double)stats->count * stats->average + (double)timing) / (double)(stats->count + 1);
stats->min = (stats->count == 0 || timing < stats->min) ? timing : stats->min;
stats->max = (stats->count == 0 || timing > stats->max) ? timing : stats->max;
stats->count++;
return stats;
}
static int exampleCompareul (const void* a, const void* b)
{
dds_time_t ul_a = *((dds_time_t*)a);
dds_time_t ul_b = *((dds_time_t*)b);
if (ul_a < ul_b) return -1;
if (ul_a > ul_b) return 1;
return 0;
}
static double exampleGetMedianFromTimeStats (ExampleTimeStats *stats)
{
double median = 0.0;
qsort (stats->values, stats->valuesSize, sizeof (dds_time_t), exampleCompareul);
if (stats->valuesSize % 2 == 0)
{
median = (double)(stats->values[stats->valuesSize / 2 - 1] + stats->values[stats->valuesSize / 2]) / 2;
}
else
{
median = (double)stats->values[stats->valuesSize / 2];
}
return median;
}
static dds_time_t exampleGet99PercentileFromTimeStats (ExampleTimeStats *stats)
{
qsort (stats->values, stats->valuesSize, sizeof (dds_time_t), exampleCompareul);
return stats->values[stats->valuesSize - stats->valuesSize / 100];
}
static dds_entity_t waitSet;
#ifdef _WIN32
#include <Windows.h>
static bool CtrlHandler (DWORD fdwCtrlType)
{
dds_waitset_set_trigger (waitSet, true);
return true; //Don't let other handlers handle this key
}
#elif !DDSRT_WITH_FREERTOS
static void CtrlHandler (int sig)
{
(void)sig;
dds_waitset_set_trigger (waitSet, true);
}
#endif
static dds_entity_t writer;
static dds_entity_t reader;
static dds_entity_t participant;
static dds_entity_t readCond;
static ExampleTimeStats roundTrip;
static ExampleTimeStats writeAccess;
static ExampleTimeStats readAccess;
static ExampleTimeStats roundTripOverall;
static ExampleTimeStats writeAccessOverall;
static ExampleTimeStats readAccessOverall;
static RoundTripModule_DataType pub_data;
static RoundTripModule_DataType sub_data[MAX_SAMPLES];
static void *samples[MAX_SAMPLES];
static dds_sample_info_t info[MAX_SAMPLES];
static dds_time_t startTime;
static dds_time_t preWriteTime;
static dds_time_t postWriteTime;
static dds_time_t preTakeTime;
static dds_time_t postTakeTime;
static dds_time_t elapsed = 0;
static bool warmUp = true;
static void data_available(dds_entity_t rd, void *arg)
{
dds_time_t difference = 0;
int status;
(void)arg;
/* Take sample and check that it is valid */
preTakeTime = dds_time ();
status = dds_take (rd, samples, info, MAX_SAMPLES, MAX_SAMPLES);
if (status < 0)
DDS_FATAL("dds_take: %s\n", dds_strretcode(-status));
postTakeTime = dds_time ();
/* Update stats */
difference = (postWriteTime - preWriteTime)/DDS_NSECS_IN_USEC;
writeAccess = *exampleAddTimingToTimeStats (&writeAccess, difference);
writeAccessOverall = *exampleAddTimingToTimeStats (&writeAccessOverall, difference);
difference = (postTakeTime - preTakeTime)/DDS_NSECS_IN_USEC;
readAccess = *exampleAddTimingToTimeStats (&readAccess, difference);
readAccessOverall = *exampleAddTimingToTimeStats (&readAccessOverall, difference);
difference = (postTakeTime - info[0].source_timestamp)/DDS_NSECS_IN_USEC;
roundTrip = *exampleAddTimingToTimeStats (&roundTrip, difference);
roundTripOverall = *exampleAddTimingToTimeStats (&roundTripOverall, difference);
if (!warmUp) {
/* Print stats each second */
difference = (postTakeTime - startTime)/DDS_NSECS_IN_USEC;
if (difference > US_IN_ONE_SEC)
{
printf("%9" PRIi64 " %9lu %8.0f %8" PRIi64 " %8" PRIi64 " %8" PRIi64 " %10lu %8.0f %8" PRIi64 " %10lu %8.0f %8" PRIi64 "\n",
elapsed + 1,
roundTrip.count,
exampleGetMedianFromTimeStats (&roundTrip) / 2,
roundTrip.min / 2,
exampleGet99PercentileFromTimeStats (&roundTrip) / 2,
roundTrip.max / 2,
writeAccess.count,
exampleGetMedianFromTimeStats (&writeAccess),
writeAccess.min,
readAccess.count,
exampleGetMedianFromTimeStats (&readAccess),
readAccess.min);
fflush (stdout);
exampleResetTimeStats (&roundTrip);
exampleResetTimeStats (&writeAccess);
exampleResetTimeStats (&readAccess);
startTime = dds_time ();
elapsed++;
}
}
preWriteTime = dds_time();
status = dds_write_ts (writer, &pub_data, preWriteTime);
if (status < 0)
DDS_FATAL("dds_write_ts: %s\n", dds_strretcode(-status));
postWriteTime = dds_time();
}
static void usage(void)
{
printf ("Usage (parameters must be supplied in order):\n"
"./ping [-l] [payloadSize (bytes, 0 - 100M)] [numSamples (0 = infinite)] [timeOut (seconds, 0 = infinite)]\n"
"./ping quit - ping sends a quit signal to pong.\n"
"Defaults:\n"
"./ping 0 0 0\n");
exit(EXIT_FAILURE);
}
int main (int argc, char *argv[])
{
uint32_t payloadSize = 0;
uint64_t numSamples = 0;
bool invalidargs = false;
dds_time_t timeOut = 0;
dds_time_t time;
dds_time_t difference = 0;
dds_attach_t wsresults[1];
size_t wsresultsize = 1U;
dds_time_t waitTimeout = DDS_SECS (1);
unsigned long i;
int status;
dds_listener_t *listener = NULL;
bool use_listener = false;
int argidx = 1;
/* poor man's getopt works even on Windows */
if (argc > argidx && strcmp(argv[argidx], "-l") == 0)
{
argidx++;
use_listener = true;
}
/* Register handler for Ctrl-C */
#ifdef _WIN32
SetConsoleCtrlHandler ((PHANDLER_ROUTINE)CtrlHandler, TRUE);
#elif !DDSRT_WITH_FREERTOS
struct sigaction sat, oldAction;
sat.sa_handler = CtrlHandler;
sigemptyset (&sat.sa_mask);
sat.sa_flags = 0;
sigaction (SIGINT, &sat, &oldAction);
#endif
exampleInitTimeStats (&roundTrip);
exampleInitTimeStats (&writeAccess);
exampleInitTimeStats (&readAccess);
exampleInitTimeStats (&roundTripOverall);
exampleInitTimeStats (&writeAccessOverall);
exampleInitTimeStats (&readAccessOverall);
memset (&sub_data, 0, sizeof (sub_data));
memset (&pub_data, 0, sizeof (pub_data));
for (i = 0; i < MAX_SAMPLES; i++)
{
samples[i] = &sub_data[i];
}
participant = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL);
if (participant < 0)
DDS_FATAL("dds_create_participant: %s\n", dds_strretcode(-participant));
if (use_listener)
{
listener = dds_create_listener(NULL);
dds_lset_data_available(listener, data_available);
}
prepare_dds(&writer, &reader, &readCond, listener);
if (argc - argidx == 1 && strcmp (argv[argidx], "quit") == 0)
{
printf ("Sending termination request.\n");
fflush (stdout);
/* pong uses a waitset which is triggered by instance disposal, and
quits when it fires. */
dds_sleepfor (DDS_SECS (1));
pub_data.payload._length = 0;
pub_data.payload._buffer = NULL;
pub_data.payload._release = true;
pub_data.payload._maximum = 0;
status = dds_writedispose (writer, &pub_data);
if (status < 0)
DDS_FATAL("dds_writedispose: %s\n", dds_strretcode(-status));
dds_sleepfor (DDS_SECS (1));
goto done;
}
if (argc - argidx == 0)
{
invalidargs = true;
}
if (argc - argidx >= 1)
{
payloadSize = (uint32_t) atol (argv[argidx]);
if (payloadSize > 100 * 1048576)
{
invalidargs = true;
}
}
if (argc - argidx >= 2)
{
numSamples = (uint64_t) atol (argv[argidx+1]);
}
if (argc - argidx >= 3)
{
timeOut = atol (argv[argidx+2]);
}
if (invalidargs || (argc - argidx == 1 && (strcmp (argv[argidx], "-h") == 0 || strcmp (argv[argidx], "--help") == 0)))
usage();
printf ("# payloadSize: %" PRIu32 " | numSamples: %" PRIu64 " | timeOut: %" PRIi64 "\n\n", payloadSize, numSamples, timeOut);
fflush (stdout);
pub_data.payload._length = payloadSize;
pub_data.payload._buffer = payloadSize ? dds_alloc (payloadSize) : NULL;
pub_data.payload._release = true;
pub_data.payload._maximum = 0;
for (i = 0; i < payloadSize; i++)
{
pub_data.payload._buffer[i] = 'a';
}
startTime = dds_time ();
printf ("# Waiting for startup jitter to stabilise\n");
fflush (stdout);
/* Write a sample that pong can send back */
while (!dds_triggered (waitSet) && difference < DDS_SECS(5))
{
status = dds_waitset_wait (waitSet, wsresults, wsresultsize, waitTimeout);
if (status < 0)
DDS_FATAL("dds_waitset_wait: %s\n", dds_strretcode(-status));
if (status > 0 && listener == NULL) /* data */
{
status = dds_take (reader, samples, info, MAX_SAMPLES, MAX_SAMPLES);
if (status < 0)
DDS_FATAL("dds_take: %s\n", dds_strretcode(-status));
}
time = dds_time ();
difference = time - startTime;
}
if (!dds_triggered (waitSet))
{
warmUp = false;
printf("# Warm up complete.\n\n");
printf("# Latency measurements (in us)\n");
printf("# Latency [us] Write-access time [us] Read-access time [us]\n");
printf("# Seconds Count median min 99%% max Count median min Count median min\n");
fflush (stdout);
}
exampleResetTimeStats (&roundTrip);
exampleResetTimeStats (&writeAccess);
exampleResetTimeStats (&readAccess);
startTime = dds_time ();
/* Write a sample that pong can send back */
preWriteTime = dds_time ();
status = dds_write_ts (writer, &pub_data, preWriteTime);
if (status < 0)
DDS_FATAL("dds_write_ts: %s\n", dds_strretcode(-status));
postWriteTime = dds_time ();
for (i = 0; !dds_triggered (waitSet) && (!numSamples || i < numSamples) && !(timeOut && elapsed >= timeOut); i++)
{
status = dds_waitset_wait (waitSet, wsresults, wsresultsize, waitTimeout);
if (status < 0)
DDS_FATAL("dds_waitset_wait: %s\n", dds_strretcode(-status));
if (status != 0 && listener == NULL) {
data_available(reader, NULL);
}
}
if (!warmUp)
{
printf
(
"\n%9s %9lu %8.0f %8" PRIi64 " %8" PRIi64 " %8" PRIi64 " %10lu %8.0f %8" PRIi64 " %10lu %8.0f %8" PRIi64 "\n",
"# Overall",
roundTripOverall.count,
exampleGetMedianFromTimeStats (&roundTripOverall) / 2,
roundTripOverall.min / 2,
exampleGet99PercentileFromTimeStats (&roundTripOverall) / 2,
roundTripOverall.max / 2,
writeAccessOverall.count,
exampleGetMedianFromTimeStats (&writeAccessOverall),
writeAccessOverall.min,
readAccessOverall.count,
exampleGetMedianFromTimeStats (&readAccessOverall),
readAccessOverall.min
);
fflush (stdout);
}
done:
#ifdef _WIN32
SetConsoleCtrlHandler (0, FALSE);
#elif !DDSRT_WITH_FREERTOS
sigaction (SIGINT, &oldAction, 0);
#endif
finalize_dds(participant);
/* Clean up */
exampleDeleteTimeStats (&roundTrip);
exampleDeleteTimeStats (&writeAccess);
exampleDeleteTimeStats (&readAccess);
exampleDeleteTimeStats (&roundTripOverall);
exampleDeleteTimeStats (&writeAccessOverall);
exampleDeleteTimeStats (&readAccessOverall);
for (i = 0; i < MAX_SAMPLES; i++)
{
RoundTripModule_DataType_free (&sub_data[i], DDS_FREE_CONTENTS);
}
RoundTripModule_DataType_free (&pub_data, DDS_FREE_CONTENTS);
return EXIT_SUCCESS;
}
static dds_entity_t prepare_dds(dds_entity_t *wr, dds_entity_t *rd, dds_entity_t *rdcond, dds_listener_t *listener)
{
dds_return_t status;
dds_entity_t topic;
dds_entity_t publisher;
dds_entity_t subscriber;
const char *pubPartitions[] = { "ping" };
const char *subPartitions[] = { "pong" };
dds_qos_t *pubQos;
dds_qos_t *dwQos;
dds_qos_t *drQos;
dds_qos_t *subQos;
/* A DDS_Topic is created for our sample type on the domain participant. */
topic = dds_create_topic (participant, &RoundTripModule_DataType_desc, "RoundTrip", NULL, NULL);
if (topic < 0)
DDS_FATAL("dds_create_topic: %s\n", dds_strretcode(-topic));
/* A DDS_Publisher is created on the domain participant. */
pubQos = dds_create_qos ();
dds_qset_partition (pubQos, 1, pubPartitions);
publisher = dds_create_publisher (participant, pubQos, NULL);
if (publisher < 0)
DDS_FATAL("dds_create_publisher: %s\n", dds_strretcode(-publisher));
dds_delete_qos (pubQos);
/* A DDS_DataWriter is created on the Publisher & Topic with a modified Qos. */
dwQos = dds_create_qos ();
dds_qset_reliability (dwQos, DDS_RELIABILITY_RELIABLE, DDS_SECS (10));
dds_qset_writer_data_lifecycle (dwQos, false);
*wr = dds_create_writer (publisher, topic, dwQos, NULL);
if (*wr < 0)
DDS_FATAL("dds_create_writer: %s\n", dds_strretcode(-*wr));
dds_delete_qos (dwQos);
/* A DDS_Subscriber is created on the domain participant. */
subQos = dds_create_qos ();
dds_qset_partition (subQos, 1, subPartitions);
subscriber = dds_create_subscriber (participant, subQos, NULL);
if (subscriber < 0)
DDS_FATAL("dds_create_subscriber: %s\n", dds_strretcode(-subscriber));
dds_delete_qos (subQos);
/* A DDS_DataReader is created on the Subscriber & Topic with a modified QoS. */
drQos = dds_create_qos ();
dds_qset_reliability (drQos, DDS_RELIABILITY_RELIABLE, DDS_SECS(10));
*rd = dds_create_reader (subscriber, topic, drQos, listener);
if (*rd < 0)
DDS_FATAL("dds_create_reader: %s\n", dds_strretcode(-*rd));
dds_delete_qos (drQos);
waitSet = dds_create_waitset (participant);
if (listener == NULL) {
*rdcond = dds_create_readcondition (*rd, DDS_ANY_STATE);
status = dds_waitset_attach (waitSet, *rdcond, *rd);
if (status < 0)
DDS_FATAL("dds_waitset_attach: %s\n", dds_strretcode(-status));
} else {
*rdcond = 0;
}
status = dds_waitset_attach (waitSet, waitSet, waitSet);
if (status < 0)
DDS_FATAL("dds_waitset_attach: %s\n", dds_strretcode(-status));
return participant;
}
static void finalize_dds(dds_entity_t ppant)
{
dds_return_t status;
status = dds_delete (ppant);
if (status < 0)
DDS_FATAL("dds_delete: %s\n", dds_strretcode(-status));
}

227
examples/roundtrip/pong.c Normal file
View file

@ -0,0 +1,227 @@
#include "dds/dds.h"
#include "RoundTrip.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <stdlib.h>
static dds_entity_t waitSet;
#define MAX_SAMPLES 10
/* Forward declarations */
static dds_entity_t prepare_dds(dds_entity_t *writer, dds_entity_t *reader, dds_entity_t *readCond, dds_listener_t *listener);
static void finalize_dds(dds_entity_t participant, RoundTripModule_DataType data[MAX_SAMPLES]);
#ifdef _WIN32
#include <Windows.h>
static bool CtrlHandler (DWORD fdwCtrlType)
{
dds_waitset_set_trigger (waitSet, true);
return true; //Don't let other handlers handle this key
}
#elif !DDSRT_WITH_FREERTOS
static void CtrlHandler (int sig)
{
(void)sig;
dds_waitset_set_trigger (waitSet, true);
}
#endif
static RoundTripModule_DataType data[MAX_SAMPLES];
static void * samples[MAX_SAMPLES];
static dds_sample_info_t info[MAX_SAMPLES];
static dds_entity_t participant;
static dds_entity_t reader;
static dds_entity_t writer;
static dds_entity_t readCond;
static void data_available(dds_entity_t rd, void *arg)
{
int status, samplecount;
(void)arg;
samplecount = dds_take (rd, samples, info, MAX_SAMPLES, MAX_SAMPLES);
if (samplecount < 0)
DDS_FATAL("dds_take: %s\n", dds_strretcode(-samplecount));
for (int j = 0; !dds_triggered (waitSet) && j < samplecount; j++)
{
/* If writer has been disposed terminate pong */
if (info[j].instance_state == DDS_IST_NOT_ALIVE_DISPOSED)
{
printf ("Received termination request. Terminating.\n");
dds_waitset_set_trigger (waitSet, true);
break;
}
else if (info[j].valid_data)
{
/* If sample is valid, send it back to ping */
RoundTripModule_DataType * valid_sample = &data[j];
status = dds_write_ts (writer, valid_sample, info[j].source_timestamp);
if (status < 0)
DDS_FATAL("dds_write_ts: %d\n", -status);
}
}
}
int main (int argc, char *argv[])
{
dds_duration_t waitTimeout = DDS_INFINITY;
unsigned int i;
int status;
dds_attach_t wsresults[1];
size_t wsresultsize = 1U;
dds_listener_t *listener = NULL;
bool use_listener = false;
int argidx = 1;
if (argc > argidx && strcmp(argv[argidx], "-l") == 0)
{
argidx++;
use_listener = true;
}
/* Register handler for Ctrl-C */
#ifdef _WIN32
SetConsoleCtrlHandler ((PHANDLER_ROUTINE)CtrlHandler, TRUE);
#elif !DDSRT_WITH_FREERTOS
struct sigaction sat, oldAction;
sat.sa_handler = CtrlHandler;
sigemptyset (&sat.sa_mask);
sat.sa_flags = 0;
sigaction (SIGINT, &sat, &oldAction);
#endif
/* Initialize sample data */
memset (data, 0, sizeof (data));
for (i = 0; i < MAX_SAMPLES; i++)
{
samples[i] = &data[i];
}
participant = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL);
if (participant < 0)
DDS_FATAL("dds_create_participant: %s\n", dds_strretcode(-participant));
if (use_listener)
{
listener = dds_create_listener(NULL);
dds_lset_data_available(listener, data_available);
}
(void)prepare_dds(&writer, &reader, &readCond, listener);
while (!dds_triggered (waitSet))
{
/* Wait for a sample from ping */
status = dds_waitset_wait (waitSet, wsresults, wsresultsize, waitTimeout);
if (status < 0)
DDS_FATAL("dds_waitset_wait: %s\n", dds_strretcode(-status));
/* Take samples */
if (listener == NULL) {
data_available (reader, 0);
}
}
#ifdef _WIN32
SetConsoleCtrlHandler (0, FALSE);
#elif !DDSRT_WITH_FREERTOS
sigaction (SIGINT, &oldAction, 0);
#endif
/* Clean up */
finalize_dds(participant, data);
return EXIT_SUCCESS;
}
static void finalize_dds(dds_entity_t pp, RoundTripModule_DataType xs[MAX_SAMPLES])
{
dds_return_t status;
status = dds_delete (pp);
if (status < 0)
DDS_FATAL("dds_delete: %s\n", dds_strretcode(-status));
for (unsigned int i = 0; i < MAX_SAMPLES; i++)
{
RoundTripModule_DataType_free (&xs[i], DDS_FREE_CONTENTS);
}
}
static dds_entity_t prepare_dds(dds_entity_t *wr, dds_entity_t *rd, dds_entity_t *rdcond, dds_listener_t *rdlist)
{
const char *pubPartitions[] = { "pong" };
const char *subPartitions[] = { "ping" };
dds_qos_t *qos;
dds_entity_t subscriber;
dds_entity_t publisher;
dds_entity_t topic;
dds_return_t status;
/* A DDS Topic is created for our sample type on the domain participant. */
topic = dds_create_topic (participant, &RoundTripModule_DataType_desc, "RoundTrip", NULL, NULL);
if (topic < 0)
DDS_FATAL("dds_create_topic: %s\n", dds_strretcode(-topic));
/* A DDS Publisher is created on the domain participant. */
qos = dds_create_qos ();
dds_qset_partition (qos, 1, pubPartitions);
publisher = dds_create_publisher (participant, qos, NULL);
if (publisher < 0)
DDS_FATAL("dds_create_publisher: %s\n", dds_strretcode(-publisher));
dds_delete_qos (qos);
/* A DDS DataWriter is created on the Publisher & Topic with a modififed Qos. */
qos = dds_create_qos ();
dds_qset_reliability (qos, DDS_RELIABILITY_RELIABLE, DDS_SECS(10));
dds_qset_writer_data_lifecycle (qos, false);
*wr = dds_create_writer (publisher, topic, qos, NULL);
if (*wr < 0)
DDS_FATAL("dds_create_writer: %s\n", dds_strretcode(-*wr));
dds_delete_qos (qos);
/* A DDS Subscriber is created on the domain participant. */
qos = dds_create_qos ();
dds_qset_partition (qos, 1, subPartitions);
subscriber = dds_create_subscriber (participant, qos, NULL);
if (subscriber < 0)
DDS_FATAL("dds_create_subscriber: %s\n", dds_strretcode(-subscriber));
dds_delete_qos (qos);
/* A DDS DataReader is created on the Subscriber & Topic with a modified QoS. */
qos = dds_create_qos ();
dds_qset_reliability (qos, DDS_RELIABILITY_RELIABLE, DDS_SECS(10));
*rd = dds_create_reader (subscriber, topic, qos, rdlist);
if (*rd < 0)
DDS_FATAL("dds_create_reader: %s\n", dds_strretcode(-*rd));
dds_delete_qos (qos);
waitSet = dds_create_waitset (participant);
if (rdlist == NULL) {
*rdcond = dds_create_readcondition (*rd, DDS_ANY_STATE);
status = dds_waitset_attach (waitSet, *rdcond, *rd);
if (status < 0)
DDS_FATAL("dds_waitset_attach: %s\n", dds_strretcode(-status));
} else {
*rdcond = 0;
}
status = dds_waitset_attach (waitSet, waitSet, waitSet);
if (status < 0)
DDS_FATAL("dds_waitset_attach: %s\n", dds_strretcode(-status));
printf ("Waiting for samples from ping to send back...\n");
fflush (stdout);
return participant;
}

View file

@ -0,0 +1,83 @@
..
Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
This program and the accompanying materials are made available under the
terms of the Eclipse Public License v. 2.0 which is available at
http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
v. 1.0 which is available at
http://www.eclipse.org/org/documents/edl-v10.php.
SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
Roundtrip
==========
Description
***********
The Roundtrip example allows the measurement of roundtrip duration when sending and receiving back a single message.
Design
******
It consists of 2 units:
- Pong: waits for messages from ping and sends the same message back.
- Ping: Sends a message to pong and waits for its return.
Scenario
********
A message is sent by the **ping** executable on the "PING" partition, which the **pong** executable is waiting for.
The **pong** executable sends the same message back on the "PONG" partition, which the **ping** executable is waiting for.
This sequence is repeated a configurable number of times.
The **ping** executable measures:
- writeAccess time: time the write() method took.
- readAccess time: time the take() method took.
- roundTrip time: time between the call to the write() method and the return of the take() method.
- **ping** also calculates min/max/average statistics on these values over a configurable number of samples and/or time out period.
Configurable:
- payloadSize: the size of the payload in bytes.
- numSamples: the number of samples to send.
- timeOut: the number of seconds ping should run for.
Running the example
*******************
It is recommended that you run ping and pong in separate terminals to avoid mixing the output.
- Open 2 terminals.
- In the first terminal start Pong by running pong.
pong usage:
``./pong``
- In the second terminal start Ping by running ping.
ping usage (parameters must be supplied in order):
``./ping [payloadSize (bytes, 0 - 655536)] [numSamples (0 = infinite)] [timeOut (seconds, 0 = infinite)]``
``./ping quit - ping sends a quit signal to pong.``
defaults:
``./ping 0 0 0``
- To achieve optimal performance it is recommended to set the CPU affinity so that ping and pong run on separate CPU cores,
and use real-time scheduling. In a Linux environment this can be achieved as follows:
pong usage:
``taskset -c 0 chrt -f 80 ./pong``
ping usage:
``taskset -c 1 chrt -f 80 ./ping [payloadSize (bytes, 0 - 655536)] [numSamples (0 = infinite)] [timeOut (seconds, 0 = infinite)]``
On Windows the CPU affinity and scheduling class can be set as follows:
pong usage:
``START /affinity 1 /high cmd /k "pong.exe"``
ping usage:
``START /affinity 2 /high cmd /k "ping.exe" [payloadSize (bytes, 0 - 655536)] [numSamples (0 = infinite)] [timeOut (seconds, 0 = infinite)]``

View file

@ -0,0 +1,86 @@
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = ['sphinx.ext.autodoc',
'sphinx.ext.intersphinx',
'sphinx.ext.coverage',
'sphinx.ext.imgmath',
'sphinx.ext.ifconfig',
'breathe']
# Add any paths that contain templates here, relative to this directory.
#templates_path = ['@CMAKE_CURRENT_SOuRCE_DIR@/_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
# The master toctree document.
master_doc = 'examples'
# General information about the project.
project = u'@CMAKE_PROJECT_NAME@'
copyright = u'@sph_conf_copyright@'
author = u'@sph_conf_author@'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y.Z version.
version = u'@sph_conf_version@'
# The full version, including alpha/beta/rc tags.
release = u'@sph_conf_release@'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This patterns also effect to html_static_path and html_extra_path
exclude_patterns = []
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'alabaster'
html_show_sourcelink = False
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#
html_theme_options = { 'show_powered_by': False }
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['@PROJECT_SOURCE_DIR@/docs/manual/_static']
# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
#
# This is required for the alabaster theme
# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars
html_sidebars = {
'**': [
'about.html',
'navigation.html',
'relations.html', # needs 'show_related': True theme option to display
'searchbox.html',
'donate.html',
]
}

View file

@ -0,0 +1,33 @@
#
# Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License v. 2.0 which is available at
# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
# v. 1.0 which is available at
# http://www.eclipse.org/org/documents/edl-v10.php.
#
# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
#
cmake_minimum_required(VERSION 3.5)
if (NOT TARGET CycloneDDS::ddsc)
# Find the CycloneDDS package. If it is not in a default location, try
# finding it relative to the example where it most likely resides.
find_package(CycloneDDS REQUIRED PATHS "${CMAKE_SOURCE_DIR}/../../")
endif()
# This is a convenience function, provided by the CycloneDDS package,
# that will supply a library target related the the given idl file.
# In short, it takes the idl file, generates the source files with
# the proper data types and compiles them into a library.
idlc_generate(Throughput_lib Throughput.idl)
# Both executables have only one related source file.
add_executable(ThroughputPublisher publisher.c)
add_executable(ThroughputSubscriber subscriber.c)
# Both executables need to be linked to the idl data type library and
# the ddsc API library.
target_link_libraries(ThroughputPublisher Throughput_lib CycloneDDS::ddsc)
target_link_libraries(ThroughputSubscriber Throughput_lib CycloneDDS::ddsc)

View file

@ -0,0 +1,9 @@
module ThroughputModule
{
struct DataType
{
unsigned long long count;
sequence<octet> payload;
};
#pragma keylist DataType
};

View file

@ -0,0 +1,295 @@
#include "dds/dds.h"
#include "Throughput.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
/*
* The Throughput example measures data throughput in bytes per second. The publisher
* allows you to specify a payload size in bytes as well as allowing you to specify
* whether to send data in bursts. The publisher will continue to send data forever
* unless a time out is specified. The subscriber will receive data and output the
* total amount received and the data rate in bytes per second. It will also indicate
* if any samples were received out of order. A maximum number of cycles can be
* specified and once this has been reached the subscriber will terminate and output
* totals and averages.
*/
#define MAX_SAMPLES 100
static bool done = false;
/* Forward declarations */
static dds_return_t wait_for_reader(dds_entity_t writer, dds_entity_t participant);
static void start_writing(dds_entity_t writer, ThroughputModule_DataType *sample,
int burstInterval, uint32_t burstSize, int timeOut);
static int parse_args(int argc, char **argv, uint32_t *payloadSize, int *burstInterval,
uint32_t *burstSize, int *timeOut, char **partitionName);
static dds_entity_t prepare_dds(dds_entity_t *writer, const char *partitionName);
static void finalize_dds(dds_entity_t participant, dds_entity_t writer, ThroughputModule_DataType sample);
static void sigint (int sig)
{
(void)sig;
done = true;
}
int main (int argc, char **argv)
{
uint32_t payloadSize = 8192;
int burstInterval = 0;
uint32_t burstSize = 1;
int timeOut = 0;
char * partitionName = "Throughput example";
dds_entity_t participant;
dds_entity_t writer;
dds_return_t rc;
ThroughputModule_DataType sample;
if (parse_args(argc, argv, &payloadSize, &burstInterval, &burstSize, &timeOut, &partitionName) == EXIT_FAILURE) {
return EXIT_FAILURE;
}
participant = prepare_dds(&writer, partitionName);
/* Wait until have a reader */
if (wait_for_reader(writer, participant) == 0) {
printf ("=== [Publisher] Did not discover a reader.\n");
fflush (stdout);
rc = dds_delete (participant);
if (rc < 0)
DDS_FATAL("dds_delete: %s\n", dds_strretcode(-rc));
return EXIT_FAILURE;
}
/* Fill the sample payload with data */
sample.count = 0;
sample.payload._buffer = dds_alloc (payloadSize);
sample.payload._length = payloadSize;
sample.payload._release = true;
for (uint32_t i = 0; i < payloadSize; i++) {
sample.payload._buffer[i] = 'a';
}
/* Register handler for Ctrl-C */
signal (SIGINT, sigint);
/* Register the sample instance and write samples repeatedly or until time out */
start_writing(writer, &sample, burstInterval, burstSize, timeOut);
/* Cleanup */
finalize_dds(participant, writer, sample);
return EXIT_SUCCESS;
}
static int parse_args(
int argc,
char **argv,
uint32_t *payloadSize,
int *burstInterval,
uint32_t *burstSize,
int *timeOut,
char **partitionName)
{
int result = EXIT_SUCCESS;
/*
* Get the program parameters
* Parameters: publisher [payloadSize] [burstInterval] [burstSize] [timeOut] [partitionName]
*/
if (argc == 2 && (strcmp (argv[1], "-h") == 0 || strcmp (argv[1], "--help") == 0))
{
printf ("Usage (parameters must be supplied in order):\n");
printf ("./publisher [payloadSize (bytes)] [burstInterval (ms)] [burstSize (samples)] [timeOut (seconds)] [partitionName]\n");
printf ("Defaults:\n");
printf ("./publisher 8192 0 1 0 \"Throughput example\"\n");
return EXIT_FAILURE;
}
if (argc > 1)
{
*payloadSize = (uint32_t) atoi (argv[1]); /* The size of the payload in bytes */
}
if (argc > 2)
{
*burstInterval = atoi (argv[2]); /* The time interval between each burst in ms */
}
if (argc > 3)
{
*burstSize = (uint32_t) atoi (argv[3]); /* The number of samples to send each burst */
}
if (argc > 4)
{
*timeOut = atoi (argv[4]); /* The number of seconds the publisher should run for (0 = infinite) */
}
if (argc > 5)
{
*partitionName = argv[5]; /* The name of the partition */
}
printf ("payloadSize: %"PRIu32" bytes burstInterval: %u ms burstSize: %"PRId32" timeOut: %u seconds partitionName: %s\n",
*payloadSize, *burstInterval, *burstSize, *timeOut, *partitionName);
fflush (stdout);
return result;
}
static dds_entity_t prepare_dds(dds_entity_t *writer, const char *partitionName)
{
dds_entity_t participant;
dds_entity_t topic;
dds_entity_t publisher;
const char *pubParts[1];
dds_qos_t *pubQos;
dds_qos_t *dwQos;
/* A domain participant is created for the default domain. */
participant = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL);
if (participant < 0)
DDS_FATAL("dds_create_participant: %s\n", dds_strretcode(-participant));
/* A topic is created for our sample type on the domain participant. */
topic = dds_create_topic (participant, &ThroughputModule_DataType_desc, "Throughput", NULL, NULL);
if (topic < 0)
DDS_FATAL("dds_create_topic: %s\n", dds_strretcode(-topic));
/* A publisher is created on the domain participant. */
pubQos = dds_create_qos ();
pubParts[0] = partitionName;
dds_qset_partition (pubQos, 1, pubParts);
publisher = dds_create_publisher (participant, pubQos, NULL);
if (publisher < 0)
DDS_FATAL("dds_create_publisher: %s\n", dds_strretcode(-publisher));
dds_delete_qos (pubQos);
/* A DataWriter is created on the publisher. */
dwQos = dds_create_qos ();
dds_qset_reliability (dwQos, DDS_RELIABILITY_RELIABLE, DDS_SECS (10));
dds_qset_history (dwQos, DDS_HISTORY_KEEP_ALL, 0);
dds_qset_resource_limits (dwQos, MAX_SAMPLES, DDS_LENGTH_UNLIMITED, DDS_LENGTH_UNLIMITED);
*writer = dds_create_writer (publisher, topic, dwQos, NULL);
if (*writer < 0)
DDS_FATAL("dds_create_writer: %s\n", dds_strretcode(-*writer));
dds_delete_qos (dwQos);
/* Enable write batching */
dds_write_set_batch (true);
return participant;
}
static dds_return_t wait_for_reader(dds_entity_t writer, dds_entity_t participant)
{
printf ("\n=== [Publisher] Waiting for a reader ...\n");
fflush (stdout);
dds_return_t rc;
dds_entity_t waitset;
rc = dds_set_status_mask(writer, DDS_PUBLICATION_MATCHED_STATUS);
if (rc < 0)
DDS_FATAL("dds_set_status_mask: %s\n", dds_strretcode(-rc));
waitset = dds_create_waitset(participant);
if (waitset < 0)
DDS_FATAL("dds_create_waitset: %s\n", dds_strretcode(-waitset));
rc = dds_waitset_attach(waitset, writer, (dds_attach_t)NULL);
if (rc < 0)
DDS_FATAL("dds_waitset_attach: %s\n", dds_strretcode(-rc));
rc = dds_waitset_wait(waitset, NULL, 0, DDS_SECS(30));
if (rc < 0)
DDS_FATAL("dds_waitset_wait: %s\n", dds_strretcode(-rc));
return rc;
}
static void start_writing(
dds_entity_t writer,
ThroughputModule_DataType *sample,
int burstInterval,
uint32_t burstSize,
int timeOut)
{
bool timedOut = false;
dds_time_t pubStart = dds_time ();
dds_time_t now;
dds_time_t deltaTv;
dds_return_t status;
if (!done)
{
dds_time_t burstStart = pubStart;
unsigned int burstCount = 0;
printf ("=== [Publisher] Writing samples...\n");
fflush (stdout);
while (!done && !timedOut)
{
/* Write data until burst size has been reached */
if (burstCount < burstSize)
{
status = dds_write (writer, sample);
if (status == DDS_RETCODE_TIMEOUT)
{
timedOut = true;
}
else if (status < 0)
{
DDS_FATAL("dds_write: %s\n", dds_strretcode(-status));
}
else
{
sample->count++;
burstCount++;
}
}
else if (burstInterval)
{
/* Sleep until burst interval has passed */
dds_time_t time = dds_time ();
deltaTv = time - burstStart;
if (deltaTv < DDS_MSECS (burstInterval))
{
dds_write_flush (writer);
dds_sleepfor (DDS_MSECS (burstInterval) - deltaTv);
}
burstStart = dds_time ();
burstCount = 0;
}
else
{
burstCount = 0;
}
if (timeOut)
{
now = dds_time ();
deltaTv = now - pubStart;
if ((deltaTv) > DDS_SECS (timeOut))
{
timedOut = true;
}
}
}
dds_write_flush (writer);
printf ("=== [Publisher] %s, %llu samples written.\n", done ? "Terminated" : "Timed out", (unsigned long long) sample->count);
fflush (stdout);
}
}
static void finalize_dds(dds_entity_t participant, dds_entity_t writer, ThroughputModule_DataType sample)
{
dds_return_t status = dds_dispose (writer, &sample);
if (status != DDS_RETCODE_TIMEOUT && status < 0)
DDS_FATAL("dds_dispose: %s\n", dds_strretcode(-status));
dds_free (sample.payload._buffer);
status = dds_delete (participant);
if (status < 0)
DDS_FATAL("dds_delete: %s\n", dds_strretcode(-status));
}

View file

@ -0,0 +1,99 @@
..
Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
This program and the accompanying materials are made available under the
terms of the Eclipse Public License v. 2.0 which is available at
http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
v. 1.0 which is available at
http://www.eclipse.org/org/documents/edl-v10.php.
SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
Throughput
==========
Description
***********
The Throughput example allows the measurement of data throughput when receiving samples from a publisher.
Design
******
It consists of 2 units:
- Publisher: sends samples at a specified size and rate.
- Subscriber: Receives samples and outputs statistics about throughput
Scenario
********
The **publisher** sends samples and allows you to specify a payload size in bytes as well as allowing you to specify whether
to send data in bursts. The **publisher** will continue to send data forever unless a time-out is specified.
Configurable:
- payloadSize: the size of the payload in bytes
- burstInterval: the time interval between each burst in ms
- burstSize: the number of samples to send each burst
- timeOut: the number of seconds the publisher should run for (0=infinite)
- partitionName: the name of the partition
The **subscriber** will receive data and output the total amount received and the data-rate in bytes-per-second. It will
also indicate if any samples were received out-of-order. A maximum number of cycles can be specified and once this has
been reached the subscriber will terminate and output totals and averages.
The **subscriber** executable measures:
- transferred: the total amount of data transferred in bytes.
- outOfOrder: the number of samples that were received out of order.
- transfer rate: the data transfer rate in bytes per second.
- subscriber also calculates statistics on these values over a configurable number of cycles.
Configurable:
- maxCycles: the number of times to output statistics before terminating
- pollingDelay
- partitionName: the name of the partition
Running the example
*******************
It is recommended that you run ping and pong in separate terminals to avoid mixing the output.
- Open 2 terminals.
- In the first terminal start Publisher by running publisher
publisher usage (parameters must be supplied in order):
``./publisher [payloadSize (bytes)] [burstInterval (ms)] [burstSize (samples)] [timeOut (seconds)] [partitionName]``
defaults:
``./publisher 8192 0 1 0 "Throughput example"``
- In the second terminal start Ping by running subscriber
subscriber usage (parameters must be supplied in order):
``./subscriber [maxCycles (0=infinite)] [pollingDelay (ms, 0 = event based)] [partitionName]``
defaults:
``./subscriber 0 0 "Throughput example"``
- To achieve optimal performance it is recommended to set the CPU affinity so that ping and pong run on separate CPU cores,
and use real-time scheduling. In a Linux environment this can be achieved as follows:
publisher usage:
``taskset -c 0 chrt -f 80 ./publisher [payloadSize (bytes)] [burstInterval (ms)] [burstSize (samples)] [timeOut (seconds)] [partitionName]``
subscriber usage:
``taskset -c 1 chrt -f 80 ./subscriber [maxCycles (0 = infinite)] [pollingDelay (ms, 0 = event based)] [partitionName]``
On Windows the CPU affinity and prioritized scheduling class can be set as follows:
publisher usage:
``START /affinity 1 /high cmd /k "publisher.exe" [payloadSize (bytes)] [burstInterval (ms)] [burstSize (samples)] [timeOut (seconds)] [partitionName]``
subscriber usage:
``START /affinity 2 /high cmd /k "subscriber.exe" [maxCycles (0 = infinite)] [pollingDelay (ms, 0 = event based)] [partitionName]``

View file

@ -0,0 +1,400 @@
#include "dds/dds.h"
#include "Throughput.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <assert.h>
/*
* The Throughput example measures data throughput in bytes per second. The publisher
* allows you to specify a payload size in bytes as well as allowing you to specify
* whether to send data in bursts. The publisher will continue to send data forever
* unless a time out is specified. The subscriber will receive data and output the
* total amount received and the data rate in bytes per second. It will also indicate
* if any samples were received out of order. A maximum number of cycles can be
* specified and once this has been reached the subscriber will terminate and output
* totals and averages.
*/
#define BYTES_PER_SEC_TO_MEGABITS_PER_SEC 125000
#define MAX_SAMPLES 1000
typedef struct HandleEntry
{
dds_instance_handle_t handle;
unsigned long long count;
struct HandleEntry * next;
} HandleEntry;
typedef struct HandleMap
{
HandleEntry *entries;
} HandleMap;
static long pollingDelay = -1; /* i.e. use a listener */
static HandleMap * imap;
static unsigned long long outOfOrder = 0;
static unsigned long long total_bytes = 0;
static unsigned long long total_samples = 0;
static dds_time_t startTime = 0;
static unsigned long payloadSize = 0;
static ThroughputModule_DataType data [MAX_SAMPLES];
static void * samples[MAX_SAMPLES];
static dds_entity_t waitSet;
static volatile sig_atomic_t done = false;
/* Forward declarations */
static HandleMap * HandleMap__alloc (void);
static void HandleMap__free (HandleMap *map);
static HandleEntry * store_handle (HandleMap *map, dds_instance_handle_t key);
static HandleEntry * retrieve_handle (HandleMap *map, dds_instance_handle_t key);
static void data_available_handler (dds_entity_t reader, void *arg);
static int parse_args(int argc, char **argv, unsigned long long *maxCycles, char **partitionName);
static void process_samples(dds_entity_t reader, unsigned long long maxCycles);
static dds_entity_t prepare_dds(dds_entity_t *reader, const char *partitionName);
static void finalize_dds(dds_entity_t participant);
static void sigint (int sig)
{
(void) sig;
done = true;
}
int main (int argc, char **argv)
{
unsigned long long maxCycles = 0;
char *partitionName = "Throughput example";
dds_entity_t participant;
dds_entity_t reader;
if (parse_args(argc, argv, &maxCycles, &partitionName) == EXIT_FAILURE)
{
return EXIT_FAILURE;
}
printf ("Cycles: %llu | PollingDelay: %ld | Partition: %s\n", maxCycles, pollingDelay, partitionName);
fflush (stdout);
participant = prepare_dds(&reader, partitionName);
printf ("=== [Subscriber] Waiting for samples...\n");
fflush (stdout);
/* Process samples until Ctrl-C is pressed or until maxCycles */
/* has been reached (0 = infinite) */
signal (SIGINT, sigint);
process_samples(reader, maxCycles);
dds_set_status_mask (reader, 0);
HandleMap__free (imap);
finalize_dds (participant);
return EXIT_SUCCESS;
}
/*
* This struct contains all of the entities used in the publisher and subscriber.
*/
static HandleMap * HandleMap__alloc (void)
{
HandleMap * map = malloc (sizeof (*map));
assert(map);
memset (map, 0, sizeof (*map));
return map;
}
static void HandleMap__free (HandleMap *map)
{
HandleEntry * entry;
while (map->entries)
{
entry = map->entries;
map->entries = entry->next;
free (entry);
}
free (map);
}
static HandleEntry * store_handle (HandleMap *map, dds_instance_handle_t key)
{
HandleEntry * entry = malloc (sizeof (*entry));
assert(entry);
memset (entry, 0, sizeof (*entry));
entry->handle = key;
entry->next = map->entries;
map->entries = entry;
return entry;
}
static HandleEntry * retrieve_handle (HandleMap *map, dds_instance_handle_t key)
{
HandleEntry * entry = map->entries;
while (entry)
{
if (entry->handle == key)
{
break;
}
entry = entry->next;
}
return entry;
}
static int do_take (dds_entity_t reader)
{
int samples_received;
dds_sample_info_t info [MAX_SAMPLES];
dds_instance_handle_t ph = 0;
HandleEntry * current = NULL;
if (startTime == 0)
{
startTime = dds_time ();
}
/* Take samples and iterate through them */
samples_received = dds_take (reader, samples, info, MAX_SAMPLES, MAX_SAMPLES);
if (samples_received < 0)
DDS_FATAL("dds_take: %s\n", dds_strretcode(-samples_received));
for (int i = 0; !done && i < samples_received; i++)
{
if (info[i].valid_data)
{
ph = info[i].publication_handle;
current = retrieve_handle (imap, ph);
ThroughputModule_DataType * this_sample = &data[i];
if (current == NULL)
{
current = store_handle (imap, ph);
current->count = this_sample->count;
}
if (this_sample->count != current->count)
{
outOfOrder++;
}
current->count = this_sample->count + 1;
/* Add the sample payload size to the total received */
payloadSize = this_sample->payload._length;
total_bytes += payloadSize + 8;
total_samples++;
}
}
return samples_received;
}
static void data_available_handler (dds_entity_t reader, void *arg)
{
(void)arg;
do_take (reader);
}
static int parse_args(int argc, char **argv, unsigned long long *maxCycles, char **partitionName)
{
/*
* Get the program parameters
* Parameters: subscriber [maxCycles] [pollingDelay] [partitionName]
*/
if (argc == 2 && (strcmp (argv[1], "-h") == 0 || strcmp (argv[1], "--help") == 0))
{
printf ("Usage (parameters must be supplied in order):\n");
printf ("./subscriber [maxCycles (0 = infinite)] [pollingDelay (ms, 0 = waitset, -1 = listener)] [partitionName]\n");
printf ("Defaults:\n");
printf ("./subscriber 0 0 \"Throughput example\"\n");
return EXIT_FAILURE;
}
if (argc > 1)
{
*maxCycles = (unsigned long long) atoi (argv[1]); /* The number of times to output statistics before terminating */
}
if (argc > 2)
{
pollingDelay = atoi (argv[2]); /* The number of ms to wait between reads (0 = waitset, -1 = listener) */
}
if (argc > 3)
{
*partitionName = argv[3]; /* The name of the partition */
}
return EXIT_SUCCESS;
}
static void process_samples(dds_entity_t reader, unsigned long long maxCycles)
{
dds_return_t status;
unsigned long long prev_bytes = 0;
unsigned long long prev_samples = 0;
dds_attach_t wsresults[2];
dds_time_t deltaTv;
bool first_batch = true;
unsigned long cycles = 0;
double deltaTime = 0;
dds_time_t prev_time = 0;
dds_time_t time_now = 0;
while (!done && (maxCycles == 0 || cycles < maxCycles))
{
if (pollingDelay > 0)
dds_sleepfor (DDS_MSECS (pollingDelay));
else
{
status = dds_waitset_wait (waitSet, wsresults, sizeof(wsresults)/sizeof(wsresults[0]), DDS_MSECS(100));
if (status < 0)
DDS_FATAL("dds_waitset_wait: %s\n", dds_strretcode(-status));
}
if (pollingDelay >= 0)
{
while (do_take (reader))
;
}
time_now = dds_time();
if (!first_batch)
{
deltaTv = time_now - prev_time;
deltaTime = (double) deltaTv / DDS_NSECS_IN_SEC;
if (deltaTime >= 1.0 && total_samples != prev_samples)
{
printf ("=== [Subscriber] %5.3f Payload size: %lu | Total received: %llu samples, %llu bytes | Out of order: %llu samples "
"Transfer rate: %.2lf samples/s, %.2lf Mbit/s\n",
deltaTime, payloadSize, total_samples, total_bytes, outOfOrder,
(deltaTime != 0.0) ? ((double)(total_samples - prev_samples) / deltaTime) : 0,
(deltaTime != 0.0) ? ((double)((total_bytes - prev_bytes) / BYTES_PER_SEC_TO_MEGABITS_PER_SEC) / deltaTime) : 0);
fflush (stdout);
cycles++;
prev_time = time_now;
prev_bytes = total_bytes;
prev_samples = total_samples;
}
}
else
{
prev_time = time_now;
first_batch = false;
}
}
/* Output totals and averages */
deltaTv = time_now - startTime;
deltaTime = (double) (deltaTv / DDS_NSECS_IN_SEC);
printf ("\nTotal received: %llu samples, %llu bytes\n", total_samples, total_bytes);
printf ("Out of order: %llu samples\n", outOfOrder);
printf ("Average transfer rate: %.2lf samples/s, ", (double)total_samples / deltaTime);
printf ("%.2lf Mbit/s\n", (double)(total_bytes / BYTES_PER_SEC_TO_MEGABITS_PER_SEC) / deltaTime);
fflush (stdout);
}
static dds_entity_t prepare_dds(dds_entity_t *reader, const char *partitionName)
{
dds_return_t status;
dds_entity_t topic;
dds_entity_t subscriber;
dds_listener_t *rd_listener;
dds_entity_t participant;
int32_t maxSamples = 4000;
const char *subParts[1];
dds_qos_t *subQos = dds_create_qos ();
dds_qos_t *drQos = dds_create_qos ();
/* A Participant is created for the default domain. */
participant = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL);
if (participant < 0)
DDS_FATAL("dds_create_particpant: %s\n", dds_strretcode(-participant));
/* A Topic is created for our sample type on the domain participant. */
topic = dds_create_topic (participant, &ThroughputModule_DataType_desc, "Throughput", NULL, NULL);
if (topic < 0)
DDS_FATAL("dds_create_topic: %s\n", dds_strretcode(-topic));
/* A Subscriber is created on the domain participant. */
subParts[0] = partitionName;
dds_qset_partition (subQos, 1, subParts);
subscriber = dds_create_subscriber (participant, subQos, NULL);
if (subscriber < 0)
DDS_FATAL("dds_create_subscriber: %s\n", dds_strretcode(-subscriber));
dds_delete_qos (subQos);
/* A Reader is created on the Subscriber & Topic with a modified Qos. */
dds_qset_reliability (drQos, DDS_RELIABILITY_RELIABLE, DDS_SECS (10));
dds_qset_history (drQos, DDS_HISTORY_KEEP_ALL, 0);
dds_qset_resource_limits (drQos, maxSamples, DDS_LENGTH_UNLIMITED, DDS_LENGTH_UNLIMITED);
rd_listener = dds_create_listener(NULL);
dds_lset_data_available(rd_listener, data_available_handler);
/* A Read Condition is created which is triggered when data is available to read */
waitSet = dds_create_waitset (participant);
if (waitSet < 0)
DDS_FATAL("dds_create_waitset: %s\n", dds_strretcode(-waitSet));
status = dds_waitset_attach (waitSet, waitSet, waitSet);
if (status < 0)
DDS_FATAL("dds_waitset_attach: %s\n", dds_strretcode(-status));
imap = HandleMap__alloc ();
memset (data, 0, sizeof (data));
for (unsigned int i = 0; i < MAX_SAMPLES; i++)
{
samples[i] = &data[i];
}
*reader = dds_create_reader (subscriber, topic, drQos, pollingDelay < 0 ? rd_listener : NULL);
if (*reader < 0)
DDS_FATAL("dds_create_reader: %s\n", dds_strretcode(-*reader));
if (pollingDelay == 0)
{
status = dds_waitset_attach (waitSet, *reader, *reader);
if (status < 0)
DDS_FATAL("dds_waitset_attach: %s\n", dds_strretcode(-status));
}
dds_delete_qos (drQos);
dds_delete_listener(rd_listener);
return participant;
}
static void finalize_dds(dds_entity_t participant)
{
dds_return_t status;
for (unsigned int i = 0; i < MAX_SAMPLES; i++)
{
ThroughputModule_DataType_free (&data[i], DDS_FREE_CONTENTS);
}
status = dds_waitset_detach (waitSet, waitSet);
if (status < 0)
DDS_FATAL("dds_waitset_detach: %s\n", dds_strretcode(-status));
status = dds_delete (waitSet);
if (status < 0)
DDS_FATAL("dds_delete: %s\n", dds_strretcode(-status));
status = dds_delete (participant);
if (status < 0)
DDS_FATAL("dds_delete: %s\n", dds_strretcode(-status));
}