Files
felhom.eu/documentation/audits/SPIKE-upload-watch-2026-10-23/tools/levels.py
T
admin a91d0b2421
gates / gates (push) Successful in 13m1s
Upload watch: spike, design (08 section 9, proposed), live proofs on 9202; rows R-1244..R-1248 (register 189 -> 194); STATUS D41/D42 + the Monday list
Spike: per-app normal levels on three boxes (19-31 days), the off-site push as a line measure (a lower bound),
qBittorrent/Transmission/Plex explainers measured on 9202, a tc ceiling measured (not built). Live on 9202 with
0.342.0-rc.1: limit set; real seed explained; CPU burner and the hidden flood alarmed once each and cleared once;
the household's limit left alone. Teardown: apps removed, 9202 back on 0.341.0, receiver 9471 destroyed.
2026-10-23 22:52:41 +02:00

31 lines
1.9 KiB
Python

import sqlite3,sys,collections,datetime,statistics
def pct(a,p):
if not a: return 0
a=sorted(a); k=(len(a)-1)*p/100; f=int(k); c=min(f+1,len(a)-1); return a[f]+(a[c]-a[f])*(k-f)
for box in sys.argv[1:]:
db=sqlite3.connect(f'file:{box}/metrics.db?mode=ro',uri=True)
lo,hi,n=db.execute('select min(ts),max(ts),count(*) from container_metrics').fetchone()
print(f'\n=== {box.rsplit("/",1)[1]}: {datetime.datetime.utcfromtimestamp(lo):%Y-%m-%d %H:%M} -> {datetime.datetime.utcfromtimestamp(hi):%Y-%m-%d %H:%M} UTC ({(hi-lo)/86400:.1f} d), {n} rows')
rows=collections.defaultdict(list)
for ts,name,cpu,tx in db.execute('select ts,container_name,cpu_percent,net_tx_bytes from container_metrics order by ts'):
rows[name].append((ts,cpu,tx))
hour=collections.defaultdict(float)
out=[]
for name,r in rows.items():
rates=[];resets=0;zero=all((x[2] or 0)==0 for x in r)
for (t0,_,a),(t1,_,b) in zip(r,r[1:]):
if a is None or b is None or t1-t0<=0 or t1-t0>180: continue
d=b-a
if d<0: resets+=1; continue
mbps=d*8/(t1-t0)/1e6; rates.append(mbps)
hour[datetime.datetime.utcfromtimestamp(t1).hour]+=d
cpus=[x[1] for x in r]
out.append((pct(rates,95),name,len(r),pct(rates,50),pct(rates,95),max(rates or [0]),pct(cpus,50),pct(cpus,95),max(cpus),zero,resets))
print(f'{"container":32} {"n":>6} {"tx p50":>8} {"p95":>8} {"max":>8} Mbit/s | {"cpu p50":>7} {"p95":>7} {"max":>7} %core | notes')
for o in sorted(out,reverse=True):
_,name,nn,a,b,c,d,e,f,zero,res=o
note=('tx counter always 0 (host network?)' if zero else '')+(f' resets={res}' if res else '')
print(f'{name[:32]:32} {nn:6} {a:8.3f} {b:8.3f} {c:8.2f} | {d:7.1f} {e:7.1f} {f:7.1f} | {note}')
tot=sum(hour.values()) or 1
print('busiest UTC hours by bytes sent:',', '.join(f'{h:02d}h {100*v/tot:.0f}%' for h,v in sorted(hour.items(),key=lambda x:-x[1])[:4]))