Skip to content

fix(libScePlayGo): answer chunk ids from the package layout - #4491

Merged
oneandonlydean merged 1 commit into
boykopovar:mainfrom
xXPBSXx:fix/playgo-bound-no-chunk-table
Oct 13, 2026
Merged

oneandonlydean merged 1 commit into
boykopovar:mainfrom
xXPBSXx:fix/playgo-bound-no-chunk-table

Conversation

@xXPBSXx

@xXPBSXx xXPBSXx commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

What

Without playgo-chunkdefs.xml or sce_sys/playgo-chunk.dat every chunk id was accepted by the PlayGo chunk checks (scePlayGoGetLocus, GetEta, GetProgress, Prefetch, SetToDoList). A title that walks the ids one call at a time until the first error then never stops: Sifu (PPSA03001), whose dump has no PlayGo file, called scePlayGoGetLocus with one ever increasing id per call at least 250 million times in 100 s (temporary counter, not part of this change); its own allocator then failed to grow a 16-byte-element array to about 348 million entries (Ran out of memory allocating 5565054976 bytes with alignment 65536) and the title trapped in libc.prx. Demon Slayer (PPSA03490) and Returnal (PPSA01285) show the same title message and trap and their dumps have no PlayGo file either (observation, not shown to be caused by PlayGo for those two).

The chunk set now follows the package layout instead of a constant (review on this PR):

  1. playgo-chunkdefs.xml or a valid playgo-chunk.dat: unchanged.
  2. Otherwise sce_sys/playgo-scenario.json present (Guardians of the Galaxy PPSA01748, fix(libScePlayGo): accept chunk ids when the dump has no chunk definitions #3238; no chunk list in the dump): every id is accepted and reported installed, as before.
  3. Otherwise, when sce_sys has no playgo-* file at all (PPSA03001, PPSA03490, PPSA01285): only chunk 0 is valid, any other id returns SCE_PLAYGO_ERROR_BAD_CHUNK_ID. This is where Sifu's enumeration ended after two calls (id 0, then id 1) before fix(libScePlayGo): accept chunk ids when the dump has no chunk definitions #3238 accepted every id (measured on Sifu (PPSA03001): RenderThread faults popping a free list whose head reads 0xFFFFFFFFFFFFFFFF #3209).
  4. A sce_sys with other playgo-* files (playgo-ficm.dat, playgo-hash-table.dat) but neither playgo-chunk.dat nor playgo-scenario.json, or a playgo-chunk.dat without a plgx header or with a zero count: throws, naming the file (no such dump is known, so no answer is guessed).

Rule 3 is recorded in docs/dev/debt/libScePlayGo.md as unverified on a console. scePlayGoGetChunkId still lists only chunk 0 in rules 2 and 3.

Tested

Windows 10, WinLibs GCC 15.2, Release, -j2, on main 4bb2c7f39 plus this commit (54ba59b92, before the rebase; the code of the PlayGo files is identical in the current head 51c7206fd, rebased onto main 8299b2f7e; libusb-cmake from a local checkout). git merge-tree of the current head 51c7206fd against main 068ab2aba (13 October) is clean. The rebased head itself was not rebuilt.

  • guest_playgo passes (3 of 3 runs). Each layout runs in its own empty root: no playgo-* file, chunk table, scenario file next to a chunk table, scenario file only, playgo-ficm.dat only, playgo-hash-table.dat only and an unreadable playgo-chunk.dat (the last three expect the throw with the file name).
  • With Export.cpp as on main the test fails; with the previous rule 3 (a96ce03cb) the three throw cases fail.
  • python tools/check_conventions.py --base upstream/main passes.
  • Title run: PPSA03001 with the libraries of this head, 100 s limit: no out-of-memory message and no BAD_CHUNK_ID line in the log; the run ended after about 109 s with a GPU message (storage image access to depth/stencil surface ... is not implemented) and abort() (details in the comment on this PR). Not tested: the chunk ids the title asks for (no PlayGo trace in the libraries); Demon Slayer (PPSA03490) and Returnal (PPSA01285) with this change; Guardians of the Galaxy (PPSA01748, layout taken from the check on fix(libScePlayGo): accept chunk ids when the dump has no chunk definitions #3238); Linux.

Checklist

  • Tested on the base named in the Tested section; the current head merges cleanly onto main 068ab2aba (git merge-tree, 13 October); no other open PR implements the same functions
  • One topic per PR; follow-ups go in a new PR
  • No comments in code except technical debt
  • Unimplemented paths throw (NotImplemented_nid_no_patch); silent stubs are listed in TechnicalDebt
  • No notes, investigation .md files or images added to the repository
  • New third-party code is a submodule built from source (none added)
  • Generic behaviour, not specific to one title
  • Depends on: none
  • Unblocks: none established (PPSA03001 no longer stops at the out-of-memory message with this change but stops later at a GPU message)
  • AI-assisted: yes

AI-assisted (Claude Code).

🤖 Generated with Claude Code

@oneandonlydean

Copy link
Copy Markdown
Collaborator

256 is a guess, and a constant tuned to end one title's loop can't go in: the answer has to follow from the package, or throw. Your own suggestion on #3238 does that, so please use it instead:

  • no playgo-* file in sce_sys (PPSA03001, PPSA03490): the package has no PlayGo data, so only chunk 0 is valid and any other id returns SCE_PLAYGO_ERROR_BAD_CHUNK_ID. That is where your trace shows the enumeration ending after two calls.
  • playgo-scenario.json without a chunk table (PPSA01748): the table is missing from the dump, and the fix(libScePlayGo): accept chunk ids when the dump has no chunk definitions #3238 behaviour stays as the debt entry records it.

Please say which playgo-* files the PPSA01285 dump has, give guest_playgo a case for each layout, and record the first rule in docs/dev/debt/libScePlayGo.md as unverified on a console.

@xXPBSXx

xXPBSXx commented Oct 13, 2026

Copy link
Copy Markdown
Contributor Author

Thanks, agreed: the answer should follow from the package, not from a constant. I will change the PR to your two rules.

Facts for the playgo-* question (file names and counts only, no game data):

  • PPSA01285 is Returnal in my list (not Guardians of the Galaxy, which is PPSA01748). Its sce_sys has no playgo-* file: about, disc_info.dat, icon0.*, keystone, nptitle.dat, param.json, pfs-version.dat, pic*, snd0.at9, trophy2, uds. PPSA03001 (Sifu) and PPSA03490 (Demon Slayer) have none either.
  • Counting the top-level folders of my game directory: 38 contain a sce_sys folder directly (10 of them are _elf copies of other dumps); 4 of those contain playgo-* files (PPSA16827, PPSA21480, PPSA23827, PPSA26223), all with playgo-chunk.dat (plus playgo-ficm.dat and playgo-hash-table.dat; PPSA21480 also has playgo-scenario.json). One more folder (Palworld) has its sce_sys nested deeper, also with playgo-chunk.dat. None has playgo-scenario.json without playgo-chunk.dat, so I cannot test the second layout on a dump; PPSA01748 is not among mine. I take the layout from Tamalero's check on fix(libScePlayGo): accept chunk ids when the dump has no chunk definitions #3238 (scenario file present, no playgo-chunk.dat, no playgo-chunkdefs.xml). High on Life (PPSA15388) has no playgo-* file there and runs with the old rule, which fits the first layout.
  • Sifu asks one id at a time in ascending order (0, 1, 2, ...) and stops at the first failing call: with the old rule that is two calls (id 0 ok, id 1 BAD_CHUNK_ID), measured on Sifu (PPSA03001): RenderThread faults popping a free list whose head reads 0xFFFFFFFFFFFFFFFF #3209 (Windows, main a11c8f7). I have not traced the ids that PPSA03490 and PPSA01285 ask for; they show the same out-of-memory message and trap, which I did not show to come from PlayGo.

Planned rule (not yet implemented, will follow after your OK):

  1. playgo-chunkdefs.xml or a valid playgo-chunk.dat: unchanged.
  2. Otherwise, sce_sys/playgo-scenario.json present: any id is accepted and reported as installed (behaviour of fix(libScePlayGo): accept chunk ids when the dump has no chunk definitions #3238, as in the debt entry).
  3. Otherwise (no playgo-* that gives a chunk table or scenario): only chunk 0 is valid, other ids return SCE_PLAYGO_ERROR_BAD_CHUNK_ID. This goes into docs/dev/debt/libScePlayGo.md as unverified on a console.

Open point: a dump with playgo-ficm.dat or playgo-hash-table.dat but neither playgo-chunk.dat nor playgo-scenario.json. None of my dumps is like that, so I would treat it like rule 3 unless you want otherwise.

guest_playgo will get one case per layout (rule 1 with the existing chunk table cases, rule 2 with only a scenario file, rule 3 with no file). The chunk set is read once per process, so each layout needs its own run of the test.

AI-assisted (Claude Code).

@xXPBSXx
xXPBSXx force-pushed the fix/playgo-bound-no-chunk-table branch from 71a81cf to a96ce03 Compare October 13, 2026 02:38
@xXPBSXx xXPBSXx changed the title fix(libScePlayGo): bound the accepted chunk ids when no chunk table exists fix(libScePlayGo): answer chunk ids from the package layout Oct 13, 2026
@xXPBSXx

xXPBSXx commented Oct 13, 2026

Copy link
Copy Markdown
Contributor Author

Updated as discussed: the chunk set now follows the package layout (the three rules from the comment above) instead of the 256 constant, with one test process per layout and the debt entry in docs/dev/debt/libScePlayGo.md marked unverified on a console. Built and run on main d1fd9372b (guest_playgo passes 3 of 3, fails without the Export.cpp change); the PR text has the details and what is not tested.

AI-assisted (Claude Code).

@oneandonlydean

Copy link
Copy Markdown
Collaborator

Rules 1 and 2 are as agreed. Rule 3 is wider than agreed: Export.cpp:52 and :74 answer "only chunk 0" for everything without a scenario file. That includes your open point (a dump with only playgo-ficm.dat or playgo-hash-table.dat) and a playgo-chunk.dat that fails the plgx/count check at :38-41. Nobody has such a dump, so chunk 0 is a guess there; please throw, naming the file, and keep "only chunk 0" for a sce_sys with no playgo-* file at all, which is what the debt entry already says.

  • guest_playgo: give the no-file layout its own empty root like the other three (the parent process now depends on no app0 sitting next to the working directory), and add a case for the throw.
  • A PPSA03001 run on the new head, with the log: the checklist says it unblocks that title, and "Not tested" says no title ran with this change.

A package with no playgo-* file in sce_sys has no PlayGo data, so only chunk 0
is valid and any other id returns SCE_PLAYGO_ERROR_BAD_CHUNK_ID. A package with
playgo-scenario.json but no chunk table (PPSA01748) keeps accepting every id.
A chunk table (playgo-chunk.dat or playgo-chunkdefs.xml) still decides when it
exists. A sce_sys that holds other playgo-* files without a chunk table or a
scenario file, or a playgo-chunk.dat that is not a plgx table with a nonzero
count, throws naming the file, since no such dump is known.

Without this a title that walks the ids until the first error (Sifu PPSA03001)
never gets the error.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@xXPBSXx
xXPBSXx force-pushed the fix/playgo-bound-no-chunk-table branch from a96ce03 to 51c7206 Compare October 13, 2026 09:27
@xXPBSXx

xXPBSXx commented Oct 13, 2026

Copy link
Copy Markdown
Contributor Author

Thanks, both points are done in the new head.

  • Rule 3 is narrower: "only chunk 0" now applies only when sce_sys has no playgo-* file at all. A sce_sys with playgo-ficm.dat or playgo-hash-table.dat but no playgo-chunk.dat and no playgo-scenario.json, and a playgo-chunk.dat without a plgx header or with a zero count, throw a std::runtime_error naming the file. The debt entry says so.
  • guest_playgo runs every layout in its own empty root now, including the no-file layout (the parent no longer depends on an app0 next to the working directory). New cases: playgo-ficm.dat only, playgo-hash-table.dat only and an unreadable playgo-chunk.dat, each expecting the throw with the file name.
  • Windows 10, MinGW GCC 15.2, -j2, on main 4bb2c7f39: guest_playgo passes (3 of 3 runs). With the previous rule 3 (a96ce03cb) the new cases make it fail; with Export.cpp as on main it fails as well. check_conventions passes.
  • No title run with this change; a PPSA03001 run is still outstanding, so the checklist no longer says it unblocks that title.

AI-assisted (Claude Code).

@xXPBSXx

xXPBSXx commented Oct 13, 2026

Copy link
Copy Markdown
Contributor Author

PPSA03001 run on the new head, as asked (Windows 10, main 8299b2f7e plus #4491 at 51c7206fd, all libraries built from that head, run_title.ps1 with a 100 s limit, started by hand):

  • Out of Memory / Ran out of memory: 0 matches. BAD_CHUNK_ID in the log: 0 matches (the libraries have no PlayGo trace, so this only shows what the title logs itself). FATAL: 1 match.
  • The run ended after about 109 s (log created 15:55:30, last write 15:57:19) with a different stop than before: AGC graphics: storage image access to depth/stencil surface ... is not implemented in a compute shader, followed by abort(). This is the GPU path, not PlayGo. The earlier stop (the out-of-memory message and the trap, 9 of 9 runs without the change, within 100 s) did not appear. Those earlier runs were made on main ffa198407/9aa5fd290, not on this base.
  • Log size: 685 lines in run_155526.err, 378 in .out. At the start the title showed its logo (seen by hand) before it went on to load.
  • What this shows: with the chunk rules of this PR the title no longer stops at the out-of-memory message. What it does not show: the chunk ids the title asks for (no trace in these libraries) and anything beyond the GPU stop above.

AI-assisted (Claude Code).

@xXPBSXx

xXPBSXx commented Oct 13, 2026

Copy link
Copy Markdown
Contributor Author

@oneandonlydean the PPSA03001 run you asked for is in my comment above (libraries built from this head): the title no longer stops at the out-of-memory message and now stops later at a GPU message; it does not show which chunk ids the title asks for.

Since your last reviews I corrected two source statements in my PRs (the .. case in #5008 and the gap behaviour of sceKernelMprotect in #5143, both now follow the FreeBSD 11.4 vfs_lookup.c / vm_map_protect source), and moved the test and debt entries of my libkernel PRs to separate places so they merge independently.

Could you have a look when it suits you? No hurry.

Thank you for the careful reviews.

AI-assisted (Claude Code).

@winstrex winstrex mentioned this pull request Oct 13, 2026
9 tasks done
@oneandonlydean
oneandonlydean merged commit 18c438b into boykopovar:main Oct 13, 2026
10 of 11 checks passed
MarcZX10 pushed a commit to MarcZX10/AnyPS5 that referenced this pull request Oct 15, 2026
…ithout PlayGo metadata

Since boykopovar#5494 a dump with no playgo-chunk.dat and no playgo-scenario.json
throws on the first nonzero chunk id. High on Life (PPSA15388) asks
scePlayGoGetLocus about ids 0-999 at startup and now aborts on id 1;
Sifu (PPSA03001) walks ids until the first error (boykopovar#4491).

APS5_PLAYGO_UNLISTED_CHUNKS=installed reports such ids as installed and
=absent returns SCE_PLAYGO_ERROR_BAD_CHUNK_ID. Without it the stop stays,
and its message now names the setting. Any other value throws.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MarcZX10 pushed a commit to MarcZX10/AnyPS5 that referenced this pull request Oct 15, 2026
…ithout PlayGo metadata

Since boykopovar#5494 a dump with no playgo-chunk.dat and no playgo-scenario.json
throws on the first nonzero chunk id. High on Life (PPSA15388) asks
scePlayGoGetLocus about ids 0-999 at startup and now aborts on id 1;
Sifu (PPSA03001) walks ids until the first error (boykopovar#4491).

APS5_PLAYGO_UNLISTED_CHUNKS=installed reports such ids as installed and
=absent returns SCE_PLAYGO_ERROR_BAD_CHUNK_ID. Without it the stop stays,
and its message now names the setting. Any other value throws.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Tamalero added a commit to Tamalero/AnyPS5 that referenced this pull request Oct 16, 2026
…ithout PlayGo metadata

Since boykopovar#5494 a dump with no playgo-chunk.dat and no playgo-scenario.json
throws on the first nonzero chunk id. High on Life (PPSA15388) asks
scePlayGoGetLocus about ids 0-999 at startup and now aborts on id 1;
Sifu (PPSA03001) walks ids until the first error (boykopovar#4491).

APS5_PLAYGO_UNLISTED_CHUNKS=installed reports such ids as installed and
=absent returns SCE_PLAYGO_ERROR_BAD_CHUNK_ID. Without it the stop stays,
and its message now names the setting. Any other value throws.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants