Repository navigation
72 lines (63 loc) · 2.67 KB
/
Copy pathci-python-benchmark.yml
File metadata and controls
72 lines (63 loc) · 2.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# SPDX-License-Identifier: AGPL-3.0-or-later
# Commercial license available
# © Concepts 1996–2026 Miroslav Šotek. All rights reserved.
# © Code 2020–2026 Miroslav Šotek. All rights reserved.
# ORCID: 0009-0009-3560-0851
# Contact: www.anulum.li | protoscience@anulum.li
# SCPN Control — CI Python Benchmark Evidence.
name: CI / Python Benchmark Evidence
on:
workflow_call:
permissions: {}
env:
CARGO_TERM_COLOR: always
PYTHONPATH: ${{ github.workspace }}/src
jobs:
# ─── Job 9: Python phase-sync benchmark (DIII-D scale) ───
python-benchmark:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7
with:
python-version: "3.12"
- name: Install
run: pip install --require-hashes -r requirements/ci-deps.txt
- name: Kuramoto benchmark (DIII-D scale)
run: |
python - <<'PY'
import time
import numpy as np
from scpn_control.phase.kuramoto import kuramoto_sakaguchi_step
from scpn_control.phase.realtime_monitor import RealtimeMonitor
rng = np.random.default_rng(42)
# Single-step latency at DIII-D scale (N=1000, 4096)
for N in (1000, 4096):
theta = rng.uniform(-np.pi, np.pi, N)
omega = rng.normal(0, 0.3, N)
times = []
for _ in range(200):
t0 = time.perf_counter()
kuramoto_sakaguchi_step(theta, omega, dt=1e-3, K=2.0, zeta=0.5,
psi_driver=0.3, psi_mode="external")
times.append(time.perf_counter() - t0)
p50 = sorted(times)[len(times) // 2] * 1e3
print(f"N={N:>5d} P50={p50:.3f} ms")
assert p50 < 5.0, f"N={N} P50={p50:.3f} ms exceeds 5 ms budget"
# RealtimeMonitor tick (16 layers × 50 oscillators)
mon = RealtimeMonitor.from_paper27(L=16, N_per=50)
tick_times = []
for _ in range(100):
t0 = time.perf_counter()
mon.tick()
tick_times.append(time.perf_counter() - t0)
p50_tick = sorted(tick_times)[len(tick_times) // 2] * 1e6
print(f"RealtimeMonitor tick P50={p50_tick:.0f} µs")
assert p50_tick < 50_000, f"Tick P50={p50_tick:.0f} µs exceeds 50 ms budget"
print("All benchmark gates passed.")
PY
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: python-bench-results
path: "*.json"
if-no-files-found: ignore