Migrating to version 3

Version 3 makes a number of breaking changes, for the purpose of keeping the number of constructor arguments under control and making future extension more manageable. Almost all code will need to be updated, but the updates will in most cases be minor.

To allow for code that wishes to support both version 3 and older versions, C++ macros are defined to allow the version number to be interrogated at compile time. Thus, version 3 can be detected as

#if defined(SPEAD2_MAJOR) && SPEAD2_MAJOR >= 3
// Version 3 or later
#else
// Older
#endif

Note that version 3.0.0b1 did not define these macros, but also did not include the breaking changes.

SPEAD2_MAJOR

Major version of spead2 e.g., 3 for version 3.4.6.

SPEAD2_MINOR

Minor version of spead2 e.g., 4 for version 3.4.6.

SPEAD2_PATCH

Patch level of spead2 e.g., 6 for version 3.4.6.

SPEAD2_VERSION

Full spead2 version number, as a string constant.

In Python, one can get the full version string from spead2.__version__. Use the classes in packaging.version to analyse it.

Receive stream configuration

Prior to version 3, some parameters to configure a stream were passed directly to the constructor (e.g., the maximum number of partial heaps), while others were set by methods after construction (such as the memory allocator). In version 3, all these parameters are set at construction time, and they are held in helper classes spead2.recv.StreamConfig and spead2.recv.RingStreamConfig (spead2::recv::stream_config and spead2::recv::ring_stream_config for C++). Code will need to be modified to construct these helper objects.

Similarly, for ibverbs there is now a spread.recv.UdpIbvConfig that is used to configure the reader. The old forms of spead.recv.Stream.add_udp_ibv_reader() are still present but are deprecated.

In version 2 it was also possible (although not recommended) to change parameters like the memory allocator after readers had already been placed. For efficiency reasons this is no longer supported in version 3.

Send stream configuration

The changes for sending are more minor: the constructor for the Python class spead2.send.StreamConfig now only takes keyword arguments, and the C++ equivalent spead2::send::stream_config takes no constructor arguments. To make it convenient to construct temporaries, the setter methods return the object, allowing configurations to be constructed in a “fluent” style e.g.:

spead2::send::stream_config().set_max_packet_size(9172).set_rate(1e6)

For ibverbs streams the changes are more significant. There is now a spead2.send.UdpIbvConfig class that works similarly to spead2.send.StreamConfig, but configures properties specific to the ibverbs stream. The old constructor is still available (but deprecated); however, the constants UdpIbvStream.DEFAULT_BUFFER_SIZE and UdpIbvStream.DEFAULT_MAX_POLL have moved to the UdpIbvConfig class.

Substreams

A new feature is the ability to create a send stream with multiple destinations and select the destination on a per-heap basis (see Substreams for more information). Supporting this cleanly required a number of changes:

  • The spead2.send.InprocStream.queue attribute has been replaced with queues. Similarly, the C++ spead2::send::inproc_stream::get_queue() has been replaced by get_queues(). The originals are still present but deprecated, and raise a RuntimeError if the stream was constructed with multiple queues.

  • The constructors for most send stream types now accept a list of endpoints (or queues) rather than a single endpoint (queue). The old constructors are still supported for backwards compatibility, but are deprecated.

  • The spead2_send and spead2_send.py example programs now take the destination in the form host:port instead of host port, and support multiple destinations.

Out-of-order packets

In prior versions of spead2, the packets forming a single heap could be received in any order. Starting with version 3, the default is to assume that packets arrive in order. Refer to Packet ordering for more details.

Loop argument to asyncio functions

The Python asyncio-based classes and functions no longer take a loop argument. As of Python 3.6, asyncio.get_event_loop() returns the executing event loop, so there is no need to pass the loop explicitly.

Command-line arguments in tools

The command-line handling in spead2_send, spead2_recv and spead2_bench has been overhauled and made more consistent. For example, spead_bench now supports the --ttl option, and --send-ibv is now an argument-less flag with the interface address given by --send-bind (and similarly for receive). See the help for each command for details of the current options.

Removal of deprecated functionality

The following functions were deprecated in version 2 and have been removed in version 3:

  • C++ stream constructors that specified a socket but not an io_service (they could not be supported with Boost 1.70 onwards).

  • Stream constructors that took both an existing (but unconnected) socket and a buffer size or a port to bind to. The caller should instead bind the socket (if receiving) and set any desired buffer size socket option.

Queue depth for sending with ibverbs

When using ibverbs to send data, heaps were previously considered complete once the packets were submitted to the hardware. They’re now only considered complete once the hardware has indicated completion, which allows for errors to be reported. While there are no breaking API changes, if the heaps are very small it may be necessary to increase max_heaps in StreamConfig so that enough heaps can be in flight to fully utilise the buffer.