Live data from Hacker News

Fixing stutters in Papers Please on Linux

blog.jhm.dev

101–110 of 202 posts

Re: Fixing stutters in Papers Please on Linux

#101
post #81

Earlier quoted context omitted.

> Logically you should expect it to block indefinitely Frankly, that’s completely insane. It should block if and only if there is actual io in flight which could produce a failure return that an application needs. Syscalls should be fast unless there is a very good reason not to be.

> It should block if and only if there is actual io in flight which could produce a failure return that an application needs. Blocking simply means that the specification does not guarantee an upper bound on the completion time. There is no other meaningful definition. POSIX is not an RTOS therefore nearly all system calls block. The alternative is that the specification guarantees an upper bound on completion time.…

> The reality is that system calls aren’t “fast” and they can’t portably or dynamically be guaranteed to be fast.

Perhaps, but the reality is also that the vast majority of games and other interactive applications routinely make blocking system calls in a tight main loop and expect these calls to take an unspecified but reasonable amount of time.

“It’s a blocking syscall so if it takes 1s to close a file, that’s technically not a bug” is correct, but is any player of “Papers, Please” going to be sympathetic to that explanation? Probably not; they’ll think “Linux is slow,” “Linux is buggy,” “why can’t Linux run basic applications correctly that I have no problem running on Windows or OS X?,” etc.

“Syscalls should be fast unless there is a very good reason not to be” strikes me as a wise operating principle, which weights usability and usefulness of the operating system alongside being technically correct.

Re: Fixing stutters in Papers Please on Linux

#102
post #65

Earlier quoted context omitted.

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.

That's standard for game devs in the Linux world. The less dependencies you have to rely on the distribution for, the better - Windows stuff is either already present or shared OS-wide with binary backwards compatibility (=DirectX), so you can get away with shipping stuff that has a chance to run even 25 years in the future without major modification.

Re: Fixing stutters in Papers Please on Linux

#103
post #92
post #88

Earlier quoted context omitted.

Very similar to people using node.getenv in hot sections of code and the resulting not understanding what's happening. https://github.com/nodejs/node/issues/3104 When you call out to the sys or libc things are going to happen and you should try and be aware of what those are.

Sorry... what? Why the hell was an application using env() to carry application state?! The environment list is created at init, it's literally placed right behind the C argument list as an array -- AUXV if you want to go read the ABI Specification for it. Therefore, anything you grab using getenv() can be considered to be static (Barring use of setenv), so the proper and correct thing to do is shove the things you n…

… unless you intend to exec after forking

Re: Fixing stutters in Papers Please on Linux

#104
post #96
post #89

Earlier quoted context omitted.

> Blocking simply means that the specification does not guarantee an upper bound on the completion time. I don't think that's a commonly-accepted (or useful) definition of "blocking." By that definition, getpid(2) is blocking. > I think this is an instance of confusing what should be with what is. Who is doing the confusing? I said "should be." Are you saying they're fast now but should be slow? Why? > The reality is…

CyberRabbi's definition of blocking is correct and what I've always seen commonly accepted. Blocking means you don't know how long it'll take, and you want to wait for it to finish. The only safe assumption is that you cannot guarantee how long it'll take. getpid is accurately therefore a blocking call. You don't know how long it'll take. You can profile and make best guesses, but you can never assuredly say how long…

I'd say that the commonly accepted definition for a blocking call is one that may depend on I/O to complete, releasing control of the CPU core while waiting.

By that definition, getpid() is definitely nonblocking, though it doesn't have an upper bound in execution time. POSIX does not offer hard realtime guarantees.

close() in general would probably be blocking (as a filesystem may need to do I/O), but I'd expect it to behave nonblocking in most cases, especially when operating on virtual files opened read-only. Unfortunately, I don't think those kinds of behavioral details are documented.

Re: Fixing stutters in Papers Please on Linux

#105
post #93
post #33

I guess that is the kind of challenge to have Windows games on GNU/Linux, fix them instead of playing.

It's not like Windows doesn't have its own issues to fix. Except developers do it anyway, because of the market size. Windows isn't perfect or better for gaming.

> Windows isn't perfect or better for gaming.

This assessment depends entirely on the perspective.

From a developer's POV, Windows definitively is the better platform, as it's very monolithic in that you can rely on the presence and longevity of APIs. Depending on the dev's influence on the market and the success of the game, you even get free optimisation, support, and bug fixes from h/w vendors in the form of game-specific driver patches.

From a gamer's POV, Windows has advantages as well, since bugs are rarely OS-related and h/w vendors offer a lot more features OOTB.

If you love tinkering with the OS and don't care if some titles or features just won't work, Linux is a valid option for gaming. Otherwise Windows is objectively the better option by default, since I can rely on the games working with all available features (e.g. multiplayer).

Re: Fixing stutters in Papers Please on Linux

#106
This looks very like a problem I encountered some time ago running the closed source 3DO emulator "Phoenix Project", and similarly the open source "FreeDO" project that it was forked from. I narrowed it down (also using strace, IIRC) to these programs repeatedly opening and closing the /dev/input/event* files, and that being weirdly slow. I made a seperate little test program just to open and close those files to confirm it. It was only slow on my main desktop machine; while on my lesser-powered laptop, running a practically identical Arch Linux setup, those file operations were quick and the programs ran fine. None of these programs use SDL. I couldn't/didn't progress any further then, but it's good to find some pointers here for further investigation (ie. the libinput issue).

Funnily enough I'm pretty sure I played Papers Please on this machine at length without problems but I think that was probably the Windows version through Wine.

Re: Fixing stutters in Papers Please on Linux

#107
post #101

Earlier quoted context omitted.

> It should block if and only if there is actual io in flight which could produce a failure return that an application needs. Blocking simply means that the specification does not guarantee an upper bound on the completion time. There is no other meaningful definition. POSIX is not an RTOS therefore nearly all system calls block. The alternative is that the specification guarantees an upper bound on completion time.…

> The reality is that system calls aren’t “fast” and they can’t portably or dynamically be guaranteed to be fast. Perhaps, but the reality is also that the vast majority of games and other interactive applications routinely make blocking system calls in a tight main loop and expect these calls to take an unspecified but reasonable amount of time. “It’s a blocking syscall so if it takes 1s to close a file, that’s tech…

> “It’s a blocking syscall so if it takes 1s to close a file, that’s technically not a bug” is correct, but is any player of “Papers, Please” going to be sympathetic to that explanation? Probably not; they’ll think “Linux is slow,” “Linux is buggy,” “why can’t Linux run basic applications correctly that I have no problem running on Windows or OS X?,” etc.

I don’t agree with this logic. Windows and macOS system calls also block. The issue of people considering Linux to be slow is not relevant to the fact that its systems calls block. The poorer quality of Linux games, and commercial Linux software in general, is more likely due to smaller market size / profit opportunity and the consequential lack of effort / investment into the Linux desktop/gaming ecosystem.

Now if your argument is we should work around buggy applications and distribute hacked patches when the developers have abandoned them for the sake of improving user experience. I agree with that.

> “Syscalls should be fast unless there is a very good reason not to be” strikes me as a wise operating principle, which weights usability and usefulness of the operating system alongside being technically correct.

Linux already operates by this principle. We are examining a situation where best effort was not good enough to hide poor application design.

Re: Fixing stutters in Papers Please on Linux

#108
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?

It looks like SDL's public symbols are all global in lime.ndll so LD_PRELOADing SDL should do what you want. Of course it is possible that lime.ndll was built with -fno-semantic-interposition or equivalent in which case the functions might be called directly without going through the dynamic linker or even (partially) inlined.

Re: Fixing stutters in Papers Please on Linux

#109
post #96

Earlier quoted context omitted.

CyberRabbi's definition of blocking is correct and what I've always seen commonly accepted. Blocking means you don't know how long it'll take, and you want to wait for it to finish. The only safe assumption is that you cannot guarantee how long it'll take. getpid is accurately therefore a blocking call. You don't know how long it'll take. You can profile and make best guesses, but you can never assuredly say how long…

I'd say that the commonly accepted definition for a blocking call is one that may depend on I/O to complete, releasing control of the CPU core while waiting. By that definition, getpid() is definitely nonblocking, though it doesn't have an upper bound in execution time. POSIX does not offer hard realtime guarantees. close() in general would probably be blocking (as a filesystem may need to do I/O), but I'd expect it…

A function that sleeps for 5 seconds is blocking. No IO involved.

Blocking just means that you're blocking your current code till you return out of the called function.

Anything else regarding a function call is an assumption unless you know the exact implementation.

Re: Fixing stutters in Papers Please on Linux

#110
post #92

Earlier quoted context omitted.

Sorry... what? Why the hell was an application using env() to carry application state?! The environment list is created at init, it's literally placed right behind the C argument list as an array -- AUXV if you want to go read the ABI Specification for it. Therefore, anything you grab using getenv() can be considered to be static (Barring use of setenv), so the proper and correct thing to do is shove the things you n…

… unless you intend to exec after forking

Sure, but just use execvp and it's a damn sight safer because you know exactly the state of your child's environment state. You can see this in the CERT C coding guidelines: https://wiki.sei.cmu.edu/confluence/display/c/ENV03-C.+Sanit...

also ENV02-C comes into effect, as well, if your program is invoked with

    SOME_INTERNAL_VARIABLE=1 PORT=2000 ./prog
then you try to invoke your child with:

    setenv("SOME_INTERNAL_VARIABLE", "2", 1);
    (fork blah blah)
Post reply on HN