graph LR HG["Hypergraph\nmodules + nets"] INIT["Initial partition"] FM["FM refinement\nmove vertices"] OUT["Optimized partition"] HG --> INIT INIT --> FM FM --> OUT style HG fill:#e3f2fd,stroke:#1565c0,stroke-width:3px style INIT fill:#fff9c4,stroke:#f57f17,stroke-width:3px style FM fill:#c8e6c9,stroke:#2e7d32,stroke-width:3px style OUT fill:#d1c4e9,stroke:#6a1b9a,stroke-width:3px
graph LR V["move v"] --> N1["net e1"] V --> N2["net e2"] N1 --> P["pins of e1"] N2 --> Q["pins of e2"] P --> K["modify_key"] Q --> K style V fill:#e3f2fd,stroke:#1565c0,stroke-width:3px style N1 fill:#fff9c4,stroke:#f57f17,stroke-width:3px style N2 fill:#fff9c4,stroke:#f57f17,stroke-width:3px style P fill:#f8bbd0,stroke:#c2185b,stroke-width:3px style Q fill:#f8bbd0,stroke:#c2185b,stroke-width:3px style K fill:#c8e6c9,stroke:#2e7d32,stroke-width:3px
cProfile hot spots on ibm03 (tottime) FMBiGainMgr.modify_key 10.4 s FMGainMgr._update_move_net 9.6 s FMGainMgr.update_move 7.1 s FMBiGainCalc.init_idx_vec 6.8 s networkx coreviews.__getitem__ 5.2 s FMBiGainCalc.update_move_general_net 6.6 s The seconds hide in wrapper frames and no-op work, not in the algorithm.
graph TD subgraph AFTER["After"] A1["vertex_list[w]"] --> A2["list index"] A3["net_pins[net]"] --> A4["plain dict"] end subgraph BEFORE["Before"] B1["vertex_list[w]"] --> B2["MapAdapter\n__getitem__"] --> B3["list.__getitem__"] B4["ugraph[net]"] --> B5["AtlasView\n__getitem__"] --> B6["dict lookup"] end style B1 fill:#f8bbd0,stroke:#c2185b,stroke-width:3px style B2 fill:#f8bbd0,stroke:#c2185b,stroke-width:3px style B3 fill:#f8bbd0,stroke:#c2185b,stroke-width:3px style B4 fill:#f8bbd0,stroke:#c2185b,stroke-width:3px style B5 fill:#f8bbd0,stroke:#c2185b,stroke-width:3px style B6 fill:#f8bbd0,stroke:#c2185b,stroke-width:3px style A1 fill:#c8e6c9,stroke:#2e7d32,stroke-width:3px style A2 fill:#c8e6c9,stroke:#2e7d32,stroke-width:3px style A3 fill:#c8e6c9,stroke:#2e7d32,stroke-width:3px style A4 fill:#c8e6c9,stroke:#2e7d32,stroke-width:3px
Before (red) vs After (green) Β· bench_fm.py p1.json 299.0 ms 215.9 ms Β· 1.38Γ ibm03 14.64 s 8.83 s Β· 1.66Γ Total calls 77.9 M β 42.9 M Β· modify_key 7.37 M β 374 K MapAdapter and networkx view frames are gone from the top-25.
graph LR PY["ckpttnpy\nPython reference"] CPP["ckpttn-cpp\nC++20 Β· CMake + xmake"] RS["ckpttn-rs\nRust Β· cargo"] PY -.->|"same algorithm"| CPP PY -.->|"same algorithm"| RS style PY fill:#e3f2fd,stroke:#1565c0,stroke-width:3px style CPP fill:#c8e6c9,stroke:#2e7d32,stroke-width:3px style RS fill:#ffe0b2,stroke:#e65100,stroke-width:3px
graph LR OLD["new vector\nper call β"] --> FIX["member buffer\nreused β "] FIX --> SPAN["std::span\nview, no copy β "] style OLD fill:#f8bbd0,stroke:#c2185b,stroke-width:3px style FIX fill:#c8e6c9,stroke:#2e7d32,stroke-width:3px style SPAN fill:#c8e6c9,stroke:#2e7d32,stroke-width:3px
nanobench Β· before (red) vs after (green) p1 Β· 2-pin 3.37 ms 2.67 ms Β· β21% p1 Β· no 2-pin 3.93 ms 2.99 ms Β· β24% k-way ibm03 2494 ms 1186 ms Β· β52% k-way Β· no 2-pin 2844 ms 1248 ms Β· β56%
criterion Β· before (red) vs after (green) ibm03 Β· 2-pin 1.557 s 1.107 s Β· β29% ibm03 Β· no 2-pin 1.550 s 1.119 s Β· β28% p1 Β· 2-pin 49.9 ms 35.6 ms Β· β29% p1 Β· no 2-pin 50.4 ms 36.0 ms Β· β29%
graph LR Q["Where is the time?"] Q -->|"Python"| PY["per-call wrapper\n& no-op work β "] Q -->|"C++"| CPP["per-call heap\nallocations β "] Q -->|"Rust"| RS["per-call clone\n& collect β "] style Q fill:#e3f2fd,stroke:#1565c0,stroke-width:3px style PY fill:#c8e6c9,stroke:#2e7d32,stroke-width:3px style CPP fill:#c8e6c9,stroke:#2e7d32,stroke-width:3px style RS fill:#c8e6c9,stroke:#2e7d32,stroke-width:3px