98 lines
3.1 KiB
Python
98 lines
3.1 KiB
Python
"""_throughput_probe.py — pre-flight test for inject_continuous_stream.
|
|
Verifies the lattice daemon can handle 10 injects/sec without packet loss
|
|
or telemetry starvation. Throwaway script, safe to delete after running."""
|
|
import zmq, json, time, threading
|
|
from collections import deque
|
|
|
|
TEL = "tcp://127.0.0.1:5556"
|
|
CMD = "tcp://127.0.0.1:5557"
|
|
ctx = zmq.Context.instance()
|
|
|
|
sub = ctx.socket(zmq.SUB); sub.connect(TEL); sub.setsockopt(zmq.SUBSCRIBE, b"")
|
|
sub.setsockopt(zmq.RCVHWM, 20000)
|
|
buf = deque(maxlen=20000)
|
|
stop = False
|
|
|
|
def reader():
|
|
while not stop:
|
|
if sub.poll(100):
|
|
try:
|
|
buf.append((time.time(), json.loads(sub.recv_string())))
|
|
except Exception:
|
|
pass
|
|
|
|
t = threading.Thread(target=reader, daemon=True); t.start()
|
|
|
|
pub = ctx.socket(zmq.PUB); pub.connect(CMD)
|
|
time.sleep(0.8)
|
|
|
|
# baseline
|
|
t0 = time.time()
|
|
time.sleep(3.0)
|
|
baseline = [x for x in list(buf) if x[0] >= t0]
|
|
print(f"baseline: {len(baseline)} msgs in 3s = {len(baseline)/3:.1f} msg/s")
|
|
buf.clear()
|
|
|
|
# burst test: 100 injects at 100ms = 10/s for 10s
|
|
N, SPACING = 100, 0.1
|
|
t_burst_start = time.time()
|
|
for i in range(N):
|
|
payload = {"cmd": "inject_density", "x": 512.0, "y": 512.0,
|
|
"sigma": 32.0, "strength": 0.05}
|
|
pub.send_string(json.dumps(payload))
|
|
next_t = t_burst_start + (i + 1) * SPACING
|
|
dt = next_t - time.time()
|
|
if dt > 0:
|
|
time.sleep(dt)
|
|
t_burst_end = time.time()
|
|
|
|
time.sleep(2.0)
|
|
stop = True
|
|
t.join(timeout=1)
|
|
|
|
recv = [x for x in list(buf) if x[0] >= t_burst_start]
|
|
elapsed = t_burst_end - t_burst_start
|
|
print(f"burst: sent {N} in {elapsed:.3f}s (target 10.0s) send_rate={N/elapsed:.2f}/s")
|
|
if recv:
|
|
span = recv[-1][0] - recv[0][0]
|
|
rate = len(recv) / span if span > 0 else 0
|
|
asyms = [m["asymmetry"] for _, m in recv]
|
|
print(f"telemetry during+after burst: {len(recv)} msgs over {span:.2f}s = {rate:.1f} msg/s")
|
|
print(f"asym range: {min(asyms):.3f} .. {max(asyms):.3f} mean={sum(asyms)/len(asyms):.3f}")
|
|
print(f" (baseline asym was ~42, large change here = injections landed)")
|
|
else:
|
|
print("WARN: no telemetry after burst")
|
|
|
|
# higher-stress test: 50 injects at 50ms = 20/s for 2.5s
|
|
print("")
|
|
print("=== STRESS: 20 injects/sec ===")
|
|
buf.clear()
|
|
t_burst_start = time.time()
|
|
stop = False
|
|
t = threading.Thread(target=reader, daemon=True); t.start()
|
|
N2, SP2 = 50, 0.05
|
|
for i in range(N2):
|
|
payload = {"cmd": "inject_density", "x": 512.0, "y": 512.0,
|
|
"sigma": 32.0, "strength": 0.05}
|
|
pub.send_string(json.dumps(payload))
|
|
next_t = t_burst_start + (i + 1) * SP2
|
|
dt = next_t - time.time()
|
|
if dt > 0:
|
|
time.sleep(dt)
|
|
t_burst_end = time.time()
|
|
time.sleep(2.0)
|
|
stop = True
|
|
t.join(timeout=1)
|
|
|
|
recv = [x for x in list(buf) if x[0] >= t_burst_start]
|
|
elapsed = t_burst_end - t_burst_start
|
|
print(f"sent {N2} in {elapsed:.3f}s = {N2/elapsed:.2f}/s")
|
|
if recv:
|
|
span = recv[-1][0] - recv[0][0]
|
|
rate = len(recv) / span if span > 0 else 0
|
|
asyms = [m["asymmetry"] for _, m in recv]
|
|
print(f"telemetry: {len(recv)} msgs over {span:.2f}s = {rate:.1f} msg/s")
|
|
print(f"asym range: {min(asyms):.3f} .. {max(asyms):.3f}")
|
|
print("")
|
|
print("DONE")
|