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

  • Part 0 · What Debugging Is6
  • Part 1 · Reproduce8
  • Part 2 · Observe9
  • Part 3 · Localise10
  • Part 4 · Hypothesise and Test6
  • Part 5 · Bug Classes16
  • Part 6 · Debug by Stage9
  • Part 7 · Hangs and Deadlocks7
  • Part 8 · Intermittent Failures7
  • Part 9 · Fix, Prove, Prevent7
  • Part 10 · Case Studies12
  • Part 11 · Debug as a Team5
  • Part 12 · Interview Prep5
    • Find the Bug in This Waveform
    • The Chip Hangs: What Do You Do?
    • A Test Fails Once in 500 Runs
    • How Do You Know Your Fix Works?
    • Mock Debug Interview
Loading lesson

‹Part 12 · Interview Prep
  1. Topics
  2. The Art of Hardware Debug
  3. Part 12 · Interview Prep
  4. A Test Fails Once in 500 Runs

Part 12 · Interview Prep · Senior (S)

A Test Fails Once in 500 Runs

The intermittent interview question rehearsed: ask what "500 runs" means, replay the seed, measure the rate with an interval, find what the failing seeds share, raise the rate, and prove the fix with a stated bound. Shown on a real 500-seed sweep of dbglab that fails 3 times.

