Review of the benchmark report:
- The file is written to `<name>.tmp` and moved over the previous one, so a
crash or kill during a rewrite keeps the last complete report.
- A dedicated writer keeps only the newest pending snapshot, so two reports
can no longer be joined into one file when the writer falls behind.
- The report is formatted on the writer thread. The presenter hands over the
kept intervals, which are shared and never copied, so the interval that
closes no longer pays for formatting every earlier one.
- Hosts that are not x86 or report no CPU brand string leave the host fields
out instead of failing every summary line.
- A `contentVersion` that is not a string, or does not fit, is left empty
instead of failing the title's metadata.
- Tests cover the 240-interval rotation and `intervals_dropped`, the
newest-only writer, the pending write on stop and the atomic replace.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The summary line names the CPU, its thread count, physical memory and,
with param.json, the title ID, name and content version.
APS5_TRACE_BENCH=1 with APS5_TRACE_SUMMARY_EVERY rewrites
aps5-bench-<commit>-<pid>.json.gz at each interval with the time between
every two presents, so reports can be recomputed and checked from raw
frame times. param.json's contentVersion is read when present.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SONIC SUPERSTARS (PPSA06888) ships "kernel": {"flexibleMemorySize": 0},
which the parser rejected, so the title stopped before its first module
loaded. A zero size now leaves the default budget, like an absent one.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Read the optional aligned budget from param.json and apply it consistently to configured, available and mapped flexible memory. Add parser and allocation regression coverage.
parseJsonValue recursed without a limit, so a param.json with tens of
thousands of nested arrays overflowed the stack. Reject nesting beyond 512
levels, the limit libSceJson2 uses.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R5WJS4ZdQynAJesCZKH5hb
sceAppContentAppParamGetInt numbers the SKU flag 0 and
USER_DEFINED_PARAM_1..4 as 1..4 (fpPS4 ps4_libsceappcontent). Id 1
returned the SKU flag and 2..5 returned zero. UFC 6 (PPSA23566) checks
that param 1 is its title number, userDefinedParam1 in param.json, and
crashes otherwise. Absent params read as zero.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A PS5 param.json keeps defaultLanguage inside localizedParameters, next to
the language entries. The parser looked for it at the root only, then fell
back to en-US and to the first member, which is the defaultLanguage string
when no en-US entry exists (PPSA12544 has only en-GB), and threw
"expected JSON object". defaultLanguage is now read from
localizedParameters first, and the fallback takes the first language
object.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>