EM-ODP  3.5.0
Event Machine on ODP
EM-ODP Documentation

General

Event Machine (EM) is a framework and an architectural abstraction of an event driven, multicore optimized, processing concept originally developed for the networking data plane. It offers an easy programming concept for scalable and dynamically load balanced multicore applications with a very low overhead run-to-completion principle.

Events, queues and execution objects (EO) along with the scheduler and the dispatcher form the main elements of the EM concept. An event is an application specific piece of data (like a message or a network packet) describing work, something to do. All processing in EM must be triggered by an event. Events are sent to asynchronous application specific EM queues. A dispatcher loop is run by a single thread on each core in the EM instance ("core" is used here to refer to a core or one HW thread on multi-threaded cores). The dispatcher on each core interfaces with the scheduler and asks for an event to process. The scheduler then evaluates the state of all the EM queues and gives the highest priority event available to the requesting dispatcher. The dispatcher looks up which EO owns the queue that the event came from and finally calls the EO's registered receive function to deliver the event for processing. When the event has been handled and the EO's receive function returns, it's again time for the dispatcher on that core to request another event from the scheduler and deliver it to the corresponding EO. The aforedescribed scenario happens in parallel on all cores running the EM instance. Events originating from a particular queue might thus be given for processing on any core, decided separately for each event by the scheduler as the dispatcher on a core requests more work - this is per-event dynamic load-balancing. EM contains mechanisms to ensure atomicity and event (re-)ordering.

The EM concept has been designed to be highly efficient, operating in a run-to-completion manner on each participating core with neither context switching nor pre-emption slowing down the event processing loops. EM can run on bare metal for best performance or under an operating system with special arrangements (e.g. one thread per core with thread affinity).

The concept and the API are intended to allow fairly easy implementations on general purpose or networking oriented multicore packet processing SoCs, which typically also contain accelerators for packet processing needs. Efficient integration with modern HW accelerators has been a major driver of the EM concept.

One general principle of the EM API is that the function calls are mostly multicore safe. The application still needs to consider parallel processing data hazards and race conditions unless explicitly documented in the API for the function call in question. For example, one core might ask for a queue context while another core changes it, thus the returned context may be invalid (valid data, but either the old or the new value is returned). Thus modifications of shared state or data should be protected by an atomic context (if load balancing is used) or otherwise synchronized by the application itself. One simple way to achieve atomic processing is to use an atomic queue to serialize the EO's incoming events and perform management operations in the EO's receive function. This serialization limits the throughput of the atomic queue in question to the equivalent throughput of a single core, but since normally EM applications use multiple queues, all cores should get events to process and the total throughput will be relative to the number of cores running the EM instance.

EM_64_BIT or EM_32_BIT (needs to be defined by the build) defines whether (most of) the types used in the API are 32 or 64 bits wide. NOTE, that this is a major decision, since it may limit value passing between different systems using the defined types directly. Using 64-bits may allow for a more efficient underlying implementation, as e.g. more data can be coded in 64-bit identifiers.

Principles

  • This API attempts to guide towards a portable application architecture, but is not defined for portability by re-compilation. Many things are system specific giving more possibilities for efficient use of HW resources.
  • EM does not define event content (one exception, see em_alloc()). This is a choice made for performance reasons, since most HW devices use proprietary descriptors. This API enables the usage of those directly.
  • EM does not define a detailed queue scheduling discipline or an API to set it up with (or actually anything to configure a system). The priority value in this API is a (mapped) system specific QoS class label only.
  • In general, EM does not implement a full SW platform or a middleware solution, it implements a subset - a driver level part. For best performance it can be used directly from the applications.

Inter-system communication

EM does not define how to communicate with another EM instance or another system transparently. However, this is a typical need and the current API does have ways to achieve almost transparent communication between systems ("event chaining"): Since the queue identifier is a system specific value, it is easy to encode extra information into it in the EM implementation. For instance it could be split into two parts, where the lower part is a local queue id or index and the higher part, if not zero, points to another system. The implementation of em_send() can detect a non-local queue and forward events to the target using any transport mechanism available and once at the target instance the lower part is used to map to a local queue. For the application nothing changes. The problem is the lack of shared memory between those systems. The given event can be fully copied, but it should not have any references to sender's local memory. Thus it is not fully transparent if the event contains references to local memory (e.g. pointers).

Files

Generic

  • event_machine.h
    • Event Machine API The application should include this file only.

Files included by event_machine.h:

HW Specific

Helper