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
  • Part 5: Transactions19
  • Part 6: Concurrency and Performance17
    • Latency, Throughput and Bandwidth
    • Little's Law
    • Outstanding Transactions
    • Tags and IDs
    • In-Order or Out-of-Order
    • Reorder Buffers
    • Interleaving
    • Split Completions
    • Protocol Efficiency
    • Peak and Sustained Bandwidth
    • Queueing Intuition
    • Tail Latency
    • Buffers That Hide Latency
    • Virtual Output Queues
    • Performance Modelling
    • Protocols Compared: Concurrency and Performance
    • Drills: Concurrency and Performance
  • 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 6: Concurrency and Performance
  1. Topics
  2. First Principles of Hardware Protocols
  3. Part 6: Concurrency and Performance
  4. Performance Modelling

Part 6 · Concurrency and Performance · Principal (P)

Performance Modelling

How architects size a protocol before writing RTL: start from bounds, build a small cycle model, sweep the parameters that matter, and present the result so that a decision can be made from it.

On this page

    Note

    Level: Principal (P) · Answers: How many requests can be in flight?

    Before this: Little's Law, The Credit Loop and Buffer Sizing

    A new link needs a tag pool and a receive buffer. The RTL team asks how big each should be. One answer is "as big as we can afford"; another is "whatever the last project used". Both are guesses that will be expensive to change after the RTL exists. A model of a few dozen lines, written in an afternoon, answers the question with numbers and shows which knob matters.

    How do you size a protocol's resources before there is any RTL?

    The obvious answer, and why it breaks

    The obvious approach is to wait for the RTL and measure. But by then the sizes are built in, and changing a tag width or a buffer depth means changing interfaces and verification. The other obvious approach, a spreadsheet of averages, misses interactions: a link limited by both its tags and its credits behaves like neither limit alone. Architects work in between: bounds first, then a small cycle model, then a sweep.

    The idea: a four-step method

    1. Write down the bounds. Each resource caps throughput by Little's law: tags ÷ round trip, credits ÷ credit loop, the target's service rate. The smallest bound is the first estimate.

    2. Build a small cycle model with only the mechanisms that create those bounds and their interactions: latency, outstanding limit, credits, service time. Leave out everything else.

    3. Sweep the parameters you can choose (tags, buffer depth) across the range you could afford, under the traffic you expect.

    4. Present the result as a picture with the decision on it: where each curve flattens, and what each extra entry buys.

    throughput≤min(service rate,round tripoutstanding​,credit loopcredits​)

    Build it: a reusable link model

    A requester reads from a target over a link with 10 cycles of wire delay each way. The target serves one request per cycle from a queue protected by credits. The model sweeps the requester's outstanding limit and the target's queue size, and checks every result against the three bounds.

    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
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    """A small cycle model for sizing a link before any RTL exists.
    
    A requester issues read requests over a link to a target and back:
      - at most `outstanding` requests may be in flight (tags, lesson 6.4)
      - requests take `wire` cycles each way
      - the target holds at most `credits` requests (its queue, lesson 4.5) and
        serves one every `service` cycles
    The model sweeps outstanding requests and target queue size and reports
    throughput (completions per cycle), then checks it never beats the three bounds:
    the target's rate, outstanding / round trip, and credits / credit loop.
    """
    from collections import deque
    
    WIRE, SERVICE = 10, 1
    
    
    def run(outstanding, credits, cycles=4000):
        inflight = 0                    # requests issued and not yet completed
        crd = credits                   # requester's view of free target slots
        to_target = deque()             # (arrival cycle) requests on the wire
        queue = deque()                 # requests waiting at the target
        to_req = deque()                # (arrival cycle) responses on the wire
        crd_back = deque()              # (arrival cycle) credits on the wire
        next_free = 0
        done = 0
        for t in range(cycles):
            while to_req and to_req[0] <= t:
                to_req.popleft(); inflight -= 1
                done += t >= cycles // 2
            while crd_back and crd_back[0] <= t:
                crd_back.popleft(); crd += 1
            while to_target and to_target[0] <= t:
                to_target.popleft(); queue.append(t)
            if queue and t >= next_free:                      # target starts serving one
                queue.popleft()
                next_free = t + SERVICE
                to_req.append(t + SERVICE + WIRE)
                crd_back.append(t + WIRE)                     # slot freed: credit goes back
            if inflight < outstanding and crd > 0:            # issue a new request
                inflight += 1; crd -= 1
                to_target.append(t + WIRE)
        return done / (cycles - cycles // 2)
    
    
    rtt = 2 * WIRE + SERVICE
    print(f"wire {WIRE} cycles each way, service {SERVICE} cycle: round trip {rtt} cycles")
    print("outstanding:   " + " ".join(f"{o:5d}" for o in (4, 8, 16, 24, 32)))
    for credits in (4, 8, 32):
        row = [run(o, credits) for o in (4, 8, 16, 24, 32)]
        print(f"credits {credits:>2}:    " + " ".join(f"{x:5.2f}" for x in row))
        for o, x in zip((4, 8, 16, 24, 32), row):
            bound = min(1 / SERVICE, o / rtt, credits / (2 * WIRE))
            assert x <= bound + 0.01 and x >= bound - 0.06, (o, credits, x, bound)
    print("PASS: throughput follows the tightest of the three bounds; size both tags and credits from the round trip")

    It prints:

    Diagram
    wire 10 cycles each way, service 1 cycle: round trip 21 cycles
    outstanding:       4     8    16    24    32
    credits  4:     0.19  0.20  0.20  0.20  0.20
    credits  8:     0.19  0.38  0.40  0.40  0.40
    credits 32:     0.19  0.38  0.76  1.00  1.00
    PASS: throughput follows the tightest of the three bounds; size both tags and credits from the round trip
    The model's numbers: each curve rises with tags until the credits run out, then flattens; only with 32 credits do 24 tags reach full rate.

    Reading the picture

    • Each curve is capped by its credits: 4 credits over a 20-cycle credit loop allow at most 0.2 per cycle, whatever the tag count.

    • The 32-credit curve is capped by tags until 21 outstanding cover the 21-cycle round trip; 24 and 32 tags both reach full rate.

    • The decision: 24 tags and at least 20 credits give full rate. Below that, the plot shows exactly what each smaller choice would cost.

    What to sweep, and what to leave out

    Include

    Leave out (until it matters)

    Latency of each path, worst case as well as typical

    Exact bit widths, encodings, field layouts

    Every limit on in-flight work: tags, credits, buffers

    Logic details that do not change timing

    The traffic you expect: rate, burstiness, mix

    Rare error paths (model them separately)

    The arbitration or scheduling policy, if resources are shared

    Anything you cannot yet estimate: say so instead

    Validate the model twice: against the bounds (as the listing does), and later against the RTL, so its next use is trusted.

    What breaks

    A team (illustrative) sized a link's tag pool from its typical round trip, 40 cycles, and modelled nothing else. Under load the round trip stretched to 90 cycles in a busy fabric, and the 48-tag pool capped the link at about half rate. A model that swept latency as well as tags would have shown the curve flattening early, and the fix (64 more tags) would have cost almost nothing before the RTL was written.

    Why this matters

    Principal lens. A performance model's job is to make a decision obvious. Keep it small enough to explain, check it against the analytical bounds, sweep the worst-case latency and not only the typical one, and present one picture per decision with the recommended point marked. Keep the model in the repository and re-run it whenever a latency, a buffer or the traffic changes.

    Interview

    Asked: "How would you size the buffers before writing RTL?"

    Weak answer: Make them as big as possible.

    Strong answer: Bounds first: each resource caps throughput by Little's law, tags over round trip, credits over the credit loop, and the target's service rate. Then a small cycle model with just latency, outstanding limit, credits and service time, swept over the sizes I could afford and over worst-case latency, under the expected traffic. I'd check the model hits the bounds and present throughput curves with the knee marked, so the choice is visible: here, 24 tags and at least 20 credits for full rate.

    Follow-ups: (1) What would you deliberately leave out of the model? (2) How do you know the model is right?

    Check yourself In the model's output, why do 8 and 16 outstanding give the same throughput with 8 credits?

    Credits are the tighter bound: 8 credits over a 20-cycle credit loop allow at most 0.4 per cycle, which 16 outstanding already reach.

    Check yourself Why sweep worst-case latency as well as tags and credits?

    Because every Little's-law bound divides by latency; a resource sized for typical latency becomes the bottleneck when latency grows under load.

    Key takeaways

    • Size before RTL: write the bounds, build a small cycle model, sweep, and present a picture with the decision on it.

    • Throughput follows the tightest of the service rate, outstanding / round trip and credits / credit loop.

    • Validate the model against the bounds and later the RTL, and sweep worst-case latency.

    Keep going

    Next: Protocols Compared: Concurrency and Performance. How a dozen protocols handle concurrency: outstanding requests, ordering, interleaving and efficiency.

    Related topics

    • Part 6 overview: Concurrency and Performance

    Previous

    101 / 234

    Next: Protocols Compared: Concurrency and Performance

    Up next

    Up nextProtocols Compared: Concurrency and Performance

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Latency, Throughput and Bandwidth
    • Little's Law
    • Outstanding Transactions