Real-time behavior

Fast RTPS can be configured to offer real-time features. These features will guarantee Fast RTPS responses within specified time constrains. To maintain this compromise Fast RTPS is able to have the following behavior:

  • Not allocate memory after the initialization of Fast RTPS entities.
  • Several methods are blocked for a maximum period of time.

This section explains how to configure Fast RTPS to achieve this behavior. For easier understanding it was divided in two subsections:

Tuning allocations

Some important non-deterministic operating system calls are the ones for allocating and deallocating memory. Most real-time systems have the need to operate in a way that all dynamic memory is allocated on the application startup, and avoid calls to memory management APIs on the main loop.

Fast-RTPS provides some configuration parameters to meet these requirements, allowing the items of internal data collections to be preallocated. In order to choose the correct values for these parameters, the user should be aware of the topology of the whole domain, so the number of participants and endpoints should be known when setting them.

Parameters on the participant

All the allocation related parameters on the participant are grouped into the rtps.allocation field of the ParticipantAttributes struct.

Limiting the number of discovered participants

Every participant in Fast-RTPS holds an internal collection of ParticipantProxyData objects with the information of the local and the remote participants. Field participants inside RTPSParticipantAllocationAttributes allows the configuration of the allocation behavior of that collection. The user can specify the initial number of elements preallocated, the maximum number of elements allowed, and the allocation increment. By default, a full dynamic behavior is used.

Limiting the number of discovered endpoints

Every ParticipantProxyData object holds internal collections with the ReaderProxyData and WriterProxyData objects with the information of the readers and writers of a participant. In a similar way to the participants field, RTPSParticipantAllocationAttributes has fields readers and writers to set the configuration of the allocation behavior of those collections. The user can specify the initial number of elements preallocated, the maximum number of elements allowed, and the allocation increment. By default, a full dynamic behavior is used.

Parameters on the publisher

Every publisher holds a collection with some information regarding the subscribers it has matched to. Field matched_subscriber_allocation inside PublisherAttributes allows the configuration of the allocation behavior of that collection. The user can specify the initial number of elements preallocated, the maximum number of elements allowed, and the allocation increment. By default, a full dynamic behavior is used.

Parameters on the subscriber

Every subscriber holds a collection with some information regarding the publishers it has matched to. Field matched_publisher_allocation inside SubscriberAttributes allows the configuration of the allocation behavior of that collection. The user can specify the initial number of elements preallocated, the maximum number of elements allowed, and the allocation increment. By default, a full dynamic behavior is used.

Full example

Given a system with the following topology:

Allocation tuning example topology
Participant P1 Participant P2 Participant P3
Topic 1 publisher Topic 1 subscriber Topic 2 subscriber
Topic 1 subscriber   Topic 2 publisher
Topic 1 subscriber   Topic 2 subscriber
  • All the subscribers match exactly with 1 publisher.
  • The publisher for topic 1 matches with 3 subscribers, and the publisher for topic 2 matches with 2 subscribers.
  • The maximum number of publishers per participant is 1, and the maximum number of subscribers per participant is 2.
  • The total number of participants is 3.

The following piece of code shows the set of parameters needed for the use case depicted in this example.

C++
// Before creating a participant:
// We know we have 3 participants on the domain
participant_attr.rtps.allocation.participants = eprosima::fastrtps::ResourceLimitedContainerConfig::fixed_size_configuration(3u);
// We know we have at most 2 readers on each participant
participant_attr.rtps.allocation.readers = eprosima::fastrtps::ResourceLimitedContainerConfig::fixed_size_configuration(2u);
// We know we have at most 1 writer on each participant
participant_attr.rtps.allocation.writers = eprosima::fastrtps::ResourceLimitedContainerConfig::fixed_size_configuration(1u);

// Before creating the publisher for topic 1:
// we know we will only have three matching subscribers
publisher_attr.matched_subscriber_allocation = eprosima::fastrtps::ResourceLimitedContainerConfig::fixed_size_configuration(3u);

// Before creating the publisher for topic 2:
// we know we will only have two matching subscribers
publisher_attr.matched_subscriber_allocation = eprosima::fastrtps::ResourceLimitedContainerConfig::fixed_size_configuration(2u);

// Before creating a subscriber:
// we know we will only have one matching publisher
subscriber_attr.matched_publisher_allocation = eprosima::fastrtps::ResourceLimitedContainerConfig::fixed_size_configuration(1u);
XML
<participant profile_name="participant_alloc_qos_example">
    <rtps>
        <allocation>
            <!-- We know we have 3 participants on the domain -->
            <total_participants>
                <initial>3</initial>
                <maximum>3</maximum>
                <increment>0</increment>
            </total_participants>
            <!-- We know we have at most 2 readers on each participant -->
            <total_readers>
                <initial>2</initial>
                <maximum>2</maximum>
                <increment>0</increment>
            </total_readers>
            <!-- We know we have at most 1 writer on each participant -->
            <total_writers>
                <initial>1</initial>
                <maximum>1</maximum>
                <increment>0</increment>
            </total_writers>
        </allocation>
    </rtps>
</participant>

<publisher profile_name="alloc_qos_example_pub_for_topic_1">
    <!-- we know we will have three matching subscribers -->
    <matchedSubscribersAllocation>
        <initial>3</initial>
        <maximum>3</maximum>
        <increment>0</increment>
    </matchedSubscribersAllocation>
</publisher>

<publisher profile_name="alloc_qos_example_pub_for_topic_2">
    <!-- we know we will have two matching subscribers -->
    <matchedSubscribersAllocation>
        <initial>2</initial>
        <maximum>2</maximum>
        <increment>0</increment>
    </matchedSubscribersAllocation>
</publisher>

<subscriber profile_name="alloc_qos_example_sub">
    <!-- we know we will only have one matching publisher -->
    <matchedPublishersAllocation>
        <initial>1</initial>
        <maximum>1</maximum>
        <increment>0</increment>
    </matchedPublishersAllocation>
</subscriber>

Non-blocking calls

Note: This feature is not fully supported on OSX. It doesn’t support necessary POSIX Real-time features. The feature is limited by the implementation of std::timed_mutex and std::condition_variable_any.

It is important that a method isn’t blocked for indeterminate time to achieve real-time. A method must only be blocked for a maximum period of time. In Fast-RTPS API there are several methods that permit to set this. But first Fast-RTPS should be configured with the CMake option -DSTRICT_REALTIME=ON. The list of these functions is displayed in the table below.

Fast RTPS non-blocking API
Method Description
Publisher::write() These methods are blocked for a period of time. ReliabilityQosPolicy.max_blocking_time on PublisherAttributes defines this period of time. Default value is 100 milliseconds.
Subscriber::takeNextData() This methods is blocked for a period of time. ReliabilityQosPolicy.max_blocking_time on SubscriberAttributes defines this period of time. Default value is 100 milliseconds.
Subscriber::readNextData() This method is blocked for a period of time. ReliabilityQosPolicy.max_blocking_time on SubscriberAttributes defines this period of time. Default value is 100 milliseconds.
Subscriber::wait_for_unread_samples() Accepts an argument specifying how long the method can be blocked.