This lesson has one job: prove the controller is big enough before it is bought. Peak datasheet bandwidth is never achieved: page misses, refresh, read-write turnarounds and arbitration shave a workload-dependent fraction off the top. The integrator's spreadsheet adds every master's worst-case demand, multiplies the peak by a realistic efficiency, and either closes the budget or rebalances traffic. An unbudgeted controller fails only under full-system load, which is the most expensive place to discover arithmetic.
Usable bandwidth is peak times efficiency, and the efficiency range of 60 to 85 percent is workload-dependent, never a guarantee. Sequential bursts to open pages sit near the top; random traffic with constant page misses sits near the bottom. Each master gets a QoS class so a bulk DMA cannot starve a latency-critical reader, and the controller's scheduling policy belongs in the integration specification alongside the classes. Ordering completes the picture: the controller may reorder for efficiency, so software-visible order is restored with barriers and by checking interrupt-against-data paths, the same discipline the DMA lessons teach. For the scheduling view see QoS Classes, Priority Arbitration, and Starvation Boundaries; for the collapse scenario see Scenario: DDR Bandwidth Collapse.
The worked example is a NanoSoC-style budget with illustrative controller numbers. Two masters demand 400 and 200 MB/s against a 900 MB/s peak at 70 percent efficiency, which closes with margin; raising the second master to 300 MB/s breaks it, and the script shows both outcomes so the re-budget habit is mechanical.
peak = 900.0
eff = 0.70
usable = peak * eff
assert abs(usable - 630.0) < 1e-9, usable
for label, demands in (("closes", (400, 200)), ("breaks", (400, 300))):
total = sum(demands)
margin = usable - total
print(f"{label}: demand {total} vs usable {usable:.0f}, margin {margin:+.0f} MB/s")
assert (margin >= 0) == (label == "closes")
print("PASS: budget closes at 600, breaks at 700 MB/s demand")Every master that can reach the controller appears in the demand column with its worst case, not its average.
The efficiency number names the workload it assumes; a single efficiency for all workloads is a review finding.
QoS classes are assigned per master and checked in performance simulation with all masters active.
Drive the traffic model with the budgeted mix and measure achieved bandwidth and tail latency at the controller port; then rerun with the starvation mix of bulk-plus-latency-critical and confirm the QoS classes hold. If throughput meets the budget but tails miss, the efficiency was right and the scheduling policy was wrong.
Because bandwidth is an average and deadlines are about tails: without QoS classes one master bursts while the other waits, and the average still looks fine. Budget the classes, not just the bytes.