Active core: rust (native pygx_core when rust). Median ns/op (testing/benchmarks/_bench.py auto-scaling timer); lower is better; — = no equivalent. Numbers are machine-specific (Apple Silicon here) — read ratios, not absolutes.
Regenerate: PYGX_CORE=rust .venv-coredev/bin/python testing/benchmarks/perf_report_bench.py
Notes: 8 fields + 4 kwargs adds 4 undeclared kwargs at construction. pygx Objects (topo=False and topo=True) and dataclass are typed/closed and reject undeclared kwargs by design, so construct / from-json show —; only pydantic (extra="allow") absorbs them. (Read-only ops for that shape run on the 8 declared fields.) symbolic children nests a 2-field object as a field. to/from-json is not identical work across columns: pygx emits a _type tag for round-trippable typed reconstruction (and dispatches on it when loading), whereas dataclass asdict / pydantic model_dump emit bare dicts — extra work attributed to pygx. Class-level utilities (register/load/save/...) and on_sym_* hooks are excluded (not per-instance ops).
Section A — all public operations (3 scalar fields)
Operation
topo=False
topo=True
dataclass
pydantic
Lifecycle (dataclass / pydantic analog)
construct (kwargs)
292.4 ns
282.7 ns
191.8 ns
522.3 ns
attr get
44.6 ns
44.5 ns
39.7 ns
45.4 ns
attr set
139.7 ns
138.6 ns
52.1 ns
142.6 ns
eq (==, same)
312.4 ns
391.3 ns
130.2 ns
288.3 ns
hash (frozen)
459.0 ns
445.3 ns
101.5 ns
113.2 ns
repr
558.8 ns
555.4 ns
306.3 ns
1.03 us
str
564.2 ns
560.5 ns
303.9 ns
909.9 ns
clone (shallow)
490.8 ns
515.7 ns
624.9 ns
592.0 ns
clone (deep)
914.6 ns
881.6 ns
2.27 us
1.62 us
to dict/json
388.6 ns
387.9 ns
631.0 ns
531.8 ns
to json str
2.22 us
2.19 us
1.51 us
596.8 ns
from dict/json
977.4 ns
981.9 ns
195.6 ns
656.2 ns
from json str
3.43 us
3.46 us
—
532.5 ns
Symbolic sym_* (no analog)
sym_clone
511.6 ns
528.2 ns
—
—
sym_rebind
887.2 ns
869.9 ns
—
—
sym_seal / unseal
91.3 ns
90.7 ns
—
—
sym_eq
80.7 ns
81.2 ns
—
—
sym_ne
110.6 ns
110.2 ns
—
—
sym_lt
1.20 us
1.22 us
—
—
sym_gt
1.43 us
1.46 us
—
—
sym_hash
403.1 ns
399.0 ns
—
—
sym_missing
566.2 ns
566.3 ns
—
—
sym_nondefault
2.14 us
2.13 us
—
—
sym_keys
226.7 ns
228.4 ns
—
—
sym_values
226.3 ns
226.3 ns
—
—
sym_items
248.6 ns
248.3 ns
—
—
sym_hasattr
168.3 ns
167.6 ns
—
—
sym_getattr
187.4 ns
186.8 ns
—
—
sym_get
445.5 ns
454.5 ns
—
—
sym_has
272.7 ns
275.8 ns
—
—
sym_contains
502.1 ns
494.8 ns
—
—
sym_jsonify
1.03 us
1.30 us
—
—
sym_descendants
1.10 us
1.11 us
—
—
sym_attr_field
172.5 ns
171.9 ns
—
—
format(compact)
403.0 ns
404.2 ns
—
—
query (pg.query)
5.99 us
6.07 us
—
—
Properties sym_* (no analog)
sym_partial
297.1 ns
298.7 ns
—
—
sym_abstract
495.3 ns
504.2 ns
—
—
sym_puresymbolic
178.8 ns
180.4 ns
—
—
sym_sealed
98.0 ns
97.9 ns
—
—
topo_root
—
197.5 ns
—
—
sym_origin
97.9 ns
97.6 ns
—
—
sym_init_args
1.14 us
1.19 us
—
—
topo_path
—
90.2 ns
—
—
topo_parent
—
90.7 ns
—
—
enable_topo
49.7 ns
49.7 ns
—
—
accessor_writable
97.5 ns
97.8 ns
—
—
allow_partial
97.8 ns
97.6 ns
—
—
is_deterministic
1.31 us
1.31 us
—
—
Section B — key operations across scales
construct
Shape
topo=False
topo=True
dataclass
pydantic
3 fields
289.6 ns
290.0 ns
201.6 ns
534.5 ns
4 fields
337.7 ns
335.0 ns
248.0 ns
593.1 ns
8 fields
512.7 ns
508.4 ns
528.9 ns
899.5 ns
16 fields
849.8 ns
860.7 ns
1.27 us
1.49 us
8 fields + 4 kwargs
—
—
—
1.22 us
container children
756.3 ns
821.9 ns
244.9 ns
785.0 ns
symbolic children
1.22 us
2.97 us
320.0 ns
853.7 ns
attr get
Shape
topo=False
topo=True
dataclass
pydantic
3 fields
39.0 ns
39.1 ns
34.9 ns
40.3 ns
4 fields
40.0 ns
40.3 ns
35.0 ns
41.1 ns
8 fields
39.4 ns
39.9 ns
34.8 ns
40.5 ns
16 fields
40.6 ns
40.0 ns
34.1 ns
41.5 ns
8 fields + 4 kwargs
40.8 ns
40.7 ns
35.4 ns
40.8 ns
container children
40.2 ns
39.6 ns
35.3 ns
40.8 ns
symbolic children
40.1 ns
41.0 ns
35.8 ns
42.1 ns
eq
Shape
topo=False
topo=True
dataclass
pydantic
3 fields
302.0 ns
384.7 ns
119.8 ns
283.9 ns
4 fields
315.2 ns
431.5 ns
141.0 ns
292.4 ns
8 fields
342.9 ns
597.0 ns
232.3 ns
316.1 ns
16 fields
387.0 ns
938.3 ns
429.7 ns
363.5 ns
8 fields + 4 kwargs
349.0 ns
607.1 ns
240.8 ns
323.5 ns
container children
536.1 ns
539.0 ns
176.9 ns
328.5 ns
symbolic children
949.2 ns
975.3 ns
220.3 ns
607.2 ns
clone
Shape
topo=False
topo=True
dataclass
pydantic
3 fields
488.6 ns
520.0 ns
634.2 ns
595.5 ns
4 fields
507.0 ns
548.8 ns
664.5 ns
602.7 ns
8 fields
542.5 ns
616.0 ns
679.9 ns
645.5 ns
16 fields
591.2 ns
724.4 ns
802.8 ns
748.5 ns
8 fields + 4 kwargs
552.6 ns
619.7 ns
711.6 ns
641.5 ns
container children
545.5 ns
571.2 ns
686.2 ns
647.6 ns
symbolic children
533.1 ns
3.78 us
676.3 ns
617.2 ns
clone/deep
Shape
topo=False
topo=True
dataclass
pydantic
3 fields
888.9 ns
884.7 ns
2.20 us
1.64 us
4 fields
971.4 ns
971.0 ns
2.51 us
1.88 us
8 fields
1.31 us
1.31 us
3.52 us
2.84 us
16 fields
1.98 us
1.97 us
5.47 us
4.77 us
8 fields + 4 kwargs
1.37 us
1.35 us
3.50 us
3.20 us
container children
4.24 us
4.30 us
4.58 us
3.92 us
symbolic children
2.46 us
3.88 us
4.55 us
3.43 us
to json
Shape
topo=False
topo=True
dataclass
pydantic
3 fields
391.9 ns
394.4 ns
647.3 ns
530.0 ns
4 fields
415.7 ns
429.8 ns
752.1 ns
571.3 ns
8 fields
538.9 ns
638.3 ns
1.17 us
730.3 ns
16 fields
770.3 ns
1.05 us
2.08 us
1.07 us
8 fields + 4 kwargs
541.4 ns
639.7 ns
1.19 us
768.5 ns
container children
668.8 ns
10.17 us
1.74 us
827.6 ns
symbolic children
2.30 us
647.2 ns
1.22 us
708.0 ns
from json
Shape
topo=False
topo=True
dataclass
pydantic
3 fields
978.4 ns
969.8 ns
207.7 ns
648.2 ns
4 fields
1.12 us
1.13 us
256.1 ns
709.5 ns
8 fields
1.61 us
1.59 us
537.5 ns
987.4 ns
16 fields
2.48 us
2.49 us
1.30 us
1.43 us
8 fields + 4 kwargs
—
—
—
1.18 us
container children
1.77 us
1.86 us
244.9 ns
924.6 ns
symbolic children
1.98 us
3.66 us
310.7 ns
968.2 ns