Live data from Hacker News

Fixing stutters in Papers Please on Linux

blog.jhm.dev

71–80 of 202 posts

Re: Fixing stutters in Papers Please on Linux

#71
I really enjoyed the debugging process here, and am glad to have learnt about the -k flag which seems to only be available on systems with strace version 5.5, at least for me.

As for the patch (and my love for all things Frida [1]), I think a call to Intercerptor.replace() after locating the symbol with Module.getExportByName() [2] would make for a simpler patch (at the cost of installing Frida). For example:

  const sym = Module.getExportByName("lime.ndll", "SDL_SemWait");
  Interceptor.replace(sym, {
    onEnter: function() {},
    onLeave: function() {}
  });
[1] https://frida.re/

[2] https://frida.re/docs/javascript-api/#module

Re: Fixing stutters in Papers Please on Linux

#72

Earlier quoted context omitted.

What the proposed patch does is delay a specific latent operation to an asynchronous context so that close() doesn’t block on that operation (which is freeing some memory). The proposed patch isn’t a comprehensive fix, it admits there are still other sources of relatively high close() latency. So that got me thinking, there is no way to fix this “bug” because there is no specification on how long close() should take…

Or, io_uring the thing. One could probably wrap close() with LD_PRELOAD and not touch the binary...

While tempting, you can’t generally fix this by simply patching close() with some function that converts it to an unchecked asynchronous operation. If that were the case, you could just do that in the kernel. Close() is expected to complete synchronously. This matters because posix guarantees that open()/pipe() etc. will return the lowest file descriptor not in use[1]. I.e. this should work:

    close(0);
    fd = open(“/foo/bar”, …);
    // fd is guaranteed to be 0
If you made close() just dispatch an asynchronous operation and not wait on the result, then the code above would break. Any code that uses dup() likely has code that expects close() to behave that way.

The other issue is that close() can return errors. Most applications ignore close errors but to be a robust solution you’d need to ensure the target application ignores those errors as well.

[1]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/V...

Re: Fixing stutters in Papers Please on Linux

#73
post #23

Earlier quoted context omitted.

Exactly. It should enumerate them when the player opens settings. Or at startup. But even if it wants to do this, why is it doing it on the main thread!? :(

If I start the game without a gamepad attached to the computer, and then attach the gamepad, I'd like to use the gamepad without restarting the game. And one would expect that polling the attached input devices should never take hundreds or thousands of milliseconds, there must be something seriously wrong in the Linux input device stack or maybe in one of the input device drivers.

The input stack is fine, this game disabled the things that would let it work nicely (see upthread discussion of SDL supporting udev and inotify)

Re: Fixing stutters in Papers Please on Linux

#74
post #67
post #61

Earlier quoted context omitted.

I've been wondering.. is it possible to write something to override the statically linked functions? In this case, most (if not all) functions have an SDL_ prefix. Would it be possible to LD_PRELOAD a library that loads a shared version of SDL and goes over all the function pointers to move them point them to a new location? Is there a tool for this?

> I've been wondering.. is it possible to write something to override the statically linked functions? SDL does have a built-in way to do that trick. A quick web search tells me it's called SDL_DYNAMIC_API.

cool, I never knew! Somehow the game I thought it would add a feature is still lacking it. For some reason rumble on my xbox joystick with Enter the Gungeon never worked. I thought it was because of an old SDL version, because experimentation showed that. But by using the SDL_DYNAMIC_API env and loading my system SDL the game still not added rumble to my joystick. Ohwell.

Re: Fixing stutters in Papers Please on Linux

#75
post #14

Earlier quoted context omitted.

If you are advanced enough to run Gentoo, you should be able to use Debian and force an install of (or re-compile yourself) a new package of the newer version, working around the fact that the official newer version would otherwise require other new packages.

You could. But the amount of time it takes is significantly more than yay -S or emerge vs the hell that this poses on Debian (not to mention the dependency hell you can run into)

I don't know the situation on Gentoo, but partial updates are explicitly unsupported on Arch, not least because they don't do stable ABIs; Debian should have a much easier time upgrading just one package.

Re: Fixing stutters in Papers Please on Linux

#76
post #7

The issue has been identified before, but seems like it stalled: https://gitlab.freedesktop.org/libinput/libinput/-/issues/50... , https://patchwork.kernel.org/project/linux-input/patch/20201... .

What the proposed patch does is delay a specific latent operation to an asynchronous context so that close() doesn’t block on that operation (which is freeing some memory). The proposed patch isn’t a comprehensive fix, it admits there are still other sources of relatively high close() latency. So that got me thinking, there is no way to fix this “bug” because there is no specification on how long close() should take…

close() is typically a blocking operation. But when it happens in devfs, procfs, tmpfs, or some other ram only filesystem I expect it to be fast unless documented otherwise.

Re: Fixing stutters in Papers Please on Linux

#77

Earlier quoted context omitted.

What the proposed patch does is delay a specific latent operation to an asynchronous context so that close() doesn’t block on that operation (which is freeing some memory). The proposed patch isn’t a comprehensive fix, it admits there are still other sources of relatively high close() latency. So that got me thinking, there is no way to fix this “bug” because there is no specification on how long close() should take…

close() is typically a blocking operation. But when it happens in devfs, procfs, tmpfs, or some other ram only filesystem I expect it to be fast unless documented otherwise.

> I expect it to be fast unless documented otherwise.

Logically you should expect it to block indefinitely unless documented otherwise. The exception would be completing within a time bound, the rule is blocking indefinitely.

Re: Fixing stutters in Papers Please on Linux

#78
post #7

The issue has been identified before, but seems like it stalled: https://gitlab.freedesktop.org/libinput/libinput/-/issues/50... , https://patchwork.kernel.org/project/linux-input/patch/20201... .

I just did a quick check the posted fix is not in the most recent -rc branch in the public git repo.

This is the issue with using mailing lists... Large numbers of perfectly good fixes, embodying many hours of effort, just get missed and forgotten about.

At least with GitHub PR's, every request either needs to be merged or rejected.

Re: Fixing stutters in Papers Please on Linux

#79

Earlier quoted context omitted.

You could. But the amount of time it takes is significantly more than yay -S or emerge vs the hell that this poses on Debian (not to mention the dependency hell you can run into)

I don't know the situation on Gentoo, but partial updates are explicitly unsupported on Arch, not least because they don't do stable ABIs; Debian should have a much easier time upgrading just one package.

Having used Arch and Debian, I‘ve definitely had an easier time installing the latest version of arbitrary packages on Arch. Something like SDL is part of base and thus is already running latest.

Re: Fixing stutters in Papers Please on Linux

#80

Earlier quoted context omitted.

Or, io_uring the thing. One could probably wrap close() with LD_PRELOAD and not touch the binary...

While tempting, you can’t generally fix this by simply patching close() with some function that converts it to an unchecked asynchronous operation. If that were the case, you could just do that in the kernel. Close() is expected to complete synchronously. This matters because posix guarantees that open()/pipe() etc. will return the lowest file descriptor not in use[1]. I.e. this should work: close(0); fd = open(“/foo…

[deleted]
Post reply on HN