lib: notification iterator: transfer a batch of notifications
This patch makes each notification iterator's "next" operation return a
batch of notifications intead of a single one. This has a positive
effect on performance as we're decreasing the number of executed
instructions because there are fewer function calls per notification.
The batch size is arbitrarily set to 15 here as a value between 10 and
50 experimentally showed to be beneficial, and there's usually more than
one active stream on a typical graph configuration. As the batch size
increases, the performance eventually degrades, as I suspect that
(pooled) notification objects are constantly getting into and out of CPU
cache. The goal of hiding the batch size in the library's implementation
is to eventually determine a value at run time depending on the
situation, and even change it when needed between consuming sinks.
Each notification iterator contains a fixed-sized array of notification
pointers. This array is allocated when the iterator is created and freed
when it is destroyed. For convenience, I'm adding this typedef:
typedef struct bt_notification **bt_notification_array;
Consumer side
=============
The consuming side API is now:
enum bt_notification_iterator_status
bt_private_connection_notification_iterator_next(
struct bt_notification_iterator *iterator,
bt_notification_array *notifs, uint64_t *count);
enum bt_notification_iterator_status
bt_output_port_notification_iterator_next(
struct bt_notification_iterator *iterator,
bt_notification_array *notifs, uint64_t *count);
In English: the function sets `notifs` to the address of a notification
array containing `*count` notifications when the returned status is
`BT_NOTIFICATION_ITERATOR_STATUS_OK`. In this case, the caller is
responsible for putting each notification in the array (the array's
content is owned by the caller, but not the array itself), as the
functions above do not put what's already in the iterator's array before
filling it. If the status is not `BT_NOTIFICATION_ITERATOR_STATUS_OK`,
then the function does not set `*notifs` and `*count`.
Because the `utils.flt.muxer` component class kept each upstream
notification iterator's current notification, it now keeps a queue of
notifications, and the upstream iterator is now considered invalid if
its notification queue is empty.
If less than `*count` notifications are required, the caller can either:
* Discard (put) unneeded notifications: they are lost forever.
* Keep a queue (or other data structure) of notifications by keeping the
references. The caller must NOT keep the array itself in this case,
but each contained notification object, copying the pointer values to
its territory.
Producer side
=============
The "next" method signature is now:
enum bt_notification_iterator_status next_method(
struct bt_private_connection_private_notification_iterator *notif_iter,
bt_notification_array notifs, uint64_t capacity,
uint64_t *count);
The callback must either:
* Fill `notifs` with up to `capacity` notifications (notification's
ownership is transfered to the array), set `*count` to how many
notifications were transfered (at least one), and return
`BT_NOTIFICATION_ITERATOR_STATUS_OK`.
`capacity` is always greater than zero.
* Return something else than `BT_NOTIFICATION_ITERATOR_STATUS_OK`,
not touching `notifs` and `count`.
IMPORTANT: The callback must NOT transfer one or more notifications to
`notifs` and return something else than
`BT_NOTIFICATION_ITERATOR_STATUS_OK`.
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
27 files changed:
This page took 0.028323 seconds and 4 git commands to generate.