Game Mode never engages for my card game

Environment: macOS 26.5, M4 Pro, native SwiftUI app (no MTKView/game render loop; it does use SwiftUI Metal shader effects).

There's a related scheduling puzzle underneath: my app's worker threads are confined to E-cores for work that runs on P-cores from a CLI.

The game computes AI decisions with brief CPU-bound bursts of parallel tree search. The identical library, doing node-count-identical work, runs ~6× slower inside the app than from a CLI on the same machine — the difference is core placement, not the workload. And since several bot decisions run in sequence each hand, that 6× stacks into user-visible seconds at the table:

CLI process, default QoS: ~54ms per decision (P-cores) GUI app, worker threads at .userInitiated and .userInteractive: ~350ms (E-cores) Reproducible from the CLI with taskpolicy clamps: utility ≈ 92ms, background ≈ 584ms The app declares LSApplicationCategoryType = public.app-category.card-games and GCSupportsGameMode = true, and runs native full screen as the frontmost app on Apple Silicon — but Game Mode never engages (no menu-bar controller icon).

Questions:

What are the actual activation criteria for Game Mode? Is a game-style render surface (e.g. MTKView/CAMetalLayer) required beyond the Info.plist declarations? Is E-core placement for a GUI app's non-main-thread compute intended scheduler policy even at userInteractive QoS? What is the supported way for a GUI app to run brief, user-blocking compute on P-cores — is Game Mode the intended lever, or should I be looking at something like os_workgroup?

Thanks for the detailed write-up, and for the measurements. The CLI-versus-app comparison isolates the behavior well.

On Game Mode specifically: on macOS 26 the Info.plist key is LSSupportsGameMode. The key you set, GCSupportsGameMode, is deprecated. The LSSupportsGameMode documentation notes that if the key is not present, Game Mode might not turn on. Adopting LSSupportsGameMode = YES is worth doing.

I would set expectations about what that will and will not do, though. Game Mode's documented purpose is to minimize background activity for smoother gameplay and more consistent frame rates. It is intended for games that are resource intensive enough to benefit. It is not documented as a control over which CPU cores your work runs on, so I would not expect it to change the core placement you are measuring. Even with the key set, the system may not turn it on for an app it does not consider resource intensive enough.

LSSupportsGameMode

There's a related scheduling puzzle underneath: my app's worker threads are confined to E-cores for work that runs on P-cores from a CLI.

What kind of thread API are you using and how are you moving work on/off them?

Based on what you're describing, my guess is that you're accidentally creating a situation where your high priority work starts on an E core and then stays on that E core because the system can't really "force" a thread to jump between cores while that thread is active.

FYI, this is particularly true of CPU bound work:

The game computes AI decisions with brief CPU-bound bursts of parallel tree search.

If locks or disruptions are involved, then those would create opportunities for the scheduler to identify the priority inversion and correct the problem by shifting core types. Of course, that doesn't really work when the work is CPU bound and the QoS relationship isn't "visible" to the scheduler.

I suspect what's happening here:

work that runs on P-cores from a CLI.

...is actually caused by differences in the thread state your work is initiated by/from, NOT the QoS of the work itself. In other words, the reason you're on a P-core is because that's where the work happened to have already been "started", not because your work was specifically "elevated" to a P-core.

What I'd highlight here is that you should be thinking about this in terms of "moving" your critical code to the right context, NOT changing the context of the code that's already executing.

Finally, a comment here:

What is the supported way for a GUI app to run brief, user-blocking compute on P-cores —

The simplest approach is to use dispatch async to run a block at a higher QoS, but the detail here really depends on exactly how your app is architected and what APIs you built around. Take a look at "Tuning your code’s performance for Apple silicon" for a general overview of the API options.

is Game Mode the intended lever?

Specifying Game Mode is definitely not the right lever, as unilaterally elevating the priority of "everything" is basically the same as lowering the priority of an app’s OWN high-priority work. I'd highlight this point from the post above:

"Game Mode's documented purpose is to minimize background activity for smoother gameplay and more consistent frame rates."

By doing this, the system is basically "creating" more resources for your app use by reducing it's own resource usage. That's obviously helpful, but it doesn't directly change how work is prioritized within your own app.

or should I be looking at something like os_workgroup?

os_workgroup is not going to be helpful here.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Game Mode never engages for my card game
 
 
Q