FIFO Buffering

A Fifo object inserts an elastic buffer between an upstream stream stage and a downstream stream stage. In Rogue terms, it sits between a Master and one or more downstream Slave objects and decouples their timing.

You typically add a Fifo for one of three reasons. The first is to absorb bursts or flow-control events so a fast producer does not immediately stall a slower consumer. The second is to create a deliberate drop point when the downstream path cannot keep up indefinitely. The third is to add a tap path for monitoring or logging, where the monitoring branch should not interfere with the primary processing path.

At a high level, Fifo behavior is controlled by three constructor parameters:

  • maxDepth controls how many Frame objects may be queued before new arrivals are dropped.

  • trimSize controls how much payload is copied when copy mode is enabled.

  • noCopy selects whether the original Frame is queued or whether a new copied Frame is created.

Constructor

  • Python: ris.Fifo(maxDepth, trimSize, noCopy)

  • C++: ris::Fifo::create(maxDepth, trimSize, noCopy)

Copy And Queue Behavior

The interaction between trimSize and noCopy determines what the Fifo actually stores.

  • noCopy=True and trimSize=0: the original incoming Frame is queued.

  • noCopy=False and trimSize=0: a full copy of the incoming Frame is queued.

  • noCopy=False and trimSize!=0: a copied Frame containing only up to trimSize bytes of payload is queued.

maxDepth determines whether the queue is bounded. When maxDepth=0, the queue depth is effectively unlimited and frames are never dropped due to queue depth. When maxDepth!=0, incoming Frame objects are dropped once the queue reaches that depth. Use dropCnt() to inspect the number of dropped Frame objects and clearCnt() to reset the counter.

Python In-Line Example

The simplest use of a Fifo is to place it directly in-line between a source and a destination. This is the normal choice when the goal is to absorb bursts without changing the payload.

import rogue.interfaces.stream as ris

# Data source
src = MyCustomMaster()

# Data destination
dst = MyCustomSlave()

# Create a Fifo with maxDepth=100, trimSize=0, noCopy=True
fifo = ris.Fifo(100, 0, True)

# Connect the Fifo between the source and the destination
src >> fifo >> dst

In this configuration the Fifo queues the original incoming Frame objects, up to a depth of 100, and begins dropping newly arrived Frame objects once that depth is reached.

C++ In-Line Example

#include "rogue/Helpers.h"
#include "rogue/interfaces/stream/Fifo.h"
#include "MyCustomMaster.h"
#include "MyCustomSlave.h"

int main() {
   // Data source
   auto src = MyCustomMaster::create();

   // Data destination
   auto dst = MyCustomSlave::create();

   // Create a Fifo with maxDepth=100, trimSize=0, noCopy=true
   auto fifo = rogue::interfaces::stream::Fifo::create(100, 0, true);

   // Connect the Fifo between the source and the destination
   rogueStreamConnect(src, fifo);
   rogueStreamConnect(fifo, dst);
   return 0;
}

Python Tap Example

Another common pattern is to use a copied Fifo as a secondary monitoring branch. In that case the primary path continues unchanged, while the tap path receives copied and optionally trimmed Frame objects.

import rogue.interfaces.stream as ris

# Data source
src = MyCustomMaster()

# Main data destination
dst = MyCustomSlave()

# Additional monitor
mon = MyCustomMonitor()

# Primary path
src >> dst

# Tap path: copy at most 20 bytes from each Frame and queue up to 150 Frames
fifo = ris.Fifo(150, 20, False)
src >> fifo >> mon

This is useful when the monitor is slower than the main path or only needs a small prefix of each payload. Because the monitor branch gets copies rather than the original Frame objects, it does not interfere with the primary path’s ownership or zero-copy behavior.

C++ Tap Example

#include "rogue/Helpers.h"
#include "rogue/interfaces/stream/Fifo.h"
#include "MyCustomMaster.h"
#include "MyCustomSlave.h"
#include "MyCustomMonitor.h"

int main() {
   // Data source
   auto src = MyCustomMaster::create();

   // Main data destination
   auto dst = MyCustomSlave::create();

   // Additional monitor
   auto mon = MyCustomMonitor::create();

   // Primary path
   rogueStreamConnect(src, dst);

   // Tap path: copy at most 20 bytes from each Frame and queue up to 150 Frames
   auto fifo = rogue::interfaces::stream::Fifo::create(150, 20, false);
   rogueStreamConnect(src, fifo);
   rogueStreamConnect(fifo, mon);
   return 0;
}

Logging

Fifo uses Rogue C++ logging with the static logger name pyrogue.stream.Fifo.

Enable that logger before constructing the object if you want constructor-time and runtime messages from the Fifo implementation:

import rogue
import rogue.interfaces.stream as ris

rogue.Logging.setFilter('pyrogue.stream.Fifo', rogue.Logging.Debug)
fifo = ris.Fifo(256, 0, True)

Fifo does not expose a separate runtime setDebug(...) helper. If you need byte-dump inspection, attach a debug Slave before or after the Fifo and use setDebug(maxBytes, name) on that monitor.

What To Explore Next

API Reference