partiallydisassembled.net

Apple C header licenses

2008-10-08 23:19:24

Seen in the prelude of the Kernel.framework/Versions/A/Headers/IOKit/hid/*.h files... "[...] APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. [...]" Not fit for quiet enjoyment? Oh, my.

What slows down development...

2008-08-16 17:00:22

... Vista bluescreening every time I terminate a hung Python process that has a lock ("Process has locked pages"). Yep, I can trigger it consistently and reliably. Makes.. me.. angry!

Multithreaded goodness for pyglet

2008-08-12 00:01:13

I've finally gotten some good results after spending the last few months (on and off) refactoring the pyglet.media module in pyglet to use multiple threads. There were two main reasons for attempting this: to make better use of multi-core machines (pyglet is currently single threaded), and to avoid having to schedule audio pump in the main event loop (in pyglet 1.0 this was explicit, in 1.1 it's done on the clock). The problem with having the audio pump in the main loop is that it requires application developers to manually tune their programs to keep the audio buffer full -- and this is obviously very dependent on the hardware and drivers available. One motivating example was my last PyWeek entry, which had background music that stalled during long loading times (I managed to get this down to just the initial loading time, and smooth for the rest of the game, but this was a lot of effort, and removing the initial pause proved too difficult). The redesigned media module is still residing in the experimental/mt_media directory of SVN trunk. Only the OpenAL driver is anywhere near complete. The DirectSound driver has yet to be ported to the multithreaded API, and the ALSA driver has been deprecated in favour of a new PulseAudio driver. PulseAudio is proving far more reliable and capable than the ALSA user-space daemon, and has been the default audio server in both Ubuntu and Fedora Core for some time. The PulseAudio driver is mostly complete, but has no 3D capability (Linux users can still choose to use OpenAL as an alternative). The audio driver modules are required to pump themselves now. The PulseAudio driver does this using the built-in PA thread runloop, whereas the OpenAL driver creates a Python thread that periodically wakes. Much of the shared code between drivers regarding video frame synchronisation has been moved into the base classes. This should greatly reduce the amount of effort required to develop a new audio driver. Audio drivers dispatch events to the Player object when a new video frame should be displayed. New methods on pyglet.app make it easy to post events from one thread into the main event loop safely (these also automatically wake up the main event loop if it's sleeping, allowing more opportunities for people to integrate multithreaded code into their pyglet applications). The AVbin source driver also now spawns a worker thread for decoding video frames. Since most of the work in decoding the frame is done outside of Python (in FFmpeg), this is a great chance for pyglet to do some real multiprocessing. Quite a lot of work went into ensuring the queue of video frames to be decoded is kept up-to-date with what's needed on-screen; without an excessive preroll period or memory usage. I've done most development on my 900MHz iBook, which is incapable enough that it can't even play YouTube videos in real time (though pyglet can play them just fine once downloaded, thanks to FFmpeg). This has forced me to make the implementation efficient enough to work on old computers; the overhead of the extra thread processing is significant and required several manual context switches to get everything playing (almost) as well as the old, single-threaded code. On newer computers the performance is fantastic. I did a quick benchmark test on my 1.8GHz Core 2 Duo Mac Mini. It happily plays 7 SD videos simultaneously (DivX or Xvid encoding) without sweating, whereas the old code could only play 3 videos. Watching the activity monitor shows that both cores are now being utilised fully when needed (and run each at around 5% when playing a single video). Expect to see this new code in pyglet 1.2. I'll introduce some more of the new features over the next few weeks. I'll also be talking about pyglet 1.2 at OSDC 2008 in Sydney in December.

Good looking tick mark distribution

2008-08-11 18:40:25

Given a min/max range of any magnitude, how do you generate a "nice looking" distribution of values to cover the range? My need for this was to generate tick marks on a graph. The function I came up with works quite nicely, I think: import math def distribute_nicely(min_val, max_val, min_ticks=3, max_ticks=8): if max_val - min_val == 0: return [min_val] mag = 10 ** int(math.log10(max_val - min_val) - .5) if mag == 0: mag = 0.1 for multiplier in (10, 5, 2, 1, .5, .2, .1): interval = multiplier * mag if min_ticks <= (max_val - min_val) / interval <= max_ticks: min_val = (min_val // interval) * interval break else: interval = (max_val - min_val) / max_ticks or max_val - min_val if interval > 1: return range(min_val, max_val + interval, interval) else: return [i * interval \ for i in range(int(min_val / interval), int(max_val / interval) + 1)] Sample results: >>> distribute_nicely(0, 10) [0, 2, 4, 6, 8, 10] >>> distribute_nicely(0, 100) [0, 20, 40, 60, 80, 100] >>> distribute_nicely(0, 5) [0, 1, 2, 3, 4, 5] >>> distribute_nicely(3, 8) [3, 4, 5, 6, 7, 8] >>> distribute_nicely(24, 786) [0, 200, 400, 600, 800] >>> distribute_nicely(0.21, 0.86) [0.2, 0.4, 0.6, 0.8] >>> distribute_nicely(-8, 8) [-10, -5, 0, 5, 10] >>> distribute_nicely(-105, 105) [-150, -100, -50, 0, 50, 100, 150] I'd be interested to hear if anyone has an alternative function or improvements to this one. Or if there's one in the standard library -- I always tend to miss those :-)

Richard Jones writes:

PILGraph, from way, way, way back (http://redback.spyda.net/~richard/) had something similar. Man, I barely even remembered that I had written it.

Alex writes:

Cool Richard (thanks also for the list of video cards supported by Linux ;-). Your function looks more or less identical to mine, in a nice example of convergent evolution (or something).

anthony baxter writes:

The fun case to deal with is when the axis represents time. Both Richard and I have spent a bunch of time producing algorithms that do the right thing here - it's pretty ugly.

Clean termination of daemon Python threads

2008-08-09 11:23:03

Daemonic threads in Python are threads that will not prevent the interpreter from exiting (put another way, the interpreter shuts down when all non-daemon threads exit). When the interpreter shuts down, all variables are set to None, then each daemon thread is woken up to crash (unexpectedly finding all its variables, globals and builtins missing). Here's a nifty pattern that suppresses the ugly exception trace resulting from these crashes being printed to the terminal: def worker_thread(): try: .... do work ... except: if True: raise This ensures ordinary exceptions are re-raised, but interpreter shutdown related exceptions are suppressed, as True is evaluated as None. In the off-chance that some future or alternative Python interpreter doesn't have the same strange daemon thread shutdown behaviour, the thread will still behave correctly.

Alex writes:

Well, this was still causing unnamed exceptions to get dumped to stderr occasionally. (Unnamed presumably because the traceback and exception machinery had been collected by the time it got handled). I've replaced the above with an atexit handler that notifies and joins all daemon threads.
login