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)
295.0 ns
283.6 ns
194.5 ns
520.4 ns
attr get
44.6 ns
45.1 ns
39.5 ns
45.2 ns
attr set
136.6 ns
138.5 ns
52.1 ns
142.0 ns
eq (==, same)
314.3 ns
393.7 ns
134.0 ns
295.6 ns
hash (frozen)
457.2 ns
456.5 ns
96.4 ns
109.2 ns
repr
574.5 ns
581.6 ns
324.0 ns
1.08 us
str
581.8 ns
591.7 ns
323.8 ns
937.6 ns
clone (shallow)
507.0 ns
540.9 ns
647.7 ns
599.2 ns
clone (deep)
954.5 ns
963.8 ns
2.31 us
1.73 us
to dict/json
409.5 ns
393.8 ns
631.0 ns
526.9 ns
to json str
2.27 us
2.28 us
1.51 us
609.8 ns
from dict/json
990.3 ns
1.03 us
197.9 ns
669.8 ns
from json str
3.58 us
3.53 us
—
535.4 ns
Symbolic sym_* (no analog)
sym_clone
527.7 ns
566.0 ns
—
—
sym_rebind
911.7 ns
880.0 ns
—
—
sym_seal / unseal
91.6 ns
91.6 ns
—
—
sym_eq
83.1 ns
83.0 ns
—
—
sym_ne
114.9 ns
113.7 ns
—
—
sym_lt
1.22 us
1.24 us
—
—
sym_gt
1.45 us
1.45 us
—
—
sym_hash
390.6 ns
394.9 ns
—
—
sym_missing
575.0 ns
578.3 ns
—
—
sym_nondefault
2.06 us
2.07 us
—
—
sym_keys
232.8 ns
233.3 ns
—
—
sym_values
231.8 ns
232.4 ns
—
—
sym_items
257.8 ns
256.7 ns
—
—
sym_hasattr
169.5 ns
167.0 ns
—
—
sym_getattr
185.2 ns
186.3 ns
—
—
sym_get
444.5 ns
446.3 ns
—
—
sym_has
277.4 ns
283.6 ns
—
—
sym_contains
508.1 ns
516.0 ns
—
—
sym_jsonify
1.03 us
1.30 us
—
—
sym_descendants
1.10 us
1.11 us
—
—
sym_attr_field
172.2 ns
175.2 ns
—
—
format(compact)
407.9 ns
405.3 ns
—
—
query (pg.query)
6.07 us
6.17 us
—
—
Properties sym_* (no analog)
sym_partial
315.5 ns
308.6 ns
—
—
sym_abstract
516.3 ns
515.5 ns
—
—
sym_puresymbolic
184.5 ns
184.7 ns
—
—
sym_sealed
97.8 ns
97.3 ns
—
—
topo_root
—
199.0 ns
—
—
sym_origin
97.6 ns
97.0 ns
—
—
sym_init_args
1.15 us
1.22 us
—
—
topo_path
—
91.1 ns
—
—
topo_parent
—
92.7 ns
—
—
enable_topo
51.1 ns
52.0 ns
—
—
accessor_writable
98.4 ns
98.6 ns
—
—
allow_partial
98.2 ns
97.7 ns
—
—
is_deterministic
1.29 us
1.29 us
—
—
Section B — key operations across scales
construct
Shape
topo=False
topo=True
dataclass
pydantic
3 fields
289.5 ns
285.7 ns
195.7 ns
518.2 ns
4 fields
329.6 ns
319.8 ns
246.8 ns
570.2 ns
8 fields
500.4 ns
499.1 ns
531.5 ns
877.1 ns
16 fields
840.0 ns
847.4 ns
1.26 us
1.44 us
8 fields + 4 kwargs
—
—
—
1.13 us
container children
742.7 ns
804.1 ns
233.7 ns
775.4 ns
symbolic children
1.24 us
2.79 us
299.3 ns
821.1 ns
attr get
Shape
topo=False
topo=True
dataclass
pydantic
3 fields
39.3 ns
39.1 ns
33.9 ns
39.5 ns
4 fields
39.1 ns
39.1 ns
34.3 ns
40.1 ns
8 fields
38.9 ns
39.2 ns
34.1 ns
39.9 ns
16 fields
39.5 ns
39.3 ns
34.0 ns
40.1 ns
8 fields + 4 kwargs
39.5 ns
40.3 ns
34.4 ns
39.9 ns
container children
39.1 ns
39.4 ns
34.1 ns
39.9 ns
symbolic children
39.5 ns
39.4 ns
34.2 ns
40.1 ns
eq
Shape
topo=False
topo=True
dataclass
pydantic
3 fields
297.7 ns
380.6 ns
117.5 ns
280.0 ns
4 fields
311.6 ns
433.9 ns
142.1 ns
289.8 ns
8 fields
326.7 ns
584.2 ns
239.0 ns
309.1 ns
16 fields
382.3 ns
932.0 ns
429.1 ns
364.1 ns
8 fields + 4 kwargs
333.2 ns
593.9 ns
238.0 ns
318.7 ns
container children
522.9 ns
518.4 ns
169.4 ns
325.0 ns
symbolic children
921.2 ns
971.6 ns
221.1 ns
598.4 ns
clone
Shape
topo=False
topo=True
dataclass
pydantic
3 fields
511.1 ns
525.0 ns
610.7 ns
592.2 ns
4 fields
525.4 ns
540.9 ns
665.4 ns
600.7 ns
8 fields
549.5 ns
605.8 ns
675.1 ns
638.6 ns
16 fields
591.4 ns
712.8 ns
765.7 ns
715.2 ns
8 fields + 4 kwargs
567.8 ns
623.6 ns
703.3 ns
632.5 ns
container children
555.4 ns
563.9 ns
662.4 ns
622.9 ns
symbolic children
545.2 ns
3.75 us
637.8 ns
600.3 ns
clone/deep
Shape
topo=False
topo=True
dataclass
pydantic
3 fields
905.4 ns
906.4 ns
2.19 us
1.65 us
4 fields
994.9 ns
985.2 ns
2.49 us
1.83 us
8 fields
1.34 us
1.33 us
3.50 us
2.85 us
16 fields
1.95 us
1.94 us
5.27 us
4.70 us
8 fields + 4 kwargs
1.32 us
1.32 us
3.39 us
3.05 us
container children
4.20 us
4.23 us
4.40 us
3.87 us
symbolic children
2.49 us
3.82 us
4.29 us
3.38 us
to json
Shape
topo=False
topo=True
dataclass
pydantic
3 fields
399.1 ns
384.3 ns
631.7 ns
525.5 ns
4 fields
425.6 ns
425.8 ns
733.3 ns
559.3 ns
8 fields
528.5 ns
622.3 ns
1.18 us
720.2 ns
16 fields
773.8 ns
1.02 us
2.05 us
1.04 us
8 fields + 4 kwargs
530.3 ns
619.3 ns
1.18 us
740.7 ns
container children
672.4 ns
9.69 us
1.66 us
796.8 ns
symbolic children
2.25 us
634.9 ns
1.19 us
686.5 ns
from json
Shape
topo=False
topo=True
dataclass
pydantic
3 fields
978.3 ns
1.01 us
200.9 ns
666.7 ns
4 fields
1.17 us
1.13 us
247.6 ns
701.3 ns
8 fields
1.58 us
1.56 us
529.8 ns
967.8 ns
16 fields
2.49 us
2.46 us
1.28 us
1.41 us
8 fields + 4 kwargs
—
—
—
1.15 us
container children
1.77 us
1.84 us
234.3 ns
897.7 ns
symbolic children
2.04 us
3.70 us
299.7 ns
963.5 ns