#!/usr/bin/env python3 import json, os, subprocess, time, urllib.request ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) LAB = os.path.join(ROOT, "lab", "skip_meter") NIC = "以太网 2" def ps(cmd): return subprocess.check_output(["powershell","-NoProfile","-Command",cmd], text=True, encoding="utf-8", errors="replace").strip() def post(p, b=None): d = json.dumps(b or {}).encode() r = urllib.request.Request("http://127.0.0.1:8090"+p, data=d, headers={"Content-Type":"application/json"}) return json.loads(urllib.request.urlopen(r, timeout=8).read().decode()) def wait_ok(t=30): t0=time.time() while time.time()-t0=3: return h except Exception: pass time.sleep(0.4) return None def set_rt(): p=int(ps("(Get-Process ecat_native).Id")) ps(f"$p=Get-Process -Id {p}; $p.PriorityClass='RealTime'; $p.PriorityClass") return p def period(ms): post("/api/motor/stop"); time.sleep(0.12) post("/api/motor/period", {"period_ms": ms}); time.sleep(0.12) post("/api/motor/start") def quiet(sec=10): st=post("/api/motor/state"); dbg=post("/api/motor/dbg") c0,s0=st.get("cycles") or 0, dbg.get("skip_total") or 0 t0=time.time(); time.sleep(sec) st=post("/api/motor/state"); dbg=post("/api/motor/dbg") dt=time.time()-t0 c1,s1=st.get("cycles") or 0, dbg.get("skip_total") or 0 cu=st.get("cyc_us") or {} # also sample dbg ring k distribution ring=dbg.get("cyc") or [] ks=[r[5] for r in ring if len(r)>=6] works=[(r[4]-r[0])*1e6 for r in ring if len(r)>=5] sends=[(r[2]-r[1])*1e6 for r in ring if len(r)>=3] rxs=[(r[3]-r[2])*1e6 for r in ring if len(r)>=4] def pct(a,q): if not a: return None a=sorted(a); return round(a[int(q*(len(a)-1))],1) return { "pdo_hz": round((c1-c0)/dt,1), "late_per_s": round((s1-s0)/dt,2), "achieved_vs_4k": round(100*(c1-c0)/dt/4000,1), "cyc_us": cu, "ring_n": len(ring), "k_gt0": sum(1 for k in ks if k>0), "k_sum": sum(ks), "work_pct": {"p50":pct(works,.5),"p90":pct(works,.9),"p99":pct(works,.99),"max":pct(works,1.0) if works else None}, "send_pct": {"p50":pct(sends,.5),"p90":pct(sends,.9),"max":pct(sends,1.0) if sends else None}, "rx_pct": {"p50":pct(rxs,.5),"p90":pct(rxs,.9),"max":pct(rxs,1.0) if rxs else None}, } # set ITR 200 ps("Set-NetAdapterAdvancedProperty -Name '以太网 2' -RegistryKeyword '*InterruptModeration' -RegistryValue '1' -NoRestart") ps("Set-NetAdapterAdvancedProperty -Name '以太网 2' -RegistryKeyword 'ITR' -RegistryValue '200' -NoRestart") ps("Restart-NetAdapter -Name '以太网 2' -Confirm:$false") time.sleep(2) print("health", wait_ok()) set_rt() rows=[] for ms in (0.25, 0.5, 1.0): print(f"\n=== {ms} ms ITR=200 ===") period(ms) time.sleep(4) set_rt() r=quiet(10) print(json.dumps(r, ensure_ascii=False, indent=2)) rows.append(r) path=os.path.join(LAB, f"summary_itr200_periods_{int(time.time())}.json") json.dump(rows, open(path,"w",encoding="utf-8"), ensure_ascii=False, indent=2) print("WROTE", path)