78 lines
6.1 KiB
Python
78 lines
6.1 KiB
Python
#!/usr/bin/env python3
|
||
"""Check and summarize all ten completed URL-fix measurements."""
|
||
import hashlib
|
||
import json
|
||
from pathlib import Path
|
||
|
||
ROOT = Path(__file__).resolve().parents[2]
|
||
OUT = ROOT / 'tests/results/portal/performance-suite'
|
||
|
||
|
||
def sha(path):
|
||
with path.open('rb') as stream:
|
||
return hashlib.file_digest(stream, 'sha256').hexdigest()
|
||
|
||
|
||
def main():
|
||
run = json.loads((OUT / 'report.json').read_text())
|
||
assert run['success'] and len(run['commands']) == 5 and all(row['exitCode'] == 0 for row in run['commands'])
|
||
assert run['runnerSha256'] == sha(OUT / 'runner-at-start.py')
|
||
binaries = {name: sha(ROOT / 'build' / name) for name in ('docview', 'docview-pdf-worker', 'docview-archive-worker')}
|
||
assert all(run['binaries'][name] == value for name, value in binaries.items())
|
||
rows, operation_count = [], 0
|
||
for corpus, formats in [('smoke', ['pdf', 'html', 'zip', 'epub']),
|
||
('standard', ['pdf', 'pdf-headings', 'html', 'zip', 'epub']), ('fonts', ['pdf'])]:
|
||
for kind in formats:
|
||
relative = corpus + '/' + kind + '.json'
|
||
value = json.loads((OUT / relative).read_text())
|
||
assert value['success'] and value['originalUnchanged'] and all(value['measurementChecks'].values())
|
||
assert value['executableSha256'] == binaries and value['runnerSha256'] == sha(ROOT / 'tests/benchmark.py')
|
||
assert len(value['openFrameMs']) == 30 and value['coldProcessOpen']['requested'] == 30 and value['coldProcessOpen']['failed'] == 0
|
||
assert value['summary']['uniform_open_close_cycles'] == 29 and value['summary']['all_closes_empty']
|
||
display = value['display']
|
||
assert display['screenLogicalWidth'] == 1100 and display['screenLogicalHeight'] == 760 and display['windowDevicePixelRatio'] == 1
|
||
cold = list((OUT / corpus / 'cold' / kind).glob('[0-9][0-9][0-9].json'))
|
||
assert len(cold) == 30
|
||
for path in cold:
|
||
sample = json.loads(path.read_text())
|
||
assert sample['success'] and sample['documentSha256'] == value['documentSha256']
|
||
assert sample['display'] == display and sample['maximumMemoryPressureLevel'] == 0
|
||
operation_count += len(value['operations'])
|
||
summary = value['summary']
|
||
exceeded = [name for name, observation in value['proposedBudgetObservations'].items()
|
||
if observation is False or isinstance(observation, dict) and observation.get('observed_met') is False]
|
||
rows.append({'corpus': corpus, 'format': kind, 'record': relative, 'recordSha256': sha(OUT / relative),
|
||
'coldOpenP95Ms': summary['fresh_process_fresh_app_cache_open']['p95_ms'],
|
||
'responseP95Ms': summary['response']['p95_ms'], 'finalQualityP95Ms': summary['final_quality']['p95_ms'],
|
||
'scrollP95Ms': summary['continuous_scroll_frames']['p95_ms'],
|
||
'processGroupPeakMiB': value['processGroupRssPeakBytes'] / 1024**2,
|
||
'budgetObservationsExceeded': exceeded, 'navigationCoverage': value['navigationCoverage']})
|
||
interaction = json.loads((OUT / 'interaction/record.json').read_text())
|
||
stress = json.loads((OUT / 'stress/report.json').read_text())
|
||
measured = {row['path']: row['sha256'] for row in interaction['binaries']}
|
||
assert interaction['success'] and measured['test_app'] == sha(ROOT / 'build/test_app')
|
||
assert all(measured[name] == digest for name, digest in binaries.items())
|
||
assert stress['success'] and stress['originalUnchanged'] and stress['sourceRemoved']
|
||
assert stress['executableSha256'] == binaries and stress['executablesUnchanged']
|
||
result = {'success': True, 'buildSha256': binaries, 'cases': rows, 'coldOpens': 300, 'sameProcessOpens': 300,
|
||
'summaryGeneratorSha256': sha(Path(__file__)),
|
||
'navigationOperations': operation_count, 'scope': run['scope'],
|
||
'interactionRecordSha256': sha(OUT / 'interaction/record.json'), 'stressRecordSha256': sha(OUT / 'stress/report.json'),
|
||
'proposedBudgetExceedances': sum(len(row['budgetObservationsExceeded']) for row in rows)}
|
||
(OUT / 'summary.json').write_text(json.dumps(result, ensure_ascii=False, indent=2) + '\n')
|
||
lines = ['# URL比較修正後の性能測定', '',
|
||
'10条件で新規プロセス・空のXDGアプリキャッシュ30回、同一プロセス30回、適用される移動系列125操作、連続scroll240入力を実施した。原本不変、全closeの状態解放、メモリ圧迫なしを確認した。', '',
|
||
'ArchのXvfb 1100×760、DPR1、software描画。OSファイルキャッシュは保持。起動後のopenを起点とし、プロセス起動時間を含めない。Qt提示通知の測定で、Webの対象画素や物理scanoutの直接測定ではない。基準機・対象OSの性能受入とは区別する。', '',
|
||
'| 資料 | 形式 | 冷open p95 ms | 応答 p95 ms | 最終品質 p95 ms | scroll p95 ms | 群RSS最大 MiB |',
|
||
'|---|---|---:|---:|---:|---:|---:|']
|
||
for row in rows:
|
||
lines.append(f"| {row['corpus']} | [{row['format']}]({row['record']}) | {row['coldOpenP95Ms']:.2f} | {row['responseP95Ms']:.2f} | {row['finalQualityP95Ms']:.2f} | {row['scrollP95Ms']:.2f} | {row['processGroupPeakMiB']:.2f} |")
|
||
lines += ['', f"新規open 300回・同一プロセスopen 300回・移動系列{operation_count}操作。暫定予算の参考超過は{result['proposedBudgetExceedances']}件。元の予算値は変更していない。未測定の系列は各JSONのnavigationCoverageで区別する。", '',
|
||
'[実行コマンド](report.json)、[機械集計](summary.json)、[操作負荷](interaction/record.json)、[約1GB・5,000ページPDF](stress/report.json)を保存した。重いPDFは3open・100操作の追加負荷であり、30回の性能受入標本ではない。', '']
|
||
(OUT / 'README.md').write_text('\n'.join(lines))
|
||
print(json.dumps({key: result[key] for key in ('success', 'coldOpens', 'sameProcessOpens', 'navigationOperations', 'proposedBudgetExceedances')}))
|
||
|
||
|
||
if __name__ == '__main__':
|
||
main()
|