Skip to guide

Concurrency and performance

QoS, Fairness, and Backpressure

02 of 3 · Concurrency, Ordering & Performance

Treat latency, bandwidth share, starvation, and credit conservation as correctness properties under sustained contention.

Trace the mechanism from failure signature through independent evidence, component ownership, stress, and recovery.

Native mechanism diagram2 implementation tradeoffs3 interview follow-ups
Correct data, correct timeOne reusable contract across 1 cases.
  1. 01OFFERGenerate sustained concurrent demand
  2. 02ARBITRATETrack identity, priority, dependencies, and credits
  3. 03COMMITApply the real ordering and visibility contract
  4. 04MEASUREProve progress, fairness, latency, and throughput

QoS and fairness

02 · Concurrency and performance

QoS, Fairness, and Backpressure

Treat latency, bandwidth share, starvation, and credit conservation as correctness properties under sustained contention.

Mechanism · failure · evidence · recovery
Contention as correctnessMeasure share, latency, starvation, and conserved credits together.

A weighted arbiter can meet aggregate bandwidth while still starving one class, leaking credits, or violating a bounded-latency promise.

Realtimetarget 50% · observed 48%oldest 42 cyclesComputetarget 30% · observed 31%oldest 87 cyclesBackgroundtarget 20% · observed 21%oldest 143 cycles
12-cycle grant and age traceAggregate share can pass while one request approaches its starvation deadline.
grantRTCPRTBGRTCPRTCPRTBGRTCP
BG age012grant01234grant01
pending BG requestmust grant before age 6
Issued credits64Free19In flight45Starvation bound< 2,000 ns

demand pending → eventual grant within class bound · free + in_flight = issued credits

Why it matters

  • A chip can move every bit correctly and still be unusable because its performance policy is broken.
  • For example, a GPU stream can starve CPU memory traffic even though every individual transaction is protocol-correct.
  • QoS verification must prove that each priority class receives its specified bandwidth and latency behavior under congestion.

What is difficult

  • Long-tail starvation may appear only once in a very large sample, such as a request waiting 10,000 cycles for a grant.
  • Weighted Round Robin and related arbiters are intentionally difficult to predict cycle by cycle under random stimulus.
  • Fairness requires statistical or bounded evidence, not a few successful transfers.
  • A credit leak can degrade throughput slowly enough that short tests pass.
  • A watchdog must distinguish an actively starved class from one with no pending demand.

Failure signatures

  • A low-priority request waits beyond its allowed starvation bound.
  • A high-priority stream misses its required bandwidth percentage.
  • Grant ratios do not converge toward programmed WRR weights.
  • A low-priority request blocks a high-priority request through a shared buffer or single-entry queue.
  • READY deassertion on the final beat causes duplication, loss, or state corruption.
  • Flow-control credits leak and total throughput decays over a long run.

Two viable approaches—and their cost

Statistical performance subscriber

Collect latency and bandwidth distributions from accepted and completed transactions.

Strengths
  • Non-intrusive and implementation-independent.
  • Provides a global view of latency, bandwidth share, and tail behavior.
Costs
  • Needs explicit thresholds or post-processing to turn statistics into pass-fail decisions.
  • A finite sample cannot prove every possible starvation trace.

Credit-based tracking

Mirror the DUT's internal flow-control credit accounting in the testbench.

Strengths
  • Detects credit leaks that slowly reduce throughput.
  • Can localize a performance failure to a conservation error.
Costs
  • Tightly coupled to RTL implementation details.
  • Sensitive to arbiter and buffering changes.

Interview answer, built from the mechanism

  1. Use pressure-cooker stimulus: saturate the arbiter with several high-priority streams plus at least one low-priority stream.
  2. Record request, grant, and completion timestamps. Build latency distributions, tail percentiles, throughput, and grant-share metrics per priority.
  3. Fail a class that exceeds its latency or starvation bound, and fail a high-priority class that misses its specified bandwidth share.
  4. Run long regressions and track credit conservation and aggregate throughput so slow credit leaks cannot hide behind short functional tests.

Component responsibility contract

Component responsibilities and required verification changes for QoS, Fairness, and Backpressure
ComponentResponsibilityRequired change
Agent configTraffic shapingAdd Weight and Priority knobs for sequences.
MonitorTimestampsRecord req_time, gnt_time, and data_done_time.
SubscriberStatisticsCollect minimum, maximum, average, histogram, and tail latency by priority.
WatchdogStarvationCheck only priority classes with pending demand against their timeout.
Credit modelConservationTrack issued, consumed, and returned credits over long runs.

Implementation patterns

Track per-priority latencysystemverilog
realtime total_latency[int];
int      trans_count[int];
realtime last_access_time[int];

realtime MAX_LATENCY_THRESHOLD = 500ns;
realtime STARVATION_TIMEOUT     = 2000ns;

virtual function void write(mac_item t);
  realtime latency = t.complete_time - t.accept_time;
  int p = t.priority;

  total_latency[p] += latency;
  trans_count[p]++;
  last_access_time[p] = $realtime;

  if (latency > MAX_LATENCY_THRESHOLD)
    uvm_report_warning("QOS_TAIL", "Latency exceeded 500 ns");

  uvm_report_info(
    "PERF_STATS",
    $sformatf("Prio=%0d Avg=%0t Count=%0d",
              p, total_latency[p] / trans_count[p], trans_count[p]),
    UVM_HIGH
  );
endfunction

The source formula is latency = complete_time - accept_time, and the running average is total_latency[p] / trans_count[p]. The example threshold is 500 ns.

Check starvation periodicallysystemverilog
virtual task run_phase(uvm_phase phase);
  forever begin
    #100ns;
    foreach (last_access_time[p]) begin
      if (pending_count[p] > 0 &&
          ($realtime - last_access_time[p]) > STARVATION_TIMEOUT)
        uvm_report_error(
          "QOS_STARVATION",
          $sformatf("Priority %0d waited more than %0t",
                    p, STARVATION_TIMEOUT)
        );
    end
  end
endtask

The source checks every 100 ns with a 2000 ns timeout. The pending-demand guard prevents an idle traffic class from being mislabeled as starved.

Report final averagessystemverilog
virtual function void report_phase(uvm_phase phase);
  foreach (trans_count[p]) begin
    uvm_report_info(
      "QOS_REPORT",
      $sformatf("Prio %0d: %0d packets, Avg latency %0t",
                p, trans_count[p],
                total_latency[p] / trans_count[p]),
      UVM_LOW
    );
  end
endfunction

Average latency is useful context, but signoff also needs tail, maximum, bandwidth share, starvation, and credit-conservation results.

Stress recipe

  1. Saturate the fabric with several high-priority streams and one continuously pending low-priority stream.
  2. Run at least the source example of 10,000 transactions for a WRR grant-ratio check.
  3. Measure request-to-grant and request-to-completion latency, bandwidth share, p99, maximum, and starvation duration by priority.
  4. Drop READY on the final beat and other state-transition boundaries.
  5. Run long enough to reveal a slow credit leak and compare total throughput over successive windows.

Follow-up questions

How do you verify Weighted Round Robin?

Run a large window, such as 10,000 transactions, count grants by class, and compare the observed grant ratios with the programmed weights using a justified statistical tolerance.

How do you expose backpressure bugs?

Use a Ready-Toggle sequence that deasserts READY at difficult boundaries, especially the final beat of a burst, then prove state and payload remain stable until the transfer completes.

What common QoS bug should you look for?

Priority inversion, where a low-priority request blocks high-priority work through a shared buffer, dependency, or single-entry queue.