Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proton 5.13-2 does not allow CPU affinity to be set #304

Closed
wwmm opened this issue Nov 29, 2020 · 26 comments
Closed

Proton 5.13-2 does not allow CPU affinity to be set #304

wwmm opened this issue Nov 29, 2020 · 26 comments

Comments

@wwmm
Copy link

wwmm commented Nov 29, 2020

In older versions it was possible to set the CPU affinity using something like taskset -c 0-4 %command% in Steam launch options. It does not work in Proton 5.13. Is this a soldier bug?

@wwmm wwmm changed the title Proton 5.13-2 does allow CPU affinity to be set Proton 5.13-2 does not allow CPU affinity to be set Nov 30, 2020
@smcv
Copy link
Contributor

smcv commented Dec 1, 2020

I think this might still work for some Windows games under Proton, but it won't work for anything that has setup commands to be run before the game itself (like installing Windows DLLs). That's because we have to start the container to run the setup commands, which already happens before Steam does anything with the launch options.

When Steam gets as far as running the actual game, it's too late to change how the container started, because it was already started, and processes inside the container will inherit the default CPU affinity from the container manager, instead of inheriting the restricted CPU affinity from what Steam thinks is the actual game (but is actually a stub process that tells processes already inside the container to run the correct command over there).

The same is true for all process parameters other than arguments and environment variables. The launch options interface is very, very general, and it isn't possible to propagate everything to an unrelated part of the process tree.

@wwmm
Copy link
Author

wwmm commented Dec 1, 2020

I imagined that was the reason. At first I did not think this would be a problem to me because I am development a software based on the kernel Process Events Connector that could apply affinity after the game has started. I tried that but after some time I realized there is a problem in this approach. At this point the game has already seen how many cores my cpu has and launched an amount of threads that would make sense when using all the cores. Obviously not what we want when setting affinity. So in this case there is no point in setting it after the game has started. Unfortunately.

@smcv
Copy link
Contributor

smcv commented Dec 1, 2020

It might be possible to set up some way to wrap just the actual game in adverbs like taskset, but it's going to be quite a mess. The launch options field is fine for command-line options (launch options = --debug), and works if you're lucky for environment variables (launch options = FOO=bar %command%), but arbitrary "adverb" commands like taskset and nice are always going to be awkward.

When using compat tools like Proton and pressure-vessel, it has also ended up with two partially-compatible meanings: some of the options apply to the compat tool, some of the options apply to the actual game, people use it for both, and sometimes the intention was to apply them to one but they really get applied to the other.

@wwmm
Copy link
Author

wwmm commented Dec 2, 2020

I think I have found a workaround that would work at least for me. As I am already using the kernel Process Events Connector my app can be notified about the pressure-vessel initialization and apply affinity to it. As far as I could see the first process related to pressure-vessel to be shown by the event connector is _v2-entry-point. And applying affinity to it results in affinity applied to the game. Hopefully the game is considering the number of cpu cores set in _v2-entry-point affinity mask.

Is _v2-entry-point the first pressure-vessel process to be started or is there another one that would be more appropriate? Is there any kind of undesirable side effect that could come from setting pressure-vessel affinity?

@smcv
Copy link
Contributor

smcv commented Dec 2, 2020

pressure-vessel-wrap would probably be a more appropriate process to target with that workaround: it's the one that actually starts the container, so every process that runs inside the container has to be a child or descendant of it.

_v2-entry-point is a parent of all the processes involved (including short-lived setup stuff that runs outside the container), but as the comment at the top says, it probably isn't going to continue to exist in its current form forever. A lot of what it does is currently in shell script for rapid prototyping, but is likely to move into C code for better error-checking in future.

@wwmm
Copy link
Author

wwmm commented Dec 2, 2020

As the comm property for the tasks under /proc has a size limit of 15 characters the name pressure-vessel-wrap will be truncated to pressure-vessel. The easy way is to set affinity to all process with the comm property equal to pressure-vessel. It works just like setting affinity to _v2-entry-point.

The event connector also gives the whole command line that was used to initialize the process. I will see if I can target only pressure-vessel-wrap by searching for its string in the command line of process where comm = pressure-vessel

@smcv
Copy link
Contributor

smcv commented Dec 2, 2020

One day I might rename the native-code executables to pv-wrap, pv-adverb and so on to make them easier to find in /proc...

@smcv
Copy link
Contributor

smcv commented Dec 2, 2020

Targeting every pressure-vessel* process for something like CPU affinity is almost certainly harmless. The only one that does a significant amount of work itself is pressure-vessel-wrap, and the only child processes that do a lot of work are Proton and the games themselves.

@smcv
Copy link
Contributor

smcv commented Dec 4, 2020

We might be able to solve this in a future release by shutting down the container after the setup commands have run, and starting a new container that takes the launch options into account. I had been concerned that this would add too much time to container startup, but it looks as though it might only add a couple of seconds in practice.

@smcv
Copy link
Contributor

smcv commented Dec 15, 2020

We might be able to solve this in a future release by shutting down the container after the setup commands have run, and starting a new container that takes the launch options into account.

In the latest beta version of SteamLinuxRuntime_soldier, you can try this out by running Steam with PRESSURE_VESSEL_RELAUNCH_CONTAINER=1 in the environment. It will make container startup slower, but it will mean that "adverb" commands in the launch options get taken into account. Please let me know how well it works for you!

For reference, you want VERSIONS.txt to say SteamLinuxRuntime v0.20201124.0-11-g197f448 or higher.

Depending how well it works in terms of performance and functionality, we might make this mandatory in a later version, or keep it opt-in, or drop it entirely. It might even become enabled by default with an opt-out, but probably not for very long, because if it's good enough to be on by default, making it mandatory would let us delete quite a lot of relatively complex code.