On this page

    Why this matters

    "It fails once in 500 runs" is where candidates reach for "rerun it and look at the waveform" or "it is probably flaky", and interviewers mark both down. The question tests whether you can turn a rate into a repro and a fix into a number.

    After this lesson you can: answer the rare-failure question as a method: tell seed-dependent from nondeterministic, measure the rate with an interval, find what failing seeds share, raise the rate, and size the sweep that proves a fix.

    Note

    Level: Senior (S) · Debug-loop step: Reproduce, Prove

    Before this: Making a Flaky Test Fail, Statistics of Rare Failures

    The question, as it is asked

    "One of our random tests fails about once in 500 runs. Nobody can make it fail on demand, and the team wants to mark it flaky and move on. You own it now. What do you do?"

    The interviewer has given you a number and a temptation. Which one do you question first?

    What the interviewer is listening for

    1. What "500 runs" means. 500 different seeds, or one seed run 500 times? The first is a deterministic bug with a rare input. The second is real nondeterminism: a race, an uninitialised value, the environment (determinism and seeds).

    2. A replay. Take one failing seed, same commit, same command, and run it again. If it fails every time, the repro already exists.

    3. A measured rate with its uncertainty, by signature. Not "once in 500" but "3 in 500, all with this message", and what that number can and cannot mean (statistics of rare failures).

    4. What the failing seeds share. A probe over every seed, failing and passing, looking for the condition only the failures have.

    5. A higher rate, on purpose. Stress the state the bug needs (making the rate go up).

    6. A proof sized in advance. How many clean runs, of what, rule out the old rate.

    A weak answer, and why it fails

    Interview

    Weak: "I would rerun it a few hundred times until it fails, dump the waveform and look for the problem. If I cannot find anything it is probably a simulator or testbench issue, so I would mark it flaky and keep an eye on it."

    "Rerun it" ignores that a seeded test is already a repro: the failing seed is the command. "Look for the problem" is browsing. "Probably the simulator" is the it must be the tool trap, unchecked. And "mark it flaky" ships a bug that fails once in 500 runs here and once a day in a customer's system.

    A strong answer, out loud

    For a rare failure, the weight is at Reproduce (seed, rate, signature), Localise (what failing seeds share) and Prove (a sized sweep).
    1. Report. "First: 500 seeds, or one seed 500 times? And do all the failures have the same message?"

    2. Reproduce. "I replay a failing seed on the same commit. If it fails every time, the bug is deterministic and the seed is my repro. I also run it in a second simulator: if both fail the same way, it is the design or the bench, not the tool."

    3. Measure. "I sweep a few hundred seeds and count failures by signature, with an interval. If the replay was not deterministic, that changes the whole plan: then I hunt the hidden input first."

    4. Localise. "I probe every seed for candidate conditions and look for one that all the failing seeds have and the passing ones do not. That condition is my hypothesis."

    5. Raise the rate. "I write a directed test, or bias the random one, towards that condition, so it fails every run instead of once in 500."

    6. Fix and prove. "I fix the cause, rerun the old failing seeds and the directed test, and then sweep fresh seeds: enough that, if the old rate were still there, I would almost surely have seen it. I keep the directed test in the regression."

    Do it: a real once-in-500

    To get a rare failure with one cause, this run uses a scratch copy of dbglab with one of its bugs fixed (B4, the unreset FILL register) and the random test shortened to 20 operations with +OPS=20. One bug is left in it. Sweep 500 seeds, as the nightly would:

    Report: three failures, one signature

    Terminal
    $ for s in $(seq 1 500); do tb/run.sh random $s icarus +OPS=20 | grep FAIL; done > fails.txt
    $ wc -l < fails.txt
           3
    $ cat fails.txt
    FAIL test=random seed=320 cycle=476: SCOREBOARD (final sweep): RAM word 253 (address 000013f4) holds 34f9eb8a, expected 97edaa4a (last written by DMA run #1)
    FAIL test=random seed=451 cycle=375: SCOREBOARD: RAM word 749 (address 00001bb4) read 1de81775, expected b76ec824 (last written by DMA run #1)
    FAIL test=random seed=487 cycle=719: SCOREBOARD (final sweep): RAM word 451 (address 0000170c) holds 09f065f7, expected 5e829a5a (last written by DMA run #1)

    Three in 500, and they look alike: a wrong but real value (not X), in a word last written by a DMA run. Treat them as one bug until something says otherwise.

    Reproduce: the seed is the repro

    Terminal
    $ tb/run.sh random 451 icarus +OPS=20
    dbglab: test=random seed=451
    FAIL test=random seed=451 cycle=375: SCOREBOARD: RAM word 749 (address 00001bb4) read 1de81775, expected b76ec824 (last written by DMA run #1)
    $ tb/run.sh random 451 icarus +OPS=20
    dbglab: test=random seed=451
    FAIL test=random seed=451 cycle=375: SCOREBOARD: RAM word 749 (address 00001bb4) read 1de81775, expected b76ec824 (last written by DMA run #1)
    $ tb/run.sh random 451 verilator +OPS=20
    dbglab: test=random seed=451
    FAIL test=random seed=451 cycle=375: SCOREBOARD: RAM word 749 (address 00001bb4) read 1de81775, expected b76ec824 (last written by DMA run #1)

    Same line, same cycle, twice and in a second simulator. Nothing about this test is flaky: seed 451 fails every time. "Once in 500" was a property of the stimulus, not of the run.

    Measure: what the number can mean

    terminal
    $ python3 rate.py 3 500 1500      # exact binomial interval; what 1500 clean runs would rule out
    Terminal
    3 in 500: rate 0.60%, 95% interval 0.12% to 1.74%
    1500 clean runs: chance if the rate were still 0.60%: 1.2e-04; rate now below 0.20% (95%)
    runs to see one failure at 0.60% with 95% confidence: 498

    "Once in 500" is consistent with these three failures, and so is once in 57. That width is why you do not plan from the point estimate. The last line answers a question the interviewer may ask: to see this bug even once with 95% confidence at its current rate takes about 500 runs, which is exactly why nobody could make it fail on demand by rerunning.

    Localise: what the failing seeds share

    Terminal
    $ probes/run-probe.sh b4fix probes/dma_probe.sv random 451 +OPS=20
    dbglab: test=random seed=451
    cycle 25: DMA run #1 start  LEN=298 SRC=000011f4 DST=00001934  left_q=42
    cycle 363: DMA run #1 done   words written=42  dst_q=000019dc
    FAIL test=random seed=451 cycle=375: SCOREBOARD: RAM word 749 (address 00001bb4) read 1de81775, expected b76ec824 (last written by DMA run #1)
    $ ./sweep-long.sh > sweep-long.txt       # every seed: any DMA run over 255 words? did it fail?
    $ awk '{print $2, $3}' sweep-long.txt | sort | uniq -c
     497 long=0 fail=0
       3 long=1 fail=1

    The DMA was asked for 298 words and wrote 42: 298 minus 256. Over all 500 seeds the pattern is exact: the three failing seeds are the only ones with a DMA run longer than 255 words. That is the hypothesis, an 8-bit beat counter, and the debug loop lesson walks this same bug to its line.

    Raise the rate: aim at the mechanism, not the length

    Stimulus

    Failures

    Mean run length

    Failures per 1,000 cycles

    random +OPS=20, seeds 1 to 500

    3 (0.6%)

    278 cycles

    about 0.022

    random default length, seeds 1 to 100

    22 (22%)

    19,493 cycles

    about 0.011

    Running 70 times longer raised the rate 37 times, so per simulated cycle it found the bug half as often. Length is not the stress this bug needs; long DMA runs are. The debug loop lesson's directed dma_long test copies 255, 256, 257 and 511 words and fails at HEAD on every seed it was tried with (1, 2, 7 and 33). That is the stressed repro to prove the fix on.

    Prove: a sweep sized to rule out the old rate

    Terminal
    $ cd ../b34fix          # the same copy with the beat counter widened to 10 bits
    $ for s in $(seq 1 1500); do tb/run.sh random $s icarus +OPS=20 | tail -1; done | cut -c1-4 | sort | uniq -c
    1500 PASS

    All 500 old seeds pass, including 320, 451 and 487, and so do 1,000 seeds that never ran before. If the old 0.60% rate were still there, 1,500 clean runs would happen with a chance of about one in 8,300. The claim is now a number: below 0.20% at 95% on this stimulus, plus a directed test that fails every seed without the fix.

    What the evidence says

    The vague report became four facts: the failure is deterministic per seed, its rate is 0.12% to 1.74%, it needs a DMA run over 255 words, and the fix leaves no failure in 1,500 runs. Each answered a sentence of the strong answer, and none needed a waveform. The time went into sweeps that a script runs while you think.

    Follow-up questions

    • "The same seed sometimes passes." Then something outside the seed differs: process order, an uninitialised value, a clock phase, the machine. Find it before anything else (why intermittents happen), for example by running the same seed with random start values or another simulator.

    • "The failure needs 2 million cycles before it shows." Shrink it: bisect the length, then the transactions (shrinking a failing test), and capture it with a flight recorder rather than a full dump (capturing the rare event).

    • "How many runs before you close it?" Decide the rate you must rule out and the confidence first. About 3/p clean runs rule out a rate p at 95%; at 0.6% that is 500, and a stressed repro needs far fewer.

    • "Two failure messages appeared in the sweep." Treat them as two bugs until one hypothesis explains both (keeping several hypotheses alive).

    Traps

    Common pitfall

    Proving on the seeds that measured the bug. Seeds 1 to 500 passing shows the three known failures are gone. Only fresh seeds bound the rate on stimulus nobody has looked at, which is why the sweep above runs to 1,500.

    Common pitfall

    "It passed 50 times, so it is fixed." At 0.6%, 50 clean runs happen 74% of the time with the bug still in. Say the rate you are ruling out before you start the sweep.

    Why this matters

    Senior lens. The team wanted to mark it flaky because nobody owned the 500 runs. A regression that records seed, commit and signature for every failure, and a rule that "flaky" needs the same seed to pass and fail, turn this conversation into a ticket with a repro attached. Part 11 covers the triage side; recording everything to replay covers the record.

    Interview

    Asked: "Your nightly regression is 2% red, different tests each night. Management asks if the design is stable enough to tape out. What do you say?"

    Weak answer: 2% is low, so it is probably noise from flaky tests. I would rerun the failures and if they pass we are fine.

    Strong answer: I would not answer from the 2%. First I sort the failures by signature and replay each failing seed: every one that fails again is a real, deterministic bug with a repro. Then I count distinct signatures and the rate of each with an interval, because ten signatures at 0.2% is ten bugs, not noise. For any that do not replay, I look for the hidden input. The answer to management is the list: how many distinct bugs, which are understood, which are fixed with a sized proof, and which are open.

    Follow-ups: (1) How would you prioritise ten distinct rare signatures? (2) What would make you believe one of them really is a testbench problem?

    Check yourself A colleague replays seed 451 and it passes. The commit and command are the same. What does that tell you, and what next?

    That the failure is not determined by the seed alone, so something else differs between the two runs: a different simulator or version, options, a plusarg, the environment, or a race or uninitialised value whose result changes between runs. Before anything else, compare the two runs' full records (version, options, plusargs, start values). In this lesson's copy, seed 451 failed identically three times, so that would point to a difference in how the colleague ran it.

    Check yourself After the fix, someone proposes running the default-length random test on 30 seeds as the proof, "since it used to fail 22% of the time". Is that enough?

    It is a reasonable first check: at 22%, 30 clean runs would happen by luck about once in 1,700. But it only rules out a rate near 22% on that stimulus. It says little about a residual rate of 1%, and nothing about the short test where the bug was reported. Add the directed long-run test, the three old failing seeds, and a fresh sweep sized to the rate you want to rule out.

    Remember

    • First ask what the 500 runs were. 500 seeds is 500 different tests; one seed run 500 times is a nondeterminism question. They need different answers.

    • A rate from a few failures is wide: 3 in 500 is anywhere from 1 in 810 to 1 in 57 at 95%. Say the interval, not the point.

    • Prove a fix with enough clean runs to rule out the old rate: here 1,500 fresh clean seeds bound it below 0.20%, against 0.60% before.

    Rule of thumb: never call a test flaky until the same seed has passed and failed on the same commit and command.

    How this was checked

    dbglab at HEAD 49c5f04 (build-history.sh), 2026-10-18, in scratch copies: b4fix is HEAD with B4's two-line FILL reset fix (one bug left, B3); b34fix adds B3's fix, localparam int CW = 10;. dbglab itself is unchanged. tb/run.sh random <s> icarus +OPS=20 over seeds 1 to 500 in b4fix: 3 FAIL (seeds 320, 451, 487), Icarus Verilog 13.0, 25 s. Seed 451 gives the same line twice in Icarus and once in Verilator 5.048.

    dma_probe.sv (the debug-loop lesson's probe) compiled next to dbglab by probes/run-probe.sh on every seed: all 3 failing seeds contain a DMA run longer than 255 words, none of the 497 passing seeds does. Default length (+OPS unset) in b4fix, seeds 1 to 100: 22 FAIL; mean run length 278 cycles at +OPS=20 and 19,493 cycles at the default (seeds 1 to 100, b34fix). b34fix, +OPS=20, seeds 1 to 1500: 1500 PASS (64 s). Intervals from rate.py (Python 3, exact binomial).

    Limits: one bug in simulation, and the 1-in-500 framing comes from shortening the random test, not from a real nightly. The bound holds for this bench's stimulus weights only. Interview wording is illustrative.

    Keep going

    • Practice: Debugging rare seed failures in regression

    • Practice: Random stability: seeds and srandom

    • Practice: Cross-simulator reproducibility

    • Practice: Delta debugging a failing random test

    • Code lab: Seed plusarg

    • Code lab: Regression seed control

    • Interview: run a mock interview on this topic

    Related topics

    • Part 12 · Interview Prep

    • Part 8: intermittent failures

    • An intermittent on dbglab

    • Bisection across configurations and seeds

    • Part 9: fix, prove, prevent

    Previous

    105 / 107

    Next: How Do You Know Your Fix Works?

    Up next

    Up nextHow Do You Know Your Fix Works?

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Find the Bug in This Waveform
    • Mock Debug Interview