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:
maxDepthcontrols how manyFrameobjects may be queued before new arrivals are dropped.trimSizecontrols how much payload is copied when copy mode is enabled.noCopyselects whether the originalFrameis queued or whether a new copiedFrameis 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=TrueandtrimSize=0: the original incomingFrameis queued.noCopy=FalseandtrimSize=0: a full copy of the incomingFrameis queued.noCopy=FalseandtrimSize!=0: a copiedFramecontaining only up totrimSizebytes 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
Connection topology rules: Connecting Streams
Filterusage: Channel FilteringRateDropusage: Rate Limiting With RateDropReceive-side monitoring patterns: Receiving Frames