@wwmm
Copy link
Author

wwmm commented Dec 18, 2020

How do I install the beta version? I never did that. My current runtime soldier version is v0.20201124.0-2-g0f9c98f

@wwmm
Copy link
Author

wwmm commented Dec 18, 2020

It is in the properties menu. I will install it

@wwmm
Copy link
Author

wwmm commented Dec 19, 2020

Please let me know how well it works for you!

Affinity configuration works after setting PRESSURE_VESSEL_RELAUNCH_CONTAINER=1. But I have to do more tests about the delay. At first sight it did not seem to make much difference. But so far I tested only 2 games.

@smcv
Copy link
Contributor

smcv commented Dec 19, 2020

The slightly slower startup should be the same for every Proton game: it's to do with the container runtime, not the game. In my tests on old/slow hardware, the "cost" of relaunching was something like 2-3 seconds. On a faster machine with SteamLinuxRuntime_soldier installed on SSD, the difference will hopefully be less than that.

We did have one report of very long startup times where this would have made a bigger difference (#323), but that's caused by a special configuration (a very high soft limit on the number of open files), and a change to avoid that problem is likely to go out in a new beta sometime in January.

@wwmm
Copy link
Author

wwmm commented Dec 20, 2020

In that case I don't see a reason for not doing this by default.

@wwmm
Copy link
Author

wwmm commented Dec 25, 2020

Relaunching the container seems to be causing problems in cyberpunk. I had to use its --launcher-skip option for it to start. Without it I see this in the system log:

steam.desktop[4256]: terminate called after throwing an instance of 'dxvk::DxvkError'

If I do not set PRESSURE_VESSEL_RELAUNCH_CONTAINER cyberpunk shows a window with useless things before starting the game. For some reason this window initialization is crashing when the container is relaunched.

@wwmm
Copy link
Author

wwmm commented Jan 30, 2022

Was there any change to how PRESSURE_VESSEL_RELAUNCH_CONTAINER=1 works? I ask because custom cpu affinity does not seem to be working while other things like environmental variables and scheduling policies are.

@kisak-valve
Copy link
Member

Hello @wwmm, are you still experiencing this issue on an up to date system?

@wwmm
Copy link
Author

wwmm commented Jul 14, 2022

Hello @wwmm, are you still experiencing this issue on an up to date system?

Yes @kisak-valve. I tried the following

PRESSURE_VESSEL_RELAUNCH_CONTAINER=1 taskset -c 0-4 %command%

with Monster Hunter Rise and when I checked the affinity settings with taskset -acp all the 16 threads of my Ryzen 3700X were being used. The taskset affinity was ignored.

At this moment I am using Soldier [client_beta] and the current Proton Experimental.

@kisak-valve
Copy link
Member

ValveSoftware/Proton#5927 might interest you as an alternative approach.

@smcv
Copy link
Contributor

smcv commented Jul 14, 2022

Was there any change to how PRESSURE_VESSEL_RELAUNCH_CONTAINER=1 works?

Modern versions of pressure-vessel always behave like PRESSURE_VESSEL_RELAUNCH_CONTAINER=1.

The environment variable is ignored, and the old PRESSURE_VESSEL_RELAUNCH_CONTAINER=0 code path (the pre-2021 default) no longer exists. This was done because various other things, other than CPU affinity, were also broken by that code path.

I ask because custom cpu affinity does not seem to be working while other things like environmental variables and scheduling policies are.

I'm not aware of any changes that would have affected CPU affinity behaviour, but it sounds as though there might be something that specifically affects CPU affinity and not other aspects of the execution environment? (But I don't know how that would happen... as far as I'm aware, CPU affinity is inherited in the same way as any other scheduling parameter.)

@wwmm
Copy link
Author

wwmm commented Jul 14, 2022

But I don't know how that would happen... as far as I'm aware, CPU affinity is inherited in the same way as any other scheduling parameter.

I haven't done tests about the scheduling in a while. But taskset definitely does not work.

@wwmm
Copy link
Author

wwmm commented Jul 14, 2022

might interest you as an alternative approach.

I was not aware of WINE_CPU_TOPOLOGY. Yes, this works.

@smcv
Copy link
Contributor

smcv commented Jul 14, 2022

Is it possible that Proton/Wine is resetting the CPU affinity, overruling whatever you set with taskset? If it is doing that, then nothing we can do in SLR is going to change that: only reconfiguring Proton/Wine is going to change that behaviour.

@smcv
Copy link
Contributor

smcv commented Jul 14, 2022

I tried running a native Linux game under SteamLinuxRuntime (I used CS:GO), and running a Windows game under Proton (I used the Ghostrunner demo under Proton Experimental), both wrapped in taskset -c 1 %command%. Both seem to inherit affinity for CPU 1.

However, if the game itself is changing its CPU affinity, I suspect Wine will just pass that through to the Linux-side process that implements it, the same way that if you run

taskset -c 1 taskset -c 2-3 sh -c 'taskset -c -p $$'

you'll find that the sh process is running on CPUs 2 and 3. (This example assumes a 4-core or better CPU.)

@wwmm
Copy link
Author

wwmm commented Jul 14, 2022

However, if the game itself is changing its CPU affinity, I suspect Wine will just pass that through to the Linux-side process that implements it

I did not consider this possibility. I tested now with A Plague Tale Innocence and the affinity set by taskset is there. Differently from what is happening with Monster Hunter Rise. So the game is probably the one changing it.

As WINE_CPU_TOPOLOGY is enough for my needs and seems to work in all cases I think we can close this issue.

@wwmm wwmm closed this as completed Jul 14, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants