"""Run the isolated synthetic C# harness and measure its own source FFmpeg only. No Jellyfin configuration changes, restarts, API keys or receiver connections. """ import argparse import json import os from pathlib import Path import signal import subprocess import time def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('--harness', required=True) parser.add_argument('--ffmpeg', default='/usr/lib/jellyfin-ffmpeg/ffmpeg') parser.add_argument('--output', required=True) parser.add_argument('--long', action='store_true') args = parser.parse_args() root = Path(args.output).resolve() if root.exists(): raise ValueError('Choose a new output directory') samples, previous = [], {} with Path(str(root) + '.log').open('x') as log: process = subprocess.Popen([args.harness, '--long-continuity-e2e' if args.long else '--continuity-e2e', args.ffmpeg, str(root)], stdout=log, stderr=subprocess.STDOUT, start_new_session=True) deadline = time.monotonic() + 240 try: while process.poll() is None: if time.monotonic() > deadline: raise TimeoutError('Synthetic harness deadline exceeded') now = time.monotonic() for proc in Path('/proc').glob('[0-9]*'): try: if not str((proc / 'cwd').resolve()).startswith(str(root / 'cache' / 'source-')): continue value = (proc / 'stat').read_text() fields = value[value.rfind(')') + 2:].split() cpu = (int(fields[11]) + int(fields[12])) / os.sysconf('SC_CLK_TCK') rss = int(fields[21]) * os.sysconf('SC_PAGE_SIZE') / 1048576 if proc.name in previous: before, at = previous[proc.name] samples.append({'one_core_percent': round((cpu-before)/(now-at)*100, 1), 'rss_mib': round(rss, 1)}) previous[proc.name] = (cpu, now) except OSError: pass time.sleep(1) finally: if process.poll() is None: os.killpg(process.pid, signal.SIGTERM) try: process.wait(timeout=5) except subprocess.TimeoutExpired: os.killpg(process.pid, signal.SIGKILL) process.wait() report = {'harness_exit_code': process.returncode, 'samples': samples, 'scope': 'Only synthetic plugin source encoding; excludes fixture and player decoders'} (root / 'cpu-sample.json').write_text(json.dumps(report, indent=2)) if process.returncode == 0 and args.long: subprocess.run(['python3', str(Path(__file__).with_name('verify-continuity-recording.py')), '--output', str(root), '--ffmpeg', args.ffmpeg], check=True) print(Path(str(root) + '.log').read_text()[-3500:]) print(json.dumps({'exit_code': process.returncode, 'cpu_samples': len(samples), 'maximum_one_core_percent': max((s['one_core_percent'] for s in samples), default=None), 'maximum_rss_mib': max((s['rss_mib'] for s in samples), default=None)})) raise SystemExit(0 if process.returncode == 0 else 1) if __name__ == '__main__': main()