subprocess-posix: use clone in Linux and rfork_thread in FreeBSD#14973
subprocess-posix: use clone in Linux and rfork_thread in FreeBSD#14973ruihe774 wants to merge 4 commits intompv-player:masterfrom
clone in Linux and rfork_thread in FreeBSD#14973Conversation
|
I feel like introducing such additional complex, platform-specific code is not worth it for a vague "lower overhead" in process creation (when is this a bottleneck??). |
I agree, we should evaluate whether it is needed using some test cases that show the actual difference. mpv, under normal operation, shouldn't spawn subprocesses, especially not ones that are performance critical. |
Well, I don't think it's complex. You can also have a look at the new handling of These APIs are also used by |
3e8da39 to
2f6617d
Compare
|
Agree with what's already said. I think there is no reason to maintain 2 additional platform-specific implementations for little benefit when the existing one works. Additionally from FreeBSD documentation: "The rfork_thread() function has been deprecated in favor of pthread_create(3)."
That's a separate issue and does not require the new process creation functions. |
|
Download the artifacts for this pull request: |
Not related IMO. The latter is for creating threads. The functionality used in the code cannot be achieved by
I don't consider they as two separated platform-specific implementations as they only differ in one single line of code of calling the API. As Linux has the de facto dominance, I think it's acceptable to optimize for it with little additional code complexity. You can consider the FreeBSD part as a side product. |
|
A microbenchmark: local utils = require 'mp.utils'
local start_time = mp.get_time()
for i = 1,1000 do
utils.subprocess_detached{
args = {"/bin/echo", "test"}
}
end
local end_time = mp.get_time()
print(end_time - start_time)Tested on Linux 6.11.0: Tested on FreeBSD 13.4: I think the performance improvement is nontrivial. |
5f3f9cd to
b6dc978
Compare
It is non trivial, but, without commenting on the PR itself, on its own it doesn't necessarily carry a lot of weight. The use cases of mpv where hundreds of processes per second are not enough but (many) thousands is just what the doctor ordered are probably not all that common. You have a track record of good code, so that's a good start, but the couter argument is that it's currently (probably) good enough and known to work where needed, while new code does carry risks. But if the reviewers find the new code great, then such a perf improvement is certainly nice. |
Yeah, we can put this aside. |
clone in Linux and rfork_thread in FreeBSDclone in Linux and rfork_thread in FreeBSD
Worth noting that the new POSIX supports this use case: https://www.austingroupbugs.net/view.php?id=1044 |
Yes. But we still need to perform a double-fork in order to detach a child process. Is BTW in fact we can use pidfd with |
|
But in any case, I agree with the rest. Seems not worth it unless there's actual use cases where this matters. |
With Also, posix_spawn has an option to reset all signal-handlers to default ( If |
The problem is that we still need to reap the zombies if we do not double-fork. |
|
FWIW for anyone who is still interested in subprocess creation stuff, you may be also interested in my another PR: ziglang/zig#22368. |
Ah, yeah... the zombies. Looked around a bit but it doesn't seem like posix_spawn has any flags/option to solve this. Maybe there's a better way to reap the child so we don't need to reparent it to pid 1? (Nothing that comes to mind though...) |
We can BTW we cannot assume orphans are reparented to pid 1. It's implementation-defined. And systemd handles orphans in a different way. See https://stackoverflow.com/a/40424702 |
I thought about doing it via SIGCHLD handler. But in either case, that's probably not an option since we'd also need to consider libmpv, I think. One other thing I thought was to collect the detached pids into a dynamic array and attempt to reap them every once in a while with Not sure where the reaping code should go. Would require the dynamic array to be global which has the usual threading issues too. So, yeah... |
|
I have no motivation to make it upstream anymore. Closing it. |
|
Could you revive this, or at least the first commit? It fixes #17669 |
Okay. I can reopen this. |
The Wanting to run N (where N isn't absurdly large) processes in parallel isn't some niche use case nor "bad programming practice", it's fairly common way to do multiprocess parallelism. |
At this point, many factors outside mpv's control can cause underruns. mpv might be preempted out for a few milliseconds by process scheduling.
4 running at a time does not mean 4 processes had ever spawned. The spawned processes die quickly and new ones spawn. So there are still lots of spawned processes.
Yes. And they spawn a few persistent processes at start and use IPC to communicate with them and they do not constantly spawn new processes. It has nothing to do with what you script was doing. |
Just run the mpv build with ninja or w/e. It's obviously not going to spawn N "persistent gcc/clang" processes. It'll spawn one per compilation unit. I'm not interested in derailing this PR further but this is simply not some sort of esoteric user-case/bad-programming practice like you're claiming it to be. |
Does ninja provide an interactive UI and playback audio? Spawning lots processes working for build system does not mean it is universally acceptable. |
On master, this takes around 4000ms for me. While with mpv-player#14973 it completes in 10ms
|
This PR causes stack buffer overflow with https://github.com/mpv-player/mpv/blob/master/TOOLS/lua/command-test.lua Test with: Though I'm not going to tell you to fix it, because it seems like this PR might get blocked to death anyway. |
It's the AddressSanitizer. I believe it's a false positive. |
|
I don't have opinion on this, would have to look into what are the issues and what can we do about them. I think I asked @llyyr is to update
I agree that, we shouldn't spam processes. If we need some separate native process to process thumbnails, it should be spawned once and asked using IPC to do the work. Of course this all is moving the bar higher and is more complex design, but we can see that processes spam is simply not working either. It's not acceptable to stall main playback process for UI related candy. Regardless if it affects audio playback only for "some" users. We identified this limitation among few people testing PR, imagine what will happen if this goes mainline. |
On master, this takes around 4000ms for me. While with mpv-player#14973 it completes in 10ms
On master, this takes around 4000ms for me. While with mpv-player#14973 it completes in 10ms
On master, this takes around 4000ms for me. While with mpv-player#14973 it completes in 10ms
N-R-K
left a comment
There was a problem hiding this comment.
Can we isolate/reduce the ifdefs?
Also, please update the relavant part with proper attributes to silence the FP ASan warning.
76240eb to
753a71d
Compare
N-R-K
left a comment
There was a problem hiding this comment.
Using #17670 for testing, this is what I get with this PR (playback works fine, no freezing):
[command_test] done rapid subprocess dispatch in 113.893ms
And this is what I get without it (playback has freezes):
[command_test] done rapid subprocess dispatch in 1179.846ms
Looks good overall. Two small changes needed, commented below:
|
Oh, and also, please rebase on top of current master. Thanks. |
61eeae9 to
d949ff5
Compare
✔️ |
d949ff5 to
ca0c0c9
Compare
ca0c0c9 to
cb5932c
Compare
This PR introduces platform-specific implementations, namely
clonein Linux andrfork_threadin FreeBSD, to optimize subprocess creation.vforksemantics is used in these implementations: virtual memory is shared between the parent and the child, and the execution of the parent suspends until the child terminates. (However,vforkis not used because its behavior varies across platforms, and it's difficult to be used properly in C.) Besides lower overhead, this simplifies the result passing: no pipe is needed.