I’ve made a ton of progress on moving my python interpreter to a daemon process to get around the GIL. I tied up the synchronous RPC mechanism using OSC over pipes, and ran some profiling to see how it was working. Generally speaking, the new IPC stack added 0.3% overhead to the audio thread in ::read() and ::write(), running in the same process.
I’m hoping that attaching those pipes to stdin/stdout of the daemon process will not add any more overhead. It shouldn’t because they are all OS-level pipes, right?
So the workflow for refactoring a C++ project that makes CPython calls directly to only making those calls in a daemon process looked like this:
– Port all code to use an abstract interface for the scripting engine. Take two years to mix this work in with normal tasks.
– Write an RPC protocol. I marshaled our UVal class over OSC, but anything will work as long as it’s light weight.
– Insert the IPC code behind the abstract interface to debug and profile the communication between app and engine within a single process. Work out call stacks (to allow for downstream calls to make upstream calls before returning) and other gritty details.
– Implement cross-platform (Windows and Mac) Process and Pipe classes and plug stdin/stdout into the pipes described above. Pray.
Praying seems to have worked. After a quite a bit of toil working with pipe, dup2, fork, and execve in XCode and a couple of simple test cases to test the process management, I got the daemon working. And it works WELL.
Then I really started praying as I moved to finish the same code on windows. Once the code compiled, it worked the first time. Unbelievable!
On that note, I have to hand it to the Windows guys, the fact that I had to sit down and crunch on the posix calls for an entire day, while simply reading an official windows tutorial (http://msdn.microsoft.com/en-us/library/ms682499(VS.85).aspx) got me up and running on windows really speaks well of the cleanliness of the API. Sure, I hate that they re-created all the standard types (BOOL? Seriously?! WTFF?!?!) and have a crazy proprietary API and pass-by-reference call style for everything, but I never had to debug my code. Plus the Visual Studio debugger is FAST and very RELIABLE.
Tell me though, if they can figure that crap out then why do I have to wait 2 minutes to move a folder from Downloads to Desktop?
Anyway, the GIL continues to go west. My solution could have been cleaner, but at least now I have python running in another process, which should kill the toughest bug I’ve been assigned to on this project…and it only took two years to fix.
NDA-safe implementation details to follow.
Creating a Child Process with Redirected Input and Output: http://msdn.microsoft.com/en-us/library/ms682499(VS.85).aspx
Pipe, Fork, Exec and Related Topics: http://www.cs.uleth.ca/~holzmann/C/system/pipeforkexec.html
Curious: my experience with pipes was exactly the opposite. A simple pipe() + fork() versus the CreatePipe/CreateProcess monstrosity taking 16 positional arguments (some of which are mysterious structs) each.
It was a long time ago, so maybe I was missing something.
yeah, there are more arguments, but they are easier to instantiate and I could copy it right from the example and have it compile and work perfectly.
I am happy because windows improves its application every single time, I would like to have to chance of read more about it