2019-01-18 14:10:19 +01:00
|
|
|
#include "dds/dds.h"
|
2018-08-07 17:30:17 +02:00
|
|
|
#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);
|
|
|
|
|
2019-01-21 17:19:11 +01:00
|
|
|
static void sigint (int sig)
|
2018-08-07 17:30:17 +02:00
|
|
|
{
|
|
|
|
(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;
|
2019-01-18 14:10:19 +01:00
|
|
|
dds_return_t rc;
|
2018-08-07 17:30:17 +02:00
|
|
|
ThroughputModule_DataType sample;
|
|
|
|
|
2019-03-08 15:13:09 +01:00
|
|
|
#if !defined(_WIN32)
|
2019-01-21 17:16:10 +01:00
|
|
|
setvbuf (stdout, NULL, _IOLBF, 0);
|
2019-03-08 15:13:09 +01:00
|
|
|
#endif
|
2019-01-21 17:16:10 +01:00
|
|
|
|
2018-08-07 17:30:17 +02:00
|
|
|
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");
|
2019-01-18 14:10:19 +01:00
|
|
|
rc = dds_delete (participant);
|
|
|
|
if (rc < 0)
|
|
|
|
DDS_FATAL("dds_delete: %s\n", dds_strretcode(-rc));
|
2018-08-07 17:30:17 +02:00
|
|
|
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';
|
|
|
|
}
|
|
|
|
|
2018-10-14 14:01:31 +08:00
|
|
|
/* Register handler for Ctrl-C */
|
2019-01-21 17:19:11 +01:00
|
|
|
signal (SIGINT, sigint);
|
2018-10-14 14:01:31 +08:00
|
|
|
|
2018-08-07 17:30:17 +02:00
|
|
|
/* 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: %u bytes burstInterval: %u ms burstSize: %u timeOut: %u seconds partitionName: %s\n",
|
|
|
|
*payloadSize, *burstInterval, *burstSize, *timeOut, *partitionName);
|
|
|
|
|
|
|
|
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);
|
2019-01-18 14:10:19 +01:00
|
|
|
if (participant < 0)
|
|
|
|
DDS_FATAL("dds_create_participant: %s\n", dds_strretcode(-participant));
|
2018-08-07 17:30:17 +02:00
|
|
|
|
|
|
|
/* A topic is created for our sample type on the domain participant. */
|
|
|
|
topic = dds_create_topic (participant, &ThroughputModule_DataType_desc, "Throughput", NULL, NULL);
|
2019-01-18 14:10:19 +01:00
|
|
|
if (topic < 0)
|
|
|
|
DDS_FATAL("dds_create_topic: %s\n", dds_strretcode(-topic));
|
2018-08-07 17:30:17 +02:00
|
|
|
|
|
|
|
/* A publisher is created on the domain participant. */
|
2018-11-09 11:16:24 +01:00
|
|
|
pubQos = dds_create_qos ();
|
2018-08-07 17:30:17 +02:00
|
|
|
pubParts[0] = partitionName;
|
|
|
|
dds_qset_partition (pubQos, 1, pubParts);
|
|
|
|
publisher = dds_create_publisher (participant, pubQos, NULL);
|
2019-01-18 14:10:19 +01:00
|
|
|
if (publisher < 0)
|
|
|
|
DDS_FATAL("dds_create_publisher: %s\n", dds_strretcode(-publisher));
|
2018-11-09 11:16:24 +01:00
|
|
|
dds_delete_qos (pubQos);
|
2018-08-07 17:30:17 +02:00
|
|
|
|
|
|
|
/* A DataWriter is created on the publisher. */
|
2018-11-09 11:16:24 +01:00
|
|
|
dwQos = dds_create_qos ();
|
2018-08-07 17:30:17 +02:00
|
|
|
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);
|
2019-01-18 14:10:19 +01:00
|
|
|
if (*writer < 0)
|
|
|
|
DDS_FATAL("dds_create_writer: %s\n", dds_strretcode(-*writer));
|
2018-11-09 11:16:24 +01:00
|
|
|
dds_delete_qos (dwQos);
|
2018-08-07 17:30:17 +02:00
|
|
|
|
|
|
|
/* 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");
|
|
|
|
|
2019-01-18 14:10:19 +01:00
|
|
|
dds_return_t rc;
|
2018-08-07 17:30:17 +02:00
|
|
|
dds_entity_t waitset;
|
|
|
|
|
2019-01-18 14:10:19 +01:00
|
|
|
rc = dds_set_status_mask(writer, DDS_PUBLICATION_MATCHED_STATUS);
|
|
|
|
if (rc < 0)
|
|
|
|
DDS_FATAL("dds_set_status_mask: %s\n", dds_strretcode(-rc));
|
2018-08-07 17:30:17 +02:00
|
|
|
|
|
|
|
waitset = dds_create_waitset(participant);
|
2019-01-18 14:10:19 +01:00
|
|
|
if (waitset < 0)
|
|
|
|
DDS_FATAL("dds_create_waitset: %s\n", dds_strretcode(-waitset));
|
2018-08-07 17:30:17 +02:00
|
|
|
|
2019-01-18 14:10:19 +01:00
|
|
|
rc = dds_waitset_attach(waitset, writer, (dds_attach_t)NULL);
|
|
|
|
if (rc < 0)
|
|
|
|
DDS_FATAL("dds_waitset_attach: %s\n", dds_strretcode(-rc));
|
2018-08-07 17:30:17 +02:00
|
|
|
|
2019-01-18 14:10:19 +01:00
|
|
|
rc = dds_waitset_wait(waitset, NULL, 0, DDS_SECS(30));
|
|
|
|
if (rc < 0)
|
|
|
|
DDS_FATAL("dds_waitset_wait: %s\n", dds_strretcode(-rc));
|
2018-08-07 17:30:17 +02:00
|
|
|
|
2019-01-18 14:10:19 +01:00
|
|
|
return rc;
|
2018-08-07 17:30:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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");
|
|
|
|
|
|
|
|
while (!done && !timedOut)
|
|
|
|
{
|
|
|
|
/* Write data until burst size has been reached */
|
|
|
|
|
|
|
|
if (burstCount < burstSize)
|
|
|
|
{
|
|
|
|
status = dds_write (writer, sample);
|
|
|
|
if (dds_err_nr(status) == DDS_RETCODE_TIMEOUT)
|
|
|
|
{
|
|
|
|
timedOut = true;
|
|
|
|
}
|
2019-01-18 14:10:19 +01:00
|
|
|
else if (status < 0)
|
|
|
|
{
|
|
|
|
DDS_FATAL("dds_write: %s\n", dds_strretcode(-status));
|
|
|
|
}
|
2018-08-07 17:30:17 +02:00
|
|
|
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);
|
|
|
|
|
|
|
|
if (done)
|
|
|
|
{
|
|
|
|
printf ("=== [Publisher] Terminated, %llu samples written.\n", (unsigned long long) sample->count);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
printf ("=== [Publisher] Timed out, %llu samples written.\n", (unsigned long long) sample->count);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void finalize_dds(dds_entity_t participant, dds_entity_t writer, ThroughputModule_DataType sample)
|
|
|
|
{
|
|
|
|
dds_return_t status = dds_dispose (writer, &sample);
|
2019-01-18 14:10:19 +01:00
|
|
|
if (dds_err_nr (status) != DDS_RETCODE_TIMEOUT && status < 0)
|
|
|
|
DDS_FATAL("dds_dispose: %s\n", dds_strretcode(-status));
|
2018-08-07 17:30:17 +02:00
|
|
|
|
|
|
|
dds_free (sample.payload._buffer);
|
|
|
|
status = dds_delete (participant);
|
2019-01-18 14:10:19 +01:00
|
|
|
if (status < 0)
|
|
|
|
DDS_FATAL("dds_delete: %s\n", dds_strretcode(-status));
|
2018-08-07 17:30:17 +02:00
|
|
|
}
|