Skip to content

Add per-game configuration override (for cpu pinning) - #572

Open
mtslzr wants to merge 4 commits into
FeralInteractive:masterfrom
mtslzr:per-game-config
Open

Add per-game configuration override (for cpu pinning)#572
mtslzr wants to merge 4 commits into
FeralInteractive:masterfrom
mtslzr:per-game-config

Conversation

@mtslzr

@mtslzr mtslzr commented Aug 5, 2026

Copy link
Copy Markdown

Elden Ring crashes when using gamemoderun with core pinning. I was using a script workaround to load a different config file on-the-fly, which was (at best) messy. This adds an option for per-game configuration files, living in ~/.config/gamemode.d/ (also ties to previous per-game use-cases, such as #388 and #570).

The change lets users pass GAMEMODE_CONFIG=x into Steam launch options, which then dynamically loads x.ini from the gamemode.d folder. Passes all tests (build, format-check, meson test). Confirmed working locally (Elden Ring now launches properly for me using GAMEMODE_CONFIG=eldenring gamemoderun %command%). Also tested against invalid names, invalid values, with and without overrides.

I originally looked at just checking the process name and using that to match to the file (so eldenring.exe would look for eldenring.ini). This worked in testing (gamemoderun sleep 5 would properly check for sleep.ini), but launching a game via Steam would look for env every time. This is because the game itself is a Windows process under Wine inside pressure-vessel, where the LD_PRELOAD never loads, so only the wrapper processes ever register with gamemode.

Additionally, names are restricted to [A-Za-z0-9_-] to prevent path traversal; config files can only be loaded from the gamemode.d folder (confirmed by testing with GAMEMODE_CONFIG=../badconfig and it being rejected). Verified the override holds across the reaper's periodic re-pinning and config reloads too.

This was intentionally scoped to only pin_cores to solve my personal issue with Elden Ring, and keep it more easily reviewable. Further keys can be added using the same pattern. Happy to adjust the approach; I would love to see a per-game solution for gamemode.

@mdiluz

mdiluz commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Cool idea! I like the implementation, it seems simple enough. I'm intending something similar in a fork, though I was gonna allow specifics within the existing configs, paired with an envar or a filter of some kind, like so:

[cpu]
pin_cores.eldenring=yes

But this approach offers similar versatility without the up-front complexity, so that's cool.

There's a few caveats that maybe are worth solving:

  • Only loading gamemode.d from the user's config home is inconsistent with the other config files using this full list. That might be easy enough to do though with a simple refactor.
  • GameMode won't reload (and re-apply) these files when changed, which is inconsistent with the other config files. This... may be harder to do than is worthwhile in the current codebase.
  • I'm not a huge fan of the maintenance of two config formats with risk of divergence or inconsistency. Not 100% sure on the solution, but it would seem preferable to share more code if possible between the two.

Comment thread daemon/gamemode-context.c Outdated
@mdiluz

mdiluz commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

This is because the game itself is a Windows process under Wine inside pressure-vessel, where the LD_PRELOAD never loads, so only the wrapper processes ever register with gamemode.

Actually worth mentioning this - I had assumed more recent code was accounting for this in gamemode-wine.c. Is that no longer working? Worth a bug report if so.

@mtslzr

mtslzr commented Aug 6, 2026

Copy link
Copy Markdown
Author

Thanks for the review! Looking at your comments in order...

Config locations: good call. I changed it to search all of the same locations as the main gamemode.ini, but using gamemode.d/. I left out $PWD since that seems to be a bit of an oddball (ironically, misunderstanding it to be the game's directory is what started me down this rabbit hole). Let me know if I should add that as well (for full parity).

Reload: agreed it doesn't match. I am open to trying to tackle it, but like you said, it doesn't seem as easy. I added a line to the README noting it, but let me know if this is a blocker.

Multiple config formats: I am not married to any particular solution. I'll admit, I really liked the ideaof pin_cores.eldenring you shared; I hadn't thought of that when trying this out. I didn't want to just open another issue saying, "please add per-game support" so I figured I'd toss a hat in the ring. I actually think they're kinda complimentary, but not sure both options are needed. TLDR: I'm flexible; if multiple files isn't the play, let me know.

gamemode-wine.c: I don't know if the wine resolution is broken; it doesn't get to wine in this environment. Under pressure-vessel, libgamemodeauto's LD_PRELOAD fails to load in the container, so only the wrapper processes (env, bash) ever register; eldenring.exe never does.

Here's an excerpt from my local testing (Fedora 44 KDE, native RPM Steam, GE-Proton11-3)
======================
Proton: 1784963766 GE-Proton11-3
SteamGameId: 1245620
depot: 4.0.20260608.242786
pressure-vessel: 0.20260601.0
steamrt4: 4.0.20260608.242786 steamrt4 4.0.20260608.242786
Kernel: Linux 7.1.6-201.fc44.x86_64
======================
Inherited environment
DISPLAY: :0
======================
gamemodeauto: dlopen failed - libgamemode.so: cannot open shared object file: No such file or directory
gamemodeauto: dlopen failed - libgamemode.so: cannot open shared object file: No such file or directory
gamemodeauto: dlopen failed - libgamemode.so: cannot open shared object file: No such file or directory
ntsync: up and running.
gamemodeauto: dlopen failed - libgamemode.so: cannot open shared object file: No such file or directory
10191.037:0028:002c:trace:seh:install_bpf Installing seccomp filters.
10191.038:0028:002c:trace:loaddll:build_module Loaded L"C:\windows\system32\wineboot.exe" at 00006FFFFFC0000: builtin

The failures start immediately at container start (before wineboot) and repeat throughout launch (there were 24 total counts here; I obviously trimmed the log down).

Happy to open a separate bug report for this with the full log output, if that would help.

@mdiluz

mdiluz commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Lovely. I'm not a maintainer (haven't been for almost a decade at this point) so we'll see what Feral thinks!

(And yes, the wine thing is worth reporting separately!)


(Sorry for micro-essay below, just dumping thoughts)

From my perspective I'll say this may not be the direction I'd go, after some consideration. I think the TL;DR is that this kind of invents a new concept along the lines of GameMode config "profiles", but the instigating problem-to-solve didn't really need that in its full form, resulting in some possibly confusing behaviours going forward.

Client Control

This has the side effect of giving clients control over their own optimisations, but as that's only an "emergent feature" it's not particularly usable. e.g. A client might think to try and set the environ before requesting GameMode, but:

  • The client wouldn't really know which "profiles" are available
  • There is a race condition in terms of when they set that environ (e.g. they could set it before an explicit request, but if the libgamemodeauto has already done the request, it won't work)
  • (As mentioned) Changing that environ on the fly won't do anything

I think this one might be solvable, but it also means feature work towards a need thats not really defined - I've not seen a request to allow clients to control themselves like this, so we'd have no "real world" use case to validate against.

Convenience

This requires a user to do two things to use this feature:

  • Set up a new config file
  • Set the envar in some way

Ideally a single step solution would be preferable and a sign of a more elegant design.

Client Only

This one might be my UX brain speaking but these "profiles" only controling the client might cause more confusion in almost the same way that the $PWD config location has caused confusion for many reporters here on the repo - it implies a new "profile" could be created and have system optimisations set in it, to have an affect on those system values.

This one maybe should be solved in this review by rejecting rather than ignoring unknown values in these files, but does reveal a wider design issue.


I think I'm leaning more towards allowing a client to set GAMEMODE_CPU_PIN_CORES=xxx directly as it avoids the "profile feature" complications, but it still doesn't fully solve some of the above issues and would probably be more messy to implement.

Another alternative would be to have a new section in the config where a user defined a pattern match to the exe or process name, and then chooses custom settings in there. Again doesn't fully solve things (especially with the identified wine issue) but would I think be a step closer to an elegant solution.

I'll ponder it for longer.

@mtslzr

mtslzr commented Aug 7, 2026

Copy link
Copy Markdown
Author

Agreed with pretty much everything you've said. Not sure a whole per-game system with multiple configuration files is totally worth it for the rare exception (in my case, Elden Ring is the only one). In that case, something like passing a pin_cores.eldenring or GAMEMODE_CPU_PIN_CORES seems more straightforward for a user.

I'll defer to your expertise on the codebase; if we move forward with this, awesome. If you wanna go a different direction, I'm down to help or see how that goes. I've been using my branch's gamemoded since I opened the PR and it solves my issue... but I also dunno if/when I'd ever use it again. So it might be overkill/extra complexity for minimal gain.

I think some form of workaround for situations like Elden Ring where one setting needs to be tweaked would be immensely useful; it's just a matter of what the easiest route to that is (both code-wise and UX-wise).

Anyways, I look forward to what comes of this!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants