CPUEquivalence: Dump every core's end state, not only the interpreter's

So a diff between hosts covers the JITs too, without minimizing every case.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Henrik RydgårdandClaude Opus 5.5 committed 2026-10-14 00:10:00 +02:00
1 parent 5495a6df90
commit 23da98199e
2 files changed
+11 -8

No files matched your search

+4 -3
View File
@@ -30,7 +30,7 @@ Environment variables:
| `PPSSPP_CPUFUZZ_SKIP` | cores to skip, by digit: 1 IR interpreter, 2 JIT, 3 JIT IR |
| `PPSSPP_CPUFUZZ_REPORTS` | how many differences to minimize and print (default 20) |
| `PPSSPP_CPUFUZZ_VERBOSE` | print every case before running it, to find one that crashes |
| `PPSSPP_CPUFUZZ_DUMP` | write the interpreter's end state of every case to a file |
| `PPSSPP_CPUFUZZ_DUMP` | write every core's end state of every case to a file |
| `PPSSPP_CPUFUZZ_STRICT` | fail on any difference, not only on a crash |
Always set `CI=1` when running it from a script on Windows. Otherwise a JIT assert opens a message
@@ -41,8 +41,9 @@ finds it and reduces it to the instructions still needed for the crash. A crash
after other cases have run usually means uninitialized or stale state, not the reduced code.
To compare hosts: run with the same seed and count and `PPSSPP_CPUFUZZ_DUMP` on each, and diff the
files. A Windows-on-ARM machine can run the x64 build under emulation, which is enough for the
host-dependent float behavior of the interpreter. It isn't for timing, of course.
files. Each line starts with the core and the seed. A Windows-on-ARM machine can run the x64 build
under emulation, which is enough for the host-dependent float behavior of the cores. It isn't for
timing, of course.
## Fixed
+7 -5
View File
@@ -376,7 +376,7 @@ bool TestJitReplacementHooks() {
// Environment variables:
// PPSSPP_CPUFUZZ_COUNT number of cases (default 2000)
// PPSSPP_CPUFUZZ_SEED first case's seed (default 1). Case i always uses seed + i.
// PPSSPP_CPUFUZZ_DUMP file to write the interpreter's end state of every case to, for diffing
// PPSSPP_CPUFUZZ_DUMP file to write every core's end state of every case to, for diffing
// the results of different host architectures.
// PPSSPP_CPUFUZZ_CLASSES instruction classes to generate, as a weighted string of "aifvm" (alu,
// imm, fpu, vfpu, memory).
@@ -754,10 +754,10 @@ static int DiffFuzzStates(const FuzzState &ref, const FuzzState &other, std::str
return diffs;
}
static void DumpFuzzState(FILE *f, u64 seed, const FuzzState &s) {
static void DumpFuzzState(FILE *f, const char *core, u64 seed, const FuzzState &s) {
// All NaNs print the same, so their payloads don't show up as differences.
auto fl = [](u32 v) { return IsNaNBits(v) ? 0x7FFFFFFFU : v; };
fprintf(f, "%llu r", (unsigned long long)seed);
fprintf(f, "%s %llu r", core, (unsigned long long)seed);
for (int i = 0; i < 32; ++i) {
fprintf(f, " %08x", s.r[i]);
}
@@ -942,8 +942,10 @@ bool TestCPUEquivalence() {
if (dumpPath) {
FILE *f = fopen(dumpPath, "w");
if (f) {
for (int i = 0; i < count; ++i) {
DumpFuzzState(f, firstSeed + i, results[(size_t)i * numCores]);
for (int c = 0; c < numCores; ++c) {
for (int i = 0; i < count; ++i) {
DumpFuzzState(f, CoreName(cores[c]), firstSeed + i, results[(size_t)i * numCores + c]);
}
}
fclose(f);
} else {