Files
PS5_RetroArch/tests/test_gpu_profile.py
T
Mihawk 62d0a4747d Keep development logs while buffering GPU timing off the frame loop
Retain frontend INFO/WARN/ERROR, driver errors, startup trace and klog.
Restore frontend log setup after rebuilt arguments, mark its build identity,
and retrieve it with each run. Remove periodic frame and button chatter;
log menu texture handover once. Profiling is opt-in, bounded and written only
after capture; validate per-frame partitions and presentation-return cadence.

Verified: bash tools/verify.sh (all gates, 28 tests); fresh vendor patch
replay/idempotence (86 edits). Two 60-second captures completed: first at
59.940238 FPS with maximum interval 16.905813 ms; fresh frontend logging
exposed three late texture-probe stalls, then those probes were limited.
Final refined build launched with zero refusals, logged handover once and
returned 0 before profiling completed; no final timing claim is made.
User requested ending performance investigation and proceeding to XMB.

Evidence: evidence/vulkan-buffered-logging/{capture,expectation}.json
Replay: python3 tools/evidence.py compare evidence/
Console: bash tools/run-title.sh --no-build --gpu-profile 60 --watch 80
Analysis: python3 tools/analyze-gpu-profile.py klog/gpu-profile-<stamp>.tsv
2026-09-19 11:30:05 -04:00

42 lines
2.0 KiB
Python

"""Reject incomplete timing evidence and check deadline-proxy accounting."""
import importlib.util
from pathlib import Path
import unittest
ROOT = Path(__file__).resolve().parent.parent
SPEC = importlib.util.spec_from_file_location('gpu_profile', ROOT / 'tools/analyze-gpu-profile.py')
MODULE = importlib.util.module_from_spec(SPEC)
SPEC.loader.exec_module(MODULE)
def fixture():
values = [16666667, 50000, 100000, 4500000, 20000, 3500000, 8466667, 30000]
fields = ['interval'] + list(MODULE.PHASES)
header = 'frame\t' + '\t'.join(name + '_ns' for name in fields)
header += '\tpresent_interval_ns\tpresent_calls\n'
body = ''.join('\t'.join(map(str, [i] + [value * (i + 1) for value in values]
+ [16666667 * (i + 1), 1])) + '\n' for i in range(2))
return '# frames=2 elapsed_ns=50000001 capacity_reached=0 api_failures=0\n' + header + body
class GpuProfile(unittest.TestCase):
def test_partition_and_completion_cadence(self):
result = MODULE.analyze(fixture())
self.assertAlmostEqual(result['fps'], 40, places=5)
self.assertAlmostEqual(result['phases']['interval']['p99_ms'], 33.333334)
self.assertEqual(result['presentation']['completion_intervals_over_20ms'], 1)
self.assertEqual(result['presentation']['estimated_extra_60hz_intervals'], 1)
self.assertEqual(result['slowest_frames'][0]['frame'], 1)
def test_rejects_truncation_failed_calls_and_bad_partition(self):
for broken in [fixture().replace('frames=2', 'frames=3'),
fixture().replace('api_failures=0', 'api_failures=1'),
fixture().replace('capacity_reached=0', 'capacity_reached=1'),
fixture().replace('\t50000\t', '\t50001\t'),
fixture().replace('elapsed_ns=50000001', 'elapsed_ns=50000002'),
fixture().replace('\t1\n', '\t2\n')]:
with self.subTest(broken=broken):
with self.assertRaises(ValueError):
MODULE.analyze(broken)