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>
PS4 titles ship sce_sys/param.sfo instead of param.json. When param.json
is absent, the application metadata now reads the title, title ID,
download data size and user defined parameters from param.sfo, and
/data and /download0 are mounted for it as for param.json. param.json
is still preferred when both files exist.
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.
Apple's libc++ marks floating-point std::from_chars unavailable below a
macOS 26 deployment target, so the relinker-only build fails on macOS 15
since the JSON number conversion switched to it. Use from_chars where
the standard library defines __cpp_lib_to_chars and otherwise convert
through a stream imbued with the classic locale, which keeps the
conversion independent of the host locale and keeps the full-consumption
and range checks.
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
On the console a title whose param.json declares downloadDataSize finds
/download0 mounted from the start. The host directory was only created
by sceAppContentDownloadDataGetAvailableSpaceKb, so a title that opens
files there directly got ENOENT. libkernel now creates it when it loads,
reading only the run directory's param.json, without resolving guest
paths, so the libc path root is still fixed at first use.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
Only the lines this branch added lose their comments; the commits before
keep them, with the reasoning behind each change, for whoever digs into
that code later.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
libkernel:
- direct memory keeps its contents per physical page across unmap and
remap; a page mapped at two live addresses at once throws
- sceKernelDirectMemoryQuery answers from tracked allocations
- SCE protections read back as set, GPU and AMPR bits included
- APR prefix path resolve, file size and stat by id, positional reads,
fsync/pread/pwrite; directories open as descriptors on Windows
- sceKernelCheckReachability, getpeername, shutdown
- Dinkumware C11 threads (_Mtx_*, _Cnd_*, _Thrd_*) in the title libc
layout; any pthread stack size, rounded at thread creation
libc:
- unaddressed guest mappings go to the system-managed area from
0x2_0000_0000, leaving the application area to fixed mappings
- the process starts in /app0
- guest sscanf on Windows; a null %s prints as (null) as on FreeBSD
- localeconv, _FNan, _FDtest, _FExp, __udivti3, wcsncpy_s, aligned
operator new, _Throw_Cpp_error
Tests: direct memory following physical pages, guest formatting.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>