Worked examples — Dataflow architectures
This page is the "hands dirty" companion to Dataflow architectures. The parent note built the rules: a program is a directed graph, edges carry tokens (packets holding a value, and in the dynamic case a tag), and a node fires the instant all its input edges hold matching tokens. Here we run those rules by hand on every kind of situation a dataflow graph can meet — so that when an exam or a real machine throws one at you, you have already seen its twin.
Before we start, one promise from the contract: nothing is used before it is drawn. If a word like token, tag, fire, epoch appears, look at the picture beside it — the picture is the definition.
The scenario matrix
Every dataflow question is one of a small number of shapes. The table below is the whole zoo. Each worked example below is stamped with the cell it lives in, and together they cover every row.
| # | Case class | What is unusual about it | Example that covers it |
|---|---|---|---|
| A | Pure independent ops (the "free parallelism" case) | Two nodes share no edge → fire together | Ex 1 |
| B | Chained dependency (forced sequential order) | Output of one is input of next → order forced by data, not by a PC | Ex 2 |
| C | Diamond (fan-out then fan-in) | One value feeds two nodes, results re-merge | Ex 3 |
| D | Degenerate: a constant / zero-input node | A node with no data edges — when does it fire? | Ex 4 |
| E | Degenerate: identity / one-input op | A node needing only one token | Ex 4 |
| F | Static conflict (two tokens want the same edge) | Edge capacity = 1 token → the machine stalls | Ex 5 |
| G | Dynamic loop with tags (overlapping iterations) | Iterations run concurrently, tags keep them apart | Ex 6 |
| H | Tag mismatch / the "garbage" limiting case | What happens if tags are dropped | Ex 7 |
| I | Real-world word problem | Map an everyday process onto the firing rule | Ex 8 |
| J | Exam-style twist (throughput / speed-up numbers) | Count firing "waves", compute parallel speed-up | Ex 9 |
Example 1 — Case A: pure independent operations
Forecast: guess now — does the node have to wait for the node? Write down "yes" or "no" before reading on.

- Wave 0 — tokens arrive. Tokens land on the two input edges of the node; land on the input edges of the node. Why this step? The firing rule only ever looks at input edges, so first we must place the starting data.
- Wave 1 — check every node. The node sees both its inputs → it fires, emitting . The node also sees both its inputs → it fires in the same wave, emitting . Why this step? Their firing rules are satisfied independently. Look at the figure: the two nodes are the red islands with no arrow bridging them — no shared edge means no dependency means no waiting.
Verify: . Total waves after data arrival . A program-counter machine would need 2 sequential steps (one add, one subtract). Speed-up — exactly the "parallelism for free" the parent note promised. This is the natural limit of Instruction-Level Parallelism: independence is visible as a missing edge.
Example 2 — Case B: a forced chain
Forecast: independent ops took 1 wave. Do you think a chain of two adds also takes 1? Guess.
- Wave 0. Tokens arrive on the first (""). Token arrives on one input of the second (""). The other input of is the edge coming from — it is empty. Why this step? We must notice is not yet fireable: one of its edges has no token.
- Wave 1. has both inputs → fires → emits token onto the edge feeding . still cannot fire this wave, because it only just now received that token — checking happens per wave. Why this step? The data dependency (the edge from to ) is the only thing forcing order here. There is no program counter saying "do the inner add first" — the empty edge says it.
- Wave 2. now sees (from ) and () → fires → .
Verify: . ✓ Waves . Contrast Ex 1: same count of operations (2 adds) but here they cannot overlap. The lesson: dataflow removes artificial order, never necessary order.
Example 3 — Case C: the diamond (fan-out + fan-in)
Forecast: is needed by both the and the . Does that create a bottleneck? Guess yes/no.

