6.4. Shared Memory Transport

The shared memory (SHM) transport enables fast communications between entities running in the same processing unit/machine, relying on the shared memory mechanisms provided by the host operating system.

SHM transport provides better performance than other network transports like UDP / TCP, even when these transports use loopback interface. This is mainly due to the following reasons:

  • Large message support: Network protocols need to fragment data in order to comply with the specific protocol and network stacks requirements, increasing communication overhead. SHM transport allows the copy of full messages where the only size limit is the machine’s memory capacity.

  • Reduce the number of memory copies: When sending the same message to different endpoints, SHM transport can directly share the same memory buffer with all the destination endpoints. Other protocols require to perform one copy of the message per endpoint.

  • Less operating system overhead: Once initial setup is completed, shared memory transfers require much less system calls than the other protocols. Therefore, there is a performance/time consume gain by using SHM.

6.4.1. Definition of Concepts

This section describes basic concepts that will help understanding how the Shared Memory Transport works in order to deliver the data messages to the appropriate DomainParticipant. The purpose is not to be a exhaustive reference of the implementation, but to be a comprehensive explanation of each concept, so that users can configure the transport to their needs.

Many of the descriptions in this section will be made following the example use case depicted in the following figure, where Participant 1 sends a data message to Participant 2. Please, refer to the figure when following the definitions.

../../../_images/shm_comm_sequence_diagram.svg

Sequence diagram for Shared Memory Transport

6.4.1.1. Segment

A Segment is a block of shared memory that can be accessed from different processes. Every DomainParticipant that has been configured with Shared Memory Transport creates a segment of shared memory. The DomainParticipant writes to this segment any data it needs to deliver to other DomainParticipants, and the remote DomainParticipants are able to read it directly using the shared memory mechanisms.

Every segment has a segmentId, a 16 character UUID that uniquely identifies each shared memory segment. These segmentIds are used to identify and access the segment of each DomainParticipant.

6.4.1.2. Segment Buffer

A buffer allocated in the shared memory Segment. It works as a container for a DDS message that is placed in the Segment. In other words, each message that the DomainParticipant writes on the Segment will be placed in a different buffer.

6.4.1.3. Buffer Descriptor

It acts as a pointer to a specific Segment Buffer in a specific Segment. It contains the segmentId and the offset of the Segment Buffer from the base of the Segment. When communicating a message to other DomainParticipants, Shared Memory Transport only distributes the Buffer Descriptor, avoiding the copy of the message from a DomainParticipant to another. With this descriptor, the receiving DomainParticipant can access the message written in the buffer, as is uniquely identifies the Segment (through the segmentId) and the Segment Buffer (through its offset).

6.4.1.4. Port

Represents a channel to communicate Buffer Descriptors. It is implemented as a ring-buffer in shared memory, so that any DomainParticipant can potentially read or write information on it. Each port has a unique identifier, a 32 bit number that can be used to refer to the port. Every DomainParticipant that has been configured with Shared Memory Transport creates a port to receive Buffer Descriptors. The identifier of this port is shared during the Discovery, so that remote peers know which port to use when they want to communicate with each DomainParticipant.

DomainParticipants create a listener to their receiving port, so that they can be notified when a new Buffer Descriptor is pushed to the port.

6.4.1.5. Port Health Check

Every time a DomainParticipant opens a Port (for reading or writing), a health check is performed to assess its correctness. The reason is that if one of the processes involved crashes while using a Port, that port can be left inoperative. If the attached listeners do not respond in a given timeout, the Port is considered damaged, and it is destroyed and created again.

6.4.2. SharedMemTransportDescriptor

In addition to the data members defined in the TransportDescriptorInterface, the TransportDescriptor for Shared Memory defines the following ones:

Member

Data type

Accessor / Mutator

Description

segment_size_

uint32_t

segment_size()

The size of the shared memory segment (in octets).

port_queue_capacity_

uint32_t

port_queue_capacity()

The size of the listening port (in messages).

healthy_check_timeout_ms_

uint32_t

healthy_check_timeout_ms()

Timeout for the health check of ports (in milliseconds).

rtps_dump_file_

string

rtps_dump_file()

Full path of the protocol dump_file.

If rtps_dump_file_ is not empty, all the shared memory traffic on the DomainParticipant (sent and received) is traced to a file. The output file format is tcpdump hexadecimal text, and can be processed with protocol analyzer applications such as Wireshark.

Note

The kind value for a SharedMemTransportDescriptor is given by the value eprosima::fastrtps::rtps::LOCATOR_KIND_SHM

6.4.3. Enabling Shared Memory Transport

SHM transport is not enabled by default. To enable SHM transport in a DomainParticipant, you need to create an instance of SharedMemTransportDescriptor and add it to the user transport list of the DomainParticipant. The examples below show this procedure in both C++ code and XML file.

C++

DomainParticipantQos qos;

// Create a descriptor for the new transport.
std::shared_ptr<SharedMemTransportDescriptor> shm_transport = std::make_shared<SharedMemTransportDescriptor>();

// Link the Transport Layer to the Participant.
qos.transport().user_transports.push_back(shm_transport);

XML

<?xml version="1.0" encoding="UTF-8" ?>
<profiles xmlns="http://www.eprosima.com/XMLSchemas/fastRTPS_Profiles">
    <transport_descriptors>
        <!-- Create a descriptor for the new transport -->
        <transport_descriptor>
            <transport_id>shm_transport</transport_id>
            <type>SHM</type>
        </transport_descriptor>
    </transport_descriptors>

    <participant profile_name="SHMParticipant">
        <rtps>
            <!-- Link the Transport Layer to the Participant -->
            <userTransports>
                <transport_id>shm_transport</transport_id>
            </userTransports>
        </rtps>
    </participant>
</profiles>

6.4.4. HelloWorldExampleSharedMem

A Shared Memory version of helloworld example can be found in the examples/C++/DDS/HelloWorldExampleSharedMem folder. It shows a publisher and a subscriber that communicate through Shared Memory.