Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutContactPrivacyTerms
Skip to lesson

Course contents

  • How to Use This Course
  • Reading Paths
  • Concept Map
  • How to Read the Diagrams
  • Part 0: What Is a Protocol?10
  • Part 1: Timing and Clocking11
  • Part 2: Encoding and Framing12
  • Part 3: Handshakes13
  • Part 4: Flow Control17
    • Why Flow Control
    • On/Off Flow Control
    • Credit-Based Flow Control
    • Credit Initialisation
    • The Credit Loop and Buffer Sizing
    • Credit Classes and Pools
    • Credit Return Latency and Batching
    • Credit Bugs
    • Window Flow Control
    • Rate-Based Shaping
    • Hop-by-Hop or End-to-End
    • Lossless or Lossy
    • Switching Modes
    • Head-of-Line Blocking
    • Choosing Flow Control
    • Protocols Compared: Flow Control
    • Drills: Flow Control
  • Part 5: Transactions19
  • Part 6: Concurrency and Performance17
  • Part 7: Ordering13
  • Part 8: Sharing and Arbitration12
  • Part 9: Deadlock and Liveness13
  • Part 10: Reliability and Recovery20
  • Part 11: Bring-Up and Link Management10
  • Part 12: Power8
  • Part 13: Shared State and Coherence9
  • Part 14: Security and Isolation7
  • Part 15: Specifying and Verifying11
  • Part 16: Protocols Dissected17
  • Part 17: Capstones5
  • Part 18: Interview Preparation6
Loading lesson

‹Part 4: Flow Control
  1. Topics
  2. First Principles of Hardware Protocols
  3. Part 4: Flow Control
  4. Head-of-Line Blocking

Part 4 · Flow Control · Working (W)

Head-of-Line Blocking

A packet at the front of a queue that cannot move blocks everything behind it, even packets for idle outputs. How to recognise head-of-line blocking and the queue structures that remove it.