- Wave 0. Tokens arrive. Crucially, is copied onto two edges — one into , one into . Why this step? Fan-out means one producer feeds many consumers; in dataflow a value that two nodes need becomes two tokens (a copy per edge). It does not cause waiting.
- Wave 1. has → fires → . Simultaneously has → fires → . Both fire together (Case A behaviour inside the diamond's left half). Why this step? Sharing does not chain them — each has its own copy, so their firing rules are independent.
- Wave 2. The node now sees and → fires → . Why this step? This is the fan-in: two edges merge into one node. Order is forced (Case B) because 's inputs did not exist before wave 1.
Verify: . ✓ Waves . A PC machine needs 3 steps (add, subtract, multiply). Speed-up .
Example 4 — Cases D & E: degenerate nodes (constant and identity)
Forecast: a node with no input edges — when is its firing rule satisfied? Guess before reading.
- Case D — the constant node. A node with zero input edges has an empty set of requirements. "All input edges hold a token" is vacuously true for the empty set, so a constant node is always ready and emits its value (here , and separately ) at wave 0. Why this step? The firing rule says "all inputs present". With no inputs, there is nothing to wait for — the same way "every unicorn in this room is pink" is true when there are no unicorns.
- Case E — the one-input identity-ish node. The node still needs two tokens ( and the constant ). It is not a one-input node. But suppose we had a node like
neg(a)= : that fires as soon as its single edge holds a token. The general rule scales: fire when the (however many) input edges are all full. Why this step? Beginners assume every node needs two operands. The rule is "all its inputs", whatever that number is — including 0 (constant) and 1 (unary). - Wave 1. has and → fires → . The has this ? No — not yet (it arrived this wave). Wave 2: has and → fires → .
Verify: . ✓ The constants never stalled anything; the only forced order was the chain (Case B again).
Example 5 — Case F: static dataflow token collision (the stall)
Forecast: guess — does the machine silently overwrite, or stall?

- Wave 1. Iteration 1's token (value ) sits on edge , waiting to be consumed by the downstream node. Why this step? We must fix the state: is occupied, capacity is 1.
- Wave 2. Iteration 2 finishes early and wants to emit onto . But already holds . In static dataflow, an edge may hold at most one token, so the producer for iteration 2 cannot fire — it stalls until is consumed. Why this step? This is the defining limitation of static dataflow (parent note): it cannot cleanly overlap invocations of the same subgraph. Look at the red token stuck behind the black one in the figure.
- Consequence. Iterations are effectively serialized on that shared edge — no pipeline parallelism across iterations.
Verify (conceptual): The two "would-be" tokens = but edge capacity = , so is violated by trying to place both → stall is the only legal outcome. This is exactly the problem Example 6 fixes with tags.
Example 6 — Case G: dynamic (tagged) loop, iterations overlapping
Forecast: the answer is . But how many waves if iterations overlap? Guess.

Recall the tagged firing rule (parent note): a node fires only when it holds two tokens and with the same tag , producing . The tag is the "which iteration am I" sticker — the red label on each token in the figure.
- Iteration 1 (). Tokens and match → fire → . Why this step? Both tokens carry , so the matching unit pairs them. This partial sum will feed iteration 2.
- Iteration 2 () can start while 1 is finishing. The token, tagged , is already flowing. It waits only for its own token (the result of iteration 1, re-tagged to ). Fire → . Why this step? Because tags differ, iteration 2's fast -token can never wrongly pair with iteration 1's slow -token — the machine only fires on matching . This is what static dataflow could not do (Ex 5).
- Iteration 3 (). → fire → .
Verify: . ✓ The chain of sums is sequential (each needs the previous partial), but the ingredient tokens () all stream in parallel — this is loop-level / pipeline parallelism, enabled purely by the tags.
Example 7 — Case H: the limiting case — drop the tags, get garbage
Forecast: guess what value the machine might compute instead of the true running sum.
- The bug. Without tags, the matching unit pairs any two tokens sitting on the two input edges. Suppose the node grabs (iteration 1's) together with (iteration 2's). Why this step? This is the "iteration-3's matches iteration-7's " failure the parent note warned about — the machine has no way to tell whose token is whose.
- The garbage. It computes and labels it as "the partial sum after iteration 1", which is wrong (true value is ). Everything downstream is now corrupted. Why this step? One mismatched pair poisons the whole running total.
Verify: True partial after iteration 1 . Garbage value . Since , the computation is corrupted. ✓ This is why dynamic dataflow exists — the tag is not decoration, it is correctness. (Fun fact from the parent's Connections: Out-of-Order Execution solves the identical problem in real CPUs with register renaming / reservation stations = a tagged-token matcher.)
Example 8 — Case I: real-world word problem (the kitchen)
Forecast: naive sequential time is minutes. Guess the dataflow time before computing.
- Build the graph. Nodes:
Sandwich(3 min),Smoothie(2 min),Plate(1 min). Edges:Sandwich → Plate,Smoothie → Plate. This is a diamond without the shared source — a fan-in (Case C). Why this step? Independent tasks (Case A: sandwich vs smoothie) run concurrently;Platewaits for both (its firing rule needs both input edges full). - One combo timing.
SandwichandSmoothiefire at in parallel.Platecan only fire when both are done → it waits for the slower one min. Then plating adds min. Why this step? The firing rule ofPlate= "all inputs ready", so its start time = the max of its predecessors' finish times. - Total for one combo minutes.
- Two combos, dynamic machine. Tag combo-A as , combo-B as . With extra cooks, combo-B's sandwich/smoothie fire at too, tagged . The
Platenode fires once for tokens and once for tokens — tags keep table A's tray separate from table B's. Both plates can proceed at . Total minutes for both. Why this step? This is exactly Ex 6's tagged overlap, in an everyday costume — the sticker on each ingredient is the tag.
Verify: One combo dataflow time min vs sequential min (speed-up ). Two combos: still min (limited by the 3-min sandwich, not by count) vs sequential min → speed-up . ✓
Example 9 — Case J: exam-style throughput twist
Forecast: guess (a) — is it 12 (all nodes) or 4 (the chain)?
- (a) Latency = critical path, not node count. With unlimited hardware, all independent nodes fire together; the only thing you cannot parallelize is a dependency chain. So minimum waves . Why this step? The critical path is the longest sequence of "output-of-one-is-input-of-next" edges (Case B stacked). Everything off the path overlaps (Case A). The nodes don't matter for latency — only the longest chain does.
- (b) Pipelined throughput. Once the pipeline is full, one iteration completes every wave (initiation interval ). The first iteration takes waves to drain; each of the remaining finishes one wave later. Why this step? This is the pipeline formula: total (fill latency) (remaining iterations) .
- Compute: total waves.
Verify: (a) waves. ✓ (b) waves. Sanity: without pipelining you'd pay waves; tagged pipelining gives , a throughput win — the payoff of dynamic dataflow's overlapping (Case G) at scale.
Recall
Recall Which case forces sequential order?
Case B (chained dependency) and every fan-in (Case C, Ex 8's plating). Order comes from empty input edges, never from a program counter. ::: A node cannot fire until all its input edges hold tokens; a chain means each node's input doesn't exist until its predecessor fires.
Recall Why does a constant (zero-input) node fire immediately?
Question ::: Its set of required input edges is empty, so "all inputs present" is vacuously true — nothing to wait for.
Recall Static vs dynamic in one collision sentence?
Question ::: Static stalls when a second token wants an occupied capacity-1 edge (Ex 5); dynamic gives each iteration a tag so many tokens coexist and iterations overlap (Ex 6).
Recall Latency of a dataflow run with unlimited hardware?
Question ::: The length of the critical (longest dependency) path — not the total node count.
Connections
- Dataflow architectures — the parent note this page drills into.
- Von Neumann architecture — the sequential baseline we keep comparing speed-ups against.
- Instruction-Level Parallelism — Case A is its theoretical limit.
- Out-of-Order Execution — Ex 7's tag-matching is literally how reservation stations work.
- Systolic Arrays — a regular, statically-scheduled cousin (relevant to Ex 5's static case).
- Directed Acyclic Graph (DAG) — the structure whose critical path drives Ex 9.
- Loop-Level Parallelism — Examples 6 and 9 are its dataflow realization.