Settings: default the thread scheduler back to the OS

The affinity migration turned the scheduler on so the big.LITTLE mask would
apply, keeping SPU and RSX off the A510s that run at roughly 27% of prime-core
capacity. That reasoning holds for one thread per core and breaks down at six.

Measured in game on a Snapdragon 8 Gen 2, reading the masks the threads actually
carry:

    app cpuset (top-app)  0-7    Android grants every core
    SPU[0..5]             3-6    six threads, four cores
    rsx::thread           3-7

Six SPU threads sharing four cores get about two thirds of a core each, which is
worse than one thread owning an A510 outright, and it caps the emulator: the
device sat at 60% busy with cores 0-2 idle while frames were slow. Spider-Man:
Web of Shadows is visibly better at OS.

Worth being clear that the mask is ours and not Android's -- the app is in
top-app with all eight cores granted -- which is also why these devices are
reported to run better under native Linux, where no such policy is applied.

The other modes stay selectable for anyone whose device disagrees.
This commit is contained in:
jpolo1224
2026-08-11 09:33:32 -04:00
parent 1c2d44502c
commit 5f346b5e2c
2 changed files with 42 additions and 6 deletions
@@ -72,6 +72,8 @@ object ConfigStore {
// migration above only ever corrected the curated field.
private const val KEY_RELAXED_ZCULL_OVERRIDE_PURGED = "config.migrated.relaxedZcullOverridePurged"
private const val KEY_AFFINITY_ON = "config.migrated.affinityScheduler"
// ...and back off it: the mask it enables confines six SPU threads to four cores.
private const val KEY_AFFINITY_OS = "config.migrated.affinitySchedulerOff"
private const val KEY_TIMESTRETCH_OFF = "config.migrated.audioTimeStretchOff"
// Scaling Mode row changed meaning; a stored 0 used to resolve to Bilinear, now Nearest.
private const val KEY_CAS_MODE_BILINEAR = "config.migrated.casModeBilinear"
@@ -154,6 +156,25 @@ object ConfigStore {
MainActivityRuntime.prefs.edit { putBoolean(KEY_AFFINITY_ON, true) }
}
// ...and undo it. The migration above turned the scheduler on so the big.LITTLE mask
// would apply, keeping SPU and RSX off the A510s. That is right for one thread per core
// and wrong at six: the mask hands the six SPU threads four cores between them, so each
// gets about two thirds of one, which is worse than a thread owning an A510 outright.
//
// Measured in game on a Snapdragon 8 Gen 2, from the masks the threads actually carry:
// Android grants the app cores 0-7, we confine SPU to 3-6, and the device sits at 60%
// with cores 0-2 idle while frames are slow. Web of Shadows is visibly better at OS.
//
// Same reason these devices are reported to do better under native Linux, which applies
// no such policy. The other modes stay selectable.
if (!MainActivityRuntime.prefs.getBoolean(KEY_AFFINITY_OS, false)) {
if (raw != null && parsed.affinityMode == 2) {
parsed = parsed.copy(affinityMode = 0)
dirty = true
}
MainActivityRuntime.prefs.edit { putBoolean(KEY_AFFINITY_OS, true) }
}
// Undo the relaxed-ZCULL default: it stopped Skate 3 rendering.
if (!MainActivityRuntime.prefs.getBoolean(KEY_RELAXED_ZCULL_OFF, false)) {
if (raw != null && parsed.ps3.relaxedZcull) {
@@ -576,13 +576,28 @@ data class Settings(
/**
* Thread Scheduler Mode: 0 = OS, 1 = RPCS3, 2 = RPCS3 Alternative.
*
* 2 by default. Anything other than OS makes cpu_thread apply an affinity
* mask, which now means something on Android: the mask logic understands
* big.LITTLE and keeps SPU/RSX on the fast cluster instead of letting the
* scheduler drop them on A510s that run at ~27% of prime-core capacity.
* Left at OS this is a no-op and six SPU threads get scattered.
* 0 by default. This was 2, to keep SPU and RSX off the A510s, which run at
* roughly 27% of prime-core capacity. The reasoning holds for one thread per
* core and breaks down at six.
*
* Measured on a Snapdragon 8 Gen 2, in game, reading the masks the threads
* actually carry:
*
* app cpuset (top-app) 0-7 Android grants every core
* SPU[0..5] 3-6 six threads, four cores
* rsx::thread 3-7
*
* Six SPU threads sharing four cores get about two thirds of a core each,
* which is worse than one thread owning an A510 outright, and it caps the
* whole emulator: the device sat at 60% with cores 0-2 idle while frames
* were slow. Spider-Man: Web of Shadows is visibly better at OS.
*
* The mask is ours, not Android's, which is also why these devices are
* reported to run better under native Linux, where no such policy applies.
*
* The other modes remain selectable for anyone whose device disagrees.
*/
val affinityMode: Int = 2,
val affinityMode: Int = 0,
/** EmuCore/GS FramerateNTSC — the emulated PS2 vsync rate for NTSC games
* (PCSX2 default 59.94). Lowering it slows the game's target rate; raising it
* speeds it up. Mirrors NetherSX2's "Framerate For NTSC". */