This course's DCRouter regressions taught a few speed lessons along the way. The constraints demonstration took 26 seconds of wall-clock time for 21,000 calls to randomize(), almost all of it waiting on the constraint solver; reduced to 4,500 calls it took 6 seconds and taught exactly the same thing (lesson 4.3). A bounded formal check of the full router took 3 seconds at depth 6 and over five minutes at depth 10 (lesson 7.2). Speed problems usually have a specific cause, and the cause decides the fix.
What makes simulation slow, and how do you speed up a slow regression?
The obvious response to a slow regression is more machines. That helps throughput if tests are independent, and does nothing for the longest test, the turnaround of a single failing run, or a test that is slow for a reason that more hardware cannot touch: a testbench doing expensive work every cycle, a waveform dump of every signal, a test running far longer than its question needs.
Lever | Examples | Typical effect |
|---|---|---|
Simulate less design | Block or subsystem instead of chip; stub or model neighbours; smaller configurations | Large: simulation cost grows with design size |
Do less work per cycle | No full waveform dumps by default; transaction-level testbench code; fewer per-cycle checks in Python or slow languages; avoid solver calls in inner loops | Often large: testbenches can cost more than the design |
Run fewer cycles per question | Shorter tests aimed at one question; backdoor setup for deep states (lesson 3.5); test modes for long timers | Large for long tests |
Run more questions in parallel | Independent tests on many machines; many seeds at once | Throughput only; no help for the longest single test |
Measure before optimising: a simulator profiler, or simply timing the same test with dumping off, checkers off, or the design stubbed, shows where the time goes.
Run | Where the time went | Fix |
|---|---|---|
Constraints demo (4.3) | Constraint solver called 21,000 times | 4,500 calls: same lesson, a quarter of the time |
Formal proof of DCRouter (7.2) | Search grows with depth | Depth 7 for the bounded check, induction for full proofs |
Bug Zoo runs (4.x to 6.9) | 25 independent builds and runs per testbench | Run in parallel across cores (bug-zoo.mjs --jobs) |
Waveforms for lessons | Dumping every signal | Dump only for the wave-generation build (the WAVE define) |
The question needs the whole chip and billions of cycles: OS boot, long software, end-to-end performance.
The design is too large to simulate the needed cycles in any reasonable time.
Then move platforms: emulation (lesson 10.3), FPGA prototyping (10.4), or virtual platforms and hybrids (10.5).
Practice | Purpose |
|---|---|
Regression profiling and per-test runtime budgets | Slow tests found and fixed, not tolerated |
Waveforms only on demand or for failing reruns | Most runs pay no dumping cost |
Block-level environments for block-level questions | Chip simulation reserved for chip questions |
Compile once, run many seeds | Build time paid once per regression |
A team (illustrative) inherited a nightly regression that no longer finished overnight and requested twice as many licences. Profiling showed that one scoreboard compared every transaction against a list by linear search, and the list grew without bound because matched entries were never removed. Fixing the scoreboard made the regression four times faster with no new licences.
A single test runs on one machine; parallelism only increases how many tests run at once.
It can do expensive work every cycle: unbounded searches, slow-language callbacks, solver calls, full waveform dumps.
Profile before optimising: slow simulation usually has a specific cause.
Simulate less design, do less work per cycle, run fewer cycles per question, then parallelise.
Move to hardware platforms only for questions that need billions of chip cycles.