aim-web2.1.0rc9
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
"""Optional synthetic read-projection benchmark; never pass a production DB.
|
||||
|
||||
python tests/benchmark_read_history.py --jobs 20000 --out /tmp/aim-history-benchmark.json
|
||||
Uses an automatically cleaned temporary database and only retained WebGUI fixtures.
|
||||
"""
|
||||
from pathlib import Path
|
||||
import argparse
|
||||
import json
|
||||
import resource
|
||||
import statistics
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
sys.path.insert(0,str(Path(__file__).resolve().parents[1]/'src'))
|
||||
from aim_webgui.activity import Activity, HistoryFilter
|
||||
from aim_webgui.auth.service import Auth
|
||||
from aim_webgui.config import Settings
|
||||
|
||||
|
||||
def main():
|
||||
parser=argparse.ArgumentParser()
|
||||
parser.add_argument('--jobs',type=int,default=20000)
|
||||
parser.add_argument('--out',type=Path,required=True)
|
||||
args=parser.parse_args()
|
||||
if not 1 <= args.jobs <= 100000:parser.error('--jobs must be 1..100000')
|
||||
counts=('ok','changed','failures','unreachable','skipped','rescued','ignored')
|
||||
now=int(time.time())
|
||||
with tempfile.TemporaryDirectory(prefix='aim-read-benchmark-') as tmp:
|
||||
auth=Auth(Settings(state_dir=Path(tmp)/'state',public_url='https://fixture.invalid').validate())
|
||||
auth.bootstrap()
|
||||
with auth.store.transaction() as db:
|
||||
db.execute('UPDATE users SET must_change_password=0')
|
||||
actor=db.execute('SELECT id FROM users WHERE username=?',('admin',)).fetchone()[0]
|
||||
for i in range(args.jobs):
|
||||
hosts=[f'host-{(i+j)%200:04d}.example' for j in range(4)]
|
||||
outcome='unreachable' if i%5==0 else 'successful'
|
||||
targets=[]
|
||||
for j,h in enumerate(hosts):
|
||||
c=dict.fromkeys(counts,0);c['ok']=30;c['changed']=1
|
||||
state=outcome if j==3 else 'successful'
|
||||
if state=='unreachable':c['unreachable']=1
|
||||
targets.append({'host':h,'outcome':state,'counts':c})
|
||||
unreachable=int(outcome=='unreachable')
|
||||
result={'status':'failed' if unreachable else 'succeeded','targets':targets,
|
||||
'target_summary':{'schema':'target_outcome_summary_v1','requested':4,'accounted':4,'complete':True,
|
||||
'successful':4-unreachable,'failed':0,'unreachable':unreachable,'indeterminate':0,'not_started':0}}
|
||||
plan={'customer':'synthetic','playbook':f'debug_fixture_{i%8}','targets':hosts}
|
||||
db.execute('INSERT INTO jobs(id,owner_id,plan,mode,status,created_at,scheduled_at,finished_at,core_result) VALUES(?,?,?,?,?,?,?,?,?)',
|
||||
(f'{i:032x}',actor,json.dumps(plan),'apply','failed' if unreachable else 'successful',now-i-1,now-i-1,now-i-1,json.dumps(result)))
|
||||
reader=Activity(auth.settings);durations=[]
|
||||
for _ in range(3):
|
||||
start=time.perf_counter();report=reader.report(actor,HistoryFilter(days='all'),now=now)
|
||||
durations.append(time.perf_counter()-start)
|
||||
assert report['jobs']==args.jobs and report['samples']==args.jobs*4
|
||||
assert len(report['records'])==min(25,args.jobs*4) and len(report['matrix'])<=20
|
||||
result={'synthetic_only':True,'jobs':args.jobs,'host_run_samples':report['samples'],
|
||||
'distinct_customer_hosts':report['host_count'],'playbooks':len(report['playbooks']),
|
||||
'runs_seconds':durations,'median_seconds':statistics.median(durations),
|
||||
'process_peak_rss_kib':resource.getrusage(resource.RUSAGE_SELF).ru_maxrss,
|
||||
'sqlite_bytes':auth.settings.database.stat().st_size,'output_records':len(report['records']),
|
||||
'matrix_rows':len(report['matrix']),'core_calls':0,'projection_tables_added':0}
|
||||
args.out.write_text(json.dumps(result,indent=2)+'\n')
|
||||
print(json.dumps(result,indent=2))
|
||||
|
||||
if __name__=='__main__':main()
|
||||
Reference in New Issue
Block a user