Skip to content

Reduce Dagre ranking traversals and adjacency allocations - #4

Merged
alixander merged 1 commit into
mainfrom
agent/perf2-adjacency
Sep 7, 2026
Merged

alixander merged 1 commit into
mainfrom
agent/perf2-adjacency

Conversation

@alixander

@alixander alixander commented Sep 7, 2026 •

Copy link
Copy Markdown
Contributor

Human


AI

Ranking repeatedly copied adjacency lists and traversed the same tree to compute cut values and update ranks. Reuse traversal buffers, record preorder/postorder during the existing low/lim walk, and enumerate immutable adjacency maps directly.

This preserves ranking arithmetic, iteration order, tie comparisons, solver termination and public slice ownership. It also avoids sorting canonical edge keys, validates direct tree-edge lookups, and keeps the UTF-16 fallback for non-ASCII IDs.

Benchmarks

D2's Dagre layout phase on existing real-world fixtures, including adapter work but excluding compilation, themes and text measurement:

Diagram Before After Speedup Allocated bytes
TPMJS 135.92 ms 81.76 ms 1.66× 100.86 → 52.20 MB
Spyre 19.57 ms 17.39 ms 1.13× 19.21 → 16.72 MB
Queue workers 7.73 ms 6.96 ms 1.11× 7.47 → 6.27 MB

Apple M4, Go 1.27.0, GOMAXPROCS=1; six alternating baseline/candidate process pairs after warmup, ten layout iterations per fixture per process. Ratios divide variant medians. Baseline is v0.2.0 (36cc8dbe); candidate is 1b61d9e. Fulcro's longer 100-iteration followup was effectively unchanged (4.85 → 4.81 ms); Mocha showed no material timing change. Allocation bytes are cumulative traffic, not peak memory. These are local measurements, not universal speedups.

Validation

  • Full Go tests, race checks and vet passed locally.
  • 1,320 frozen layouts matched byte-for-byte: 311 captured D2 inputs, nine focused cases and 1,000 seeded compound graphs.
  • A separate traversal oracle checked 241 individual exchanges across 100 weighted DAGs, including exact ranks, cuts, low/lim labels and iteration order.
  • Added tests for adjacency ownership/order, self-loops, named multiedges, empty/numeric/Unicode IDs, delimiter collisions and differing ranking roots.
  • Combined D2 changes preserved all 672 E2E output hashes without changing goldens.

The accompanying D2 PR, d2lang/d2#2880, adds BenchmarkDagreRealWorld and consumes Dagro v0.2.1. Reproduce there with GOMAXPROCS=1 go test ./d2layouts/d2dagrelayout -run '^$' -bench '^BenchmarkDagreRealWorld$' -benchmem -benchtime=10x.

@alixander
alixander merged commit b53832c into main Sep 7, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant