Live data from Hacker News

Fixing stutters in Papers Please on Linux

blog.jhm.dev

61–70 of 202 posts

Re: Fixing stutters in Papers Please on Linux

#61

Earlier quoted context omitted.

SDL should probably use inotify() on linux so the kernel can let it know when /dev/input has changed rather than polling it.

SDL has three methods for detecting input devices [1]: udev, inotify, and, as a fallback, enumerating /dev/input. It seems like Papers, Please uses a statically linked version of SDL, without udev or inotify support compiled in. 1: https://github.com/libsdl-org/SDL/blob/d0de4c625ad26ef540166...

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?

Re: Fixing stutters in Papers Please on Linux

#62
post #38

Earlier quoted context omitted.

Ah, but are /dev/input entries reusable? Let's say you have /dev/input/event{0,10}, event5 is a USB keyboard, you unplug it, I assume event5 goes away. But then you plug in a controller, does this get mapped to event11, or does event5 get reused? Is the behaviour reliable in all versions of linux? You might argue that metadata should do the trick, but in my experience, on device files, anything beyond read/write is a…

The actual SDL fix was even simpler, they now just check if the mtime of the /dev/input directory changed: https://github.com/spurious/SDL-mirror/commit/59728f9802c786...

Upstream fixes are nice, but since the game statically links SDL you can't put in a newer version of libSDL.so in the game path and have it patched like that. Are there other ways of patching statically linked binaries with updated functions?

Re: Fixing stutters in Papers Please on Linux

#63
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…

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

Re: Fixing stutters in Papers Please on Linux

#64
post #8

Why is the engine even checking input devices so often? Shouldn't the input device be registered via settings and then assumed to exist when the game runs? It seems wasteful to check all input devices every few seconds.

SDL should probably use inotify() on linux so the kernel can let it know when /dev/input has changed rather than polling it.

Actually, I think the truly preferred path is to just monitor for udev events, which SDL supports but is presumably not enabled for Papers, Please for one reason or another.

Re: Fixing stutters in Papers Please on Linux

#65

Earlier quoted context omitted.

Because this is the fallback when you compile without udev support

I can guess that, but I was wondering why ... Is there a distro without udev? The steam/whatever sandbox does not support udev?

It's not the system that is not supporting udev, it's the choice of the game developers how they compiled SDL .. without dependencies, and so without udev.

Re: Fixing stutters in Papers Please on Linux

#66
post #61

Earlier quoted context omitted.

SDL has three methods for detecting input devices [1]: udev, inotify, and, as a fallback, enumerating /dev/input. It seems like Papers, Please uses a statically linked version of SDL, without udev or inotify support compiled in. 1: https://github.com/libsdl-org/SDL/blob/d0de4c625ad26ef540166...

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?

Well if you know where to fork, you could use Intel Pin and divert the CFG, favorite tool for binary 'patching'.

Edit: though here if it's a problem of file enumeration and access, I'd probably just LD_PRELOAD something to bypass libc file access functions and return the same result than the first time, with no delay.

Re: Fixing stutters in Papers Please on Linux

#67
post #61

Earlier quoted context omitted.

SDL has three methods for detecting input devices [1]: udev, inotify, and, as a fallback, enumerating /dev/input. It seems like Papers, Please uses a statically linked version of SDL, without udev or inotify support compiled in. 1: https://github.com/libsdl-org/SDL/blob/d0de4c625ad26ef540166...

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.

Re: Fixing stutters in Papers Please on Linux

#68
post #60

Wait, why is `close` in libpthread.so?

I believe that a few libc functions are reimplemented in libpthread, the idea being that if you don’t link to pthreads, you don’t need the overhead (locking, etc.) that is needed in multithreaded situations. Feels a bit antiquated now… As for why close specifically though, that’s a good question. I wonder if it has something to do with special libc treatment of the standard fds or anything like that.

As you can see in the disassembly, it has to do with implementing async cancellation. I think they wrap many blocking syscalls in the same way. https://man7.org/linux/man-pages/man3/pthread_cancel.3.html

Re: Fixing stutters in Papers Please on Linux

#69

Wait, why is `close` in libpthread.so?

> why is `close` in libpthread.so?

That's because close() is a pthreads "cancellation point" (see https://man7.org/linux/man-pages/man7/pthreads.7.html for details), so it needs special handling when the process is using pthreads. If the process does not link to libpthread.so, the implementation in libc.so (which probably doesn't have cancellation point support) will be used.

Post reply on HN