dagron

Benchmarks

Performance benchmarks comparing dagron's Rust core against NetworkX on common DAG operations.

dagron's core graph engine is written in Rust (petgraph + PyO3), giving it a significant performance advantage over pure-Python graph libraries. This page presents representative benchmarks comparing dagron against NetworkX on equivalent operations.

Reproduce these results yourself

uv pip install pytest-benchmark networkx
uv run python -m pytest tests/python/test_benchmarks.py --benchmark-only --benchmark-columns=mean,stddev,rounds -q

All Python benchmarks below were measured with pytest-benchmark on a single machine. Rust-only benchmarks use Criterion. Numbers will vary by hardware — treat ratios as the meaningful signal.

Hardware: AMD Ryzen / Intel Core (modern x86_64), Linux, Python 3.12, dagron 0.1.0. Last measured: March 2026.


dagron vs NetworkX (Python API)

Construction (10K nodes)

BenchmarkdagronNetworkXSpeedup
Chain (10K nodes, 9,999 edges)7.66 ms21.04 ms2.7x
Wide (1,000 roots x 10 depth)7.05 ms22.45 ms3.2x

Topological Sort (10K-node chain)

BenchmarkdagronNetworkXSpeedup
Topological sort880 us6,668 us7.6x

Ancestors / Descendants (mid-node on 10K chain)

BenchmarkdagronNetworkXSpeedup
Ancestors of node 5000562 us1,955 us3.5x
Descendants of node 5000548 us2,053 us3.7x

Cycle Detection / Validation (10K chain)

BenchmarkdagronNetworkXSpeedup
Validate (acyclic check)535 us6,718 us12.6x

JSON Serialization (1K-node chain)

BenchmarkdagronNetworkXSpeedup
Serialize to JSON258 us823 us3.2x

Reachability (5K-node chain)

BenchmarkdagronNetworkX
Build reachability index1,818 usN/A (no equivalent)
Batch query (10 pairs)3.2 us12,637 us (nx.has_path)

Once the reachability index is built, dagron answers batch reachability queries ~3,900x faster than NetworkX's has_path (which re-traverses the graph each call).

BFS / Topological Levels (10K chain)

BenchmarkdagronNetworkXSpeedup
Topological levels2,045 us9,312 us4.6x

Why the performance gap?

Three factors drive dagron's advantage:

  1. Rust core releases the GIL. Every expensive operation in dagron runs inside py.allow_threads(), so the Rust code executes without Python interpreter overhead.
  2. petgraph's adjacency list is cache-friendly. Nodes and edges are stored in contiguous arena-allocated vectors, giving excellent CPU cache behavior during traversals.
  3. ahash beats Python dict overhead. Node name lookups use AHashMap — a fast, non-cryptographic hash map — instead of Python's general-purpose dict.

Rust-Only Numbers (Criterion)

These benchmarks run entirely in Rust, showing the pure performance ceiling before any PyO3 overhead.

Construction

BenchmarkTime
Chain 1K252 us
Chain 10K2.73 ms
Chain 100K48.6 ms
Wide 1,000x102.96 ms
Diamond 10x10111 us

Topological Sort (10K nodes)

BenchmarkTime
Kahn (chain)332 us
Kahn (wide)332 us
DFS (chain)336 us
DFS (wide)337 us
Levels (chain)617 us
Levels (wide)331 us

Cycle Detection (10K chain)

BenchmarkTime
validate (acyclic)466 us
would_create_cycle501 us

Reachability (10K chain)

BenchmarkTime
Build index3.26 ms
can_reach (single query)6.8 ns
reachable_from11.5 us
ancestors_of27.4 us

Serialization

BenchmarkTime
to_json (1K)241 us
from_json (1K)481 us
to_bincode (1K)57.9 us
from_bincode (1K)305 us
to_bincode (10K)617 us
from_bincode (10K)3.30 ms
to_bincode (100K)6.60 ms
to_dot (1K)48.0 us

Scheduling (1K chain)

BenchmarkTime
Max parallelism plan281 us
Resource-constrained (4 workers)450 us
Critical path133 us

Transforms (1K chain)

BenchmarkTime
Transitive reduction268 us
Snapshot (deep clone)70 us

Introspection (10K chain)

BenchmarkTime
Ancestors (mid-node)273 us
Descendants (mid-node)274 us
Roots37 ns
Leaves39 ns

Run Rust benchmarks

cargo bench --bench graph_bench

On this page