On this page

    Note

    Level: Working (W) · Answers: How much may I send before I hear back?

    Before this: Hop-by-Hop or End-to-End

    A router input receives traffic for two outputs, X and Y. Output X is always free. Output Y is busy half the time. Measured, traffic to X gets only half its bandwidth, even though nothing ever blocks output X. The packets for X are stuck somewhere they should never be: behind packets for Y.

    Why can traffic for a free output be held up, and how do you stop it?

    The obvious answer, and why it breaks

    The obvious input buffer is one FIFO: packets arrive, wait in order, and leave in order. It is simple and preserves order. But a FIFO can only send its head. When the head packet's output is busy, it cannot leave, and neither can anything behind it, including packets for outputs that are completely free. This is head-of-line (HoL) blocking: the queue's order, not the outputs, decides who waits.

    The idea: queue by where packets are going

    The fix is to give each destination (or each class of traffic) its own queue at the input, so a packet waits only behind packets going to the same place. In a switch these are virtual output queues (VOQs): one queue per output at each input. In an on-chip network the same idea appears as virtual channels: separate buffers on one physical link, so a blocked packet in one channel does not hold up the others. A packet now blocks only traffic that would have waited for the same output anyway.

    Top: a blocked Y packet at the head of one FIFO holds back the X packets behind it. Bottom: separate queues let X traffic flow while Y waits.

    Build it: measure the loss

    The model sends packets alternately to X and Y, with Y busy for ten cycles out of every twenty, and counts how many X packets get through in 1,000 cycles with one shared FIFO and with a queue per output.

    example.py
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    """Head-of-line blocking at an input with traffic for two outputs.
    
    An input receives one packet per cycle, alternating between output X and output Y.
    Output Y is blocked every other 10 cycles (busy downstream); output X is always free.
      single FIFO: packets leave in arrival order; a Y packet at the head blocks X packets behind it
      per-output queues: X and Y packets wait in separate queues and leave independently
    Measure how many X packets get through in 1000 cycles (offered: 500).
    """
    from collections import deque
    
    
    def run(per_output, cycles=1000, depth=8):
        q = {"X": deque(), "Y": deque()} if per_output else deque()
        x_out = 0
        for t in range(cycles):
            dest = "X" if t % 2 == 0 else "Y"
            if per_output:
                if len(q[dest]) < depth:
                    q[dest].append(dest)
            elif len(q) < depth:
                q.append(dest)
            y_free = (t // 10) % 2 == 0
            if per_output:
                if q["X"]:
                    q["X"].popleft(); x_out += 1
                if q["Y"] and y_free:
                    q["Y"].popleft()
            elif q and (q[0] == "X" or y_free):
                if q.popleft() == "X":
                    x_out += 1
        return x_out
    
    
    shared, voq = run(False), run(True)
    print(f"X packets delivered (500 offered): single FIFO {shared}, per-output queues {voq}")
    assert voq == 500 and shared < voq
    print("PASS: in one FIFO a blocked Y packet holds back the X packets behind it")

    It prints:

    Diagram
    X packets delivered (500 offered): single FIFO 251, per-output queues 500
    PASS: in one FIFO a blocked Y packet holds back the X packets behind it

    With one FIFO, X gets about half of what it offered, even though output X was never busy: whenever a Y packet reached the head during Y's busy period, everything behind it waited. With a queue per output, X receives all 500. The cost is extra queues and the logic to choose among them.

    In a larger switch the loss is a known number: with one FIFO per input and uniformly random traffic, head-of-line blocking limits throughput to about 58.6% of the outputs' capacity, however fast the switch is. Virtual output queues remove that limit.

    The design space

    Structure

    HoL blocking

    Cost

    One FIFO per input

    Yes: any blocked head stalls the input

    Least: one queue

    Virtual output queues (one per output per input)

    None between outputs

    N queues per input and a scheduler that matches inputs to outputs

    Virtual channels (a few buffers per link)

    Reduced: a blocked packet holds one channel, not the link

    Buffers and arbitration per channel

    Output queuing (buffer at the outputs)

    None

    The fabric must run N times faster to deliver N simultaneous arrivals

    Where it appears

    • Network switches and routers: input-queued designs use virtual output queues with a scheduler; HoL blocking is the classic reason.

    • On-chip networks: virtual channels let packets bypass a blocked one on the same link, and keep traffic classes from blocking each other (Part 9).

    • Inside protocols: any single in-order channel carrying independent streams has the same problem; protocols that allow responses out of order (transaction IDs, Part 6) let a slow target stop holding up a fast one.

    What breaks

    The opening router (illustrative) had one input FIFO per port. Under a mixed workload, traffic to a fast memory controller was throttled by traffic to a slow peripheral queued in front of it, and the fast controller sat idle about half the time. Adding a second virtual channel for peripheral traffic gave the memory traffic a path around the slow packets and restored its bandwidth, at the cost of a second buffer and an arbiter on each port.

    Why this matters

    Senior lens. Look for HoL blocking wherever independent traffic shares one in-order queue: router inputs, bridge FIFOs, response paths with a single ordering. The signature is an idle output with traffic for it waiting in a queue. The cure is always the same shape: separate queues for traffic that must not wait for each other, at the cost of more buffers and a scheduler. Decide which traffic must be independent before deciding how many queues to build.

    Interview

    Asked: "What is head-of-line blocking and how do you fix it?"

    Weak answer: When the queue is full.

    Strong answer: A queue can only send its head, so when the head packet's output is busy, everything behind it waits, even packets for free outputs. With a FIFO per input and uniform random traffic it limits a switch to about 58.6% throughput. The fix is separate queues by destination: virtual output queues in switches, virtual channels in NoCs, so a packet waits only behind packets that need the same output. The cost is more buffers and a scheduler or arbiter to pick among the queues.

    Follow-ups: (1) Why doesn't output queuing have HoL blocking? (2) Where does HoL blocking appear inside a protocol?

    Check yourself What is the waveform or counter signature of HoL blocking?

    An output that is idle while packets destined for it wait in an input queue behind a packet for a busy output.

    Check yourself In the model, why does X get about half its traffic with one FIFO?

    Y is busy half the time; whenever a Y packet is at the head during that time, the X packets behind it cannot leave either.

    Check yourself What do virtual output queues cost?

    One queue per output at each input, and a scheduler that matches waiting inputs to free outputs every cycle.

    Key takeaways

    • A queue sends only its head: a blocked head packet holds back everything behind it, even traffic for free outputs.

    • One FIFO per input limits a switch to about 58.6% throughput under uniform random traffic.

    • Separate queues by destination or class (virtual output queues, virtual channels) remove it, at the cost of buffers and scheduling.

    Keep going

    Next: Lesson 4.15, Choosing Flow Control. Ready, on/off, credits, windows or rate limits? A decision guide for any link.

    Related topics

    • Part 4 overview: Flow Control

    Previous

    64 / 234

    Next: Choosing Flow Control

    Up next

    Up nextChoosing Flow Control

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Why Flow Control
    • On/Off Flow Control
    • Credit-Based Flow Control