pcb · routing · placement · evals

We benchmarked a new open-source router against ours. It won, so we added it.

2026-10-05 · Dan Newcome

Yesterday we scored our routers on 119 real boards and called 78% on the small ones close to the state of the art. A newly published router does better than that, on our machine, with our judge. TraceMaker is a new open-source autorouter for KiCad, written in C++ with CUDA, built largely by coding agents. We ran it on the same boards.

Three bar charts of clean-pass rate, for 99 small, 10 medium and 10 large boards. Designer's own routing 1.00, 1.00, 0.90. circuit-skills best of backends 1.00, 1.00, 0.90. TraceMaker 0.99, 1.00, 0.90. Freerouting 2.1.0 0.87, 0.80, 0.30. Freerouting 2.2.4 0.73, 0.60, 0.30. tscircuit capacity autorouter 0.21, 0.00, 0.00. circuit-skills a day earlier 0.78, 0.70, 0.20.

01 / The comparison

The benchmark is the one from yesterday's post: PCBWorld's D3 set of real open-source boards. Each board keeps its designer's placement and has its routing stripped. A result counts as a clean pass only if it comes back fully connected with zero error-level KiCad DRC violations under the board's own rules.

TraceMaker built from source in 22 seconds. Its CUDA build targets its author's two older Tesla cards; one CMake setting retargets it to an RTX 4070. The GPU only speeds up its cost fields: on the board we checked, GPU and CPU builds wrote byte-identical files. Every run below used its default 8-variant portfolio with a 60-second limit, and was scored by the same stock KiCad 9 DRC as our own backends.

SplitTraceMakercircuit-skills, a day earlierFreerouting 2.2.4
D3-A, 99 small0.990.780.75
D3-B, 10 medium1.000.700.70
D3-C, 10 large0.900.200.20

Board by board, it was clean on 32 boards where we were not. We were clean on one where it was not, a pogo-pin adapter where it reported three pins boxed in. It added zero DRC errors on all 119 boards, including the ones it did not finish. On small boards it was also faster: a median of 0.6 seconds against our 5.9. On boards both routed clean, its tracks were 5–7% shorter, with about twice the vias on the larger boards.

One caution about these numbers. PCBWorld's boards come from PCBench, which is the set TraceMaker was developed against, so some of them may be boards it was tuned on. Its own held-out figure, on 60 harder boards, is 73–78% clean.

02 / Why it wins

This benchmark hands every router a finished placement, so none of our placement work gets used. What is left is pure routing, and there we were only as good as the two routers we wrap. Both lose for plain reasons:

TraceMaker avoids all three. It reads the KiCad board and rules directly. It checks every segment against exact geometry before it commits it. And when a connection is blocked it rips up and renegotiates. On the medium board we looked at closely, all eight of its variants routed every connection in a single pass with no rip-ups at all. On this evidence the boards are within reach of a router that checks its own work, and ours were leaving them unfinished.

03 / How it was built

Nothing in TraceMaker is a new algorithm. Its repository is worth reading for how the work was set up:

It also changes how we read yesterday's result. We measured ourselves against Freerouting and called that close to the state of the art; on these boards, at least, there was more room above it than we assumed.

04 / So we plugged it in

Our harness, route_eval, runs every available router on a board, scores each result the same way and keeps the best. Adding a router is one branch. We added two: tracemaker, and freerouting:2.1.0, the older Freerouting release that keeps optimizing where 2.2.4 stops.

SplitBest of all backendsTraceMakerFreerouting 2.1.0Freerouting 2.2.4tscircuit
D3-A, 99 small1.000.990.870.730.21
D3-B, 10 medium1.001.000.800.600.00
D3-C, 10 large0.900.900.300.300.00

The tenth large board is the one its own designer left incomplete, so 0.90 is the ceiling there.

The routers are not redundant. On the small boards the kept candidate came from TraceMaker 63 times, Freerouting 2.1.0 19 times, Freerouting 2.2.4 13 times and the tscircuit router 4 times. The one board TraceMaker could not finish, another router did. Running several and keeping the best is still the right shape; it just needed a better router in it.

The cost is time. The full pass on a small board went from 7 seconds to 13, and on the large boards it now takes minutes, because every router that cannot finish runs out its clock.

05 / Take the parts off

All of that is routing on a placement a person made. The harder question is the one before it. We took the ten medium boards, stripped the routing, pulled every part that carries a net off its position, and asked a placer to put them back. Then we routed the result with three routers and kept the best.

