Wednesday, July 23, 2008

C++ and Python project config

Before I started writing commercial C++ code a couple of years ago, I had just begun to reach a wonderful state of Zen with python. I had developed good personal balance of prototyping, code organization, and debugging techniques that I still haven't seen the likes of with my C++ project. If anything, the biggest advantage that my python projects had over my C++ projects is impeccable project config. With no compilation and the guarantee that the code would run the same accross platforms, the fight was over before I even started coding.

These days I spend 50% of my time either writing code or managing a Visual Studio or XCode build system to fit the needs of the compiled language's environment. Third party vendors don't accurately support audio plugin standards, their objects are compiled with a different runtime than ours, and their headers conflict with ours and cause others to bail completely (windows.h, anybody?). Strong typing causes twice the code bloat and twice the up-front design effort that the interpreted language took. The code is unreadable; the macros clutter up the logic, the indentation is all over the place, and there's just plain too much of it. Worst of all, our repository is totally fragile, which seriously stresses out my boss.

When you code in C you get speed and easy debugging, which is important for projects like ours, which consists of a separated gui and dsp engine that is instantiated as an audio plugin with popular music sequencing hosts like Ableton Live, Pro Tools, Logic, and more. These days we are still writing for scalability and performance, so the engine has to be written in C. We debug our gui code and step into the engine on a regular basis, so writing the gui code (> 50%) in python and trying to debug the engine would be very difficult.

Theoretically the gui code would have been so easy to write in python that we wouldn't have needed to debug it, and could have just debugged the engine using C++ breakpoints in XCode and Visual Studio as we do now, but I wouldn't know without trying it. One thing is for sure, coding with a clear conscience would have required a solid set of tests to work out all the bugs we've run into using Qt as a graphical toolkit from within a native application. With the tremendous overhead of writing unit tests for this stuff, we would never have met our initial project deadline, and I would never have had the opportunity to look back and grumble about our choice of language.

Maybe it's possible to get around these problems with better plugin standards? Or maybe having a really really good python-based plugin dev platform to work with would help.

Anyway, back to the topic. I originally wanted to write about the stylistic differences that separate python and C/C++ projects. Here's what I've found:

Python induces highly modularized code that is still readable, while in C it's much easier to read code that is written in larger blocks. Remember that big, long function that you wrote in your first college class?

When I code in C++ I end up spending most of the time coming up with solutions that work for the syntax of the language, as opposed to using that time and energy to focus on the functionality of that code. I eventually stopped using a debugger with python because I was able to produce pieces of code that worked well from the start, or could be quickly fixed using print statements and some sort of unit test using an "if __name__ == '__main__':" block. With C++ I ended up writing verbose code that is easily debuggable, for example always using temporary values of built-in types to expose the state of the stack.

The biggest difference, though, is that I got very comfortable with being a style nazi when reading and writing python code. The difference is that it just doesn't matter what the code looks like in C++ as long as it runs. We have three primary developers in our project that all use whitespace differently, name our variables and methods with different conventions, and it's pointless and also unnecessary to try to change them. You just jump into the C code and fix the problem, leave the crazy indentation from your tabified copy and paste, then just compile it and make it work, and work fast.

I do miss the unified indentation, simple syntax, and no crashes, compiler flags, or linkage problems have cost us a lot of man hours, not to mention stress for my project manager. Most of all, I miss just sitting down and solving problems 100% of the time.

Wednesday, July 16, 2008

Multiple RT threads and the GIL


The Problem

Same old topic, new person. The GIL sucks. It makes programming easy, but it makes true parallel processing impossible. Audio sequencing plugin hosts use a different thread for each track, allowing their DSP to scale with the number of available processors. While python has performed beautifully for doing control-rate midi processing in our commercial plugin (http://www.soundsonline.com/) running in RT threads, the presence of the GIL causes brief CPU spikes when one or more threads take to much time to run their scripts. The lack of performance in a single thread is not a problem since the audio event will safely occur later, it's the fact that that thread slags all the other threads that are running perfectly fine that sucks.

Python has otherwise proven to be a fantastic platform for our scripting engine, and it would even more fantasticer if the GIL didn't get in the way. It would be a shame for such a great scripting engine to be blocked by such a small hurdle (although still a major design decision). A per-interpreter lock would solve the problem for us since each track is always independent from another and so never share objects.

One solution is to try and patch the python source to actually be able to use completely separate interpreters. This means that all objects would live on one interpreter, and their accompanying functions would need to modified to take an interpreter as an argument. Loading extension modules would have to be disabled since they generally use static data. As of right now I don't know how hard this would be but if anything I'd get a good code read out of it. 

Another idea I was playing with was to somehow find a way to use the fact that dlls use their own address spaces to maintain separate images of the python lib and therefore separate GILs. If there was a way to copy a dll and store separate instances of it, this would be possible. I wouldn't mind the extra footprint on the heap if I could get rid of those CPU spikes.

The correctly pythonic answer to this problem is to use process migration. This would imply creating a daemon process for every instance of our engine. I don't know if this is a very nice thing to do to a plugin host, but it would fix the problem if we could get around all the shared memory and IPC overhead. But ummm, I think I'll read the python code for now.

The Future

At Present, making python available to the audio world is what interests me most. It would be great if we could use the language for control-rate audio scripting, graphical interfaces, etc. The biggest problem I've had with the current implementation is when using it with plugin instances, and I can see problems popping up whenever complex intra-process use is involved.

That's two major python no-no's: single-process scalability, and use in high-priority threads. I have the belief, though, that while processors have already become fast enough to get over the old "python is bad for real time use" performance myth, and we are going to see more cores, which makes true mutli-threading a very very good thing to have.

forste melding

Hello! I'm back after over a year. After becoming more involved in my C++ work for EastWest, I didn't have the time to focus on my python code. Now after implementing a python-based scripting engine for Play, I've slowly regained a grip on my personal artistic interests and have startup up my blog again.

I don't anticipate getting the traffic on this blog that I used to when I was more active in the python/pyqt/supercollider world, but it would be really nice to have a spot to ramble about music and code. I sure hope they have a good code highlighter...yay internet! I manually imported all of my old pyblosxom entries with the correct dates as well. Happy following.