Two bar charts for ten medium boards placed from scratch. Clean pass: designer's placement 1.00, TraceMaker's placer 0.50, our annealer and untangle at part level 0.10, TraceMaker's placer with the tscircuit router 0.00. Connections routed: designer 1.00, TraceMaker's placer 0.85, ours 0.94, TraceMaker's placer with the tscircuit router 0.60.

Ten boards is a small sample. The gap to the designers is not small: every one of their placements routes clean.

06 / What we were missing

  1. We don't own a legality model. We connect routers through adapters that lose rules, and find out from KiCad afterwards.
  2. Our benchmark is new and gates nothing. We run it by hand. TraceMaker's gated every change from its first commit.
  3. We optimise a proxy. Our placement score predicts whether a board will route weakly: it gets the ordering right 48–66% of the time. TraceMaker's loop optimises the real outcome.
  4. We have no legal placer for a bare KiCad board.

We are not going to write a router. TraceMaker is a better one than we would build, it is GPL-3.0, and it now runs inside our harness as a separate program. What we take from it is the method, pointed at the part nobody is good at yet: placement, and the loop between placement and routing. Half of TraceMaker's failed placements fail on a handful of boxed-in pins, the kind a small local move would free.

07 / A corpus with real rules

PCBench's boards are KiCad 5 files with no project file, so every one is judged against KiCad's default rules. For placement work we want current designs with their own rules, so we started a second corpus from GitHub. It has 235 boards from 170 repositories under open-hardware and permissive licences, each pinned to a commit, with its licence recorded. 178 are two-layer and 57 four-layer.

A board qualifies if it opens in KiCad 9, has a project file beside it, and its designer's routing leaves nothing open. Only 77 of the 235 have zero DRC errors as their designers shipped them, so those 77 are the set where a clean pass is a fair bar. The boards are published as punkfab/pcb-corpus: each one as its designer shipped it and as an unrouted copy, with its project rules, its source commit and its own licence file.

08 / Update: the tscircuit router, the placement score and the corpus

Three follow-ups from the same day.

The tscircuit router's errors are its own, and they can be repaired from outside. We checked its returned traces against the exact geometry we hand it, with KiCad out of the loop. On 40 small boards the two agree closely: 107 segments narrower than the minimum we set, and about 180 places where a trace overlaps or crowds another net. The narrow segments are all exactly 0.1 mm, whatever the board's rule. So we wrapped it instead of patching it. A new backend, srj-legal, lets it route, deletes every track KiCad's DRC objects to, and has TraceMaker re-route only those connections against the board's rules.

Splittscircuit alonetscircuit + legal finishTraceMaker alone
D3-A, 99 small0.210.980.99
D3-B, 10 medium0.001.001.00

A median of 86% of its tracks and vias survive on the small boards and 61% on the medium ones. It matches TraceMaker alone on these splits; it does not beat it. The large split had not finished when this was written.

The placement score now has measured weights. We placed each of 64 corpus boards five ways (the designer's placement, two degraded copies of it, our placer and TraceMaker's), routed every one, and asked which measures rank the better-routing placement first. Peak congestion, the measure we leaned on, gets it right 72% of the time. Between two legal placements it is one of the weakest measures we have (62%), and ratsnest crossings per net is the strongest (85%). A combined score fitted on those outcomes gets 79% on boards held out of the fit, and is now what placement_score.py reports for comparing placements of one board.

Corrected 2026-10-05. This paragraph first reported 79%, 90% and 89% for those three figures. A bug in our placer left copper pours in its output, which made its placements look far worse to the router than they were, and the fit used those results. The numbers above are from the re-run.

The corpus is public and grouped. punkfab/pcb-corpus now describes every board (size, density, stackup, packages, rules, what is on it) and sorts the 235 into overlapping groups. Difficulty is measured: routed by TraceMaker with a 30-second budget, 48 boards come back clean, 101 are at least 98% connected but not clean, and 86 are left more open than that. Through-hole and single-sided boards are the easy end. Fine-pitch, four-layer and FPGA boards are the hard end.

09 / Caveats

Everything is in punkfab/circuit-skills: the new backends in route_eval, a runner that scores any external router beside a stored run, the unplaced-board harness, the corpus collector and every result. Thanks to TraceMaker's author for publishing something this easy to build and check. Have a board that needs placing or routing? Start a project →