Dirty Hack of the Day: Python DNS Edition

In Python, you can set most request timeouts w/ socket.setdefaulttimeout(). In recent versions, urllib2 has also added a timeout field to urllib2.urlopen(). So far so good, right?

Unfortunately, while these work fine when looking up IPs or domains in /etc/hosts, this fails miserable when querying a FQDN as you’re at the mercy of socket.gethostbyname() and your DNS resolver which does not let you adjust the timeout. On my Mac this defaults to 30 seconds. It’ll ruin your day, really. (A good recent thread, old summary)

This is a somewhat common problem and you can see a lot of various workarounds (using signals didn’t work for me). The proper modern way is to probably using multiprocessing with a join(timeout) (sample) but that seemed awfully wordy, so here’s my simple one-line hack that I ended up with instead:

subprocess.check_call(['/sbin/ping','-t','1','FQDN'])

Just set 1 to the timeout you want. It’s hacky, but it works and it’s much easier and shorter – a one liner in a try block without any other libraries. Another advantage this has is that it works as it should both with DNS and mDNS (zeroconf) without any additional lookups. I’m using this for finding local machines so this is quite useful.

Some extra references:

UPDATE:

So, at the end of 2016 I encountered this problem, and decided that I could do better, especially because I wanted to do a sub-second query. I decided that of course the way to go would be to use concurrent.futures, but that was actually wrong, it turns out. When you call whether on the ThreadPoolExecutor or ProcessPoolExecutor version, it still waits for socket.gethostbyname() to finish. Here’s the simplest code that I implemented that worked:

from   multiprocessing import Process, Queue
def dns_lookup(host, q):
  try:
    socket.gethostbyname(host)
    q.put('OK')
  except:
    pass

q = Queue()
p = Process(target=dns_lookup, args=('example.com', q,))
p.start()
time.sleep(0.4)

if q.empty():
  p.terminate()
  print('dns timeout')

Using the multiprocessing library turns out to be the way to go because the terminate() function actually works like you expect it to, killing with extreme prejudice and w/o too much extra code. Hope that helps anyone dealing with the same problem.

Late Night Reading

Transcript of secret meeting between Julian Assange and Google CEO Eric Schmidt

And I wanted there to be more just acts, and fewer unjust acts. And one can sort of say, well what are your philosophical axioms for this? And I say I do not need to consider them. This is simply my temperament. And it is an axiom because it is that way. And so that avoids, then, getting into further unhelpful discussions about why you want to do something. It is enough that I do. So in considering how unjust acts are caused and what tends to promote them and what promotes just acts I saw that human beings are basically invariant. That is that their inclinations and biological temperament haven’t changed much over thousands of years and so therefore the only playing field left is: what do they have? And what do they know? And “have” is something that is fairly hard to influence, so that is what resources do they have at their disposal? And how much energy they can harness, and what are the supplies and so on. But what they know can be affected in a nonlnear way because when one person conveys information to another they can convey on to another and another and so on in a way that nonlinear and so you can affect a lot of people with a small amount of information. And therefore you can change the behaviour of many people with a small amount of information. So the question then arises as to what kinds of information will produce behaviour which is just? And disincentivise behaviour which is unjust?

Thinking about this in context of the events unfolding in Boston, and the crowdsourced attention happening among other things.

Performance Comparison of Image Libraries Revisited

A few years ago, I wrote up a brief comparison of various image libraries running a series of operations (image compositing and resizing) that we use for Lensley on an OS X + Python setup.

Just recently, I started doing work with Ruby + RMagick, however I ran into some issues doing basic operations (PNG resizing on a set of images) that was just incredibly slow.

ruby 1.9.3p385 (rvm) + RMagick 2.13.2 (ImageMagick 6.8.0-7 2013-02-19 Q16)
real	9m37.735s
user	4m11.995s
sys	3m16.644s

What’s going on here? Looking more closely, Ruby started out maxing out the CPU but this actually declined as the script ran, and memory steadily climbed, reaching 6GB by the end (which took about 30s after processing just to release). Obviously a GC issue, and sure enough, there was a thread about it. Adding a couple destroy! calls at the end seemed to fix things nicely:

real	3m49.132s
user	3m44.673s
sys	0m3.150s

Now, how did that compare with running convert via Python, I wondered?

Python 2.7.3 + envoy + convert (ImageMagick 6.8.0-7 2013-02-19 Q16)
real	4m58.882s
user	4m40.536s
sys	0m15.840s

Seems about right (one interesting thing to note is that the processing was actually shorter than Activity Monitor’s refresh so it never showed maxed CPU usage). Now how about running ImageMagick directly?

time mogrify -path test-seq3 -scale 800x450  test-in/*.png
real	3m17.050s
user	3m14.937s
sys	0m1.879s

OK, and since we’re just doing simple manipulation, lets see how it does against sips.

real	0m56.272s
user	0m51.000s
sys	0m5.150s

Well now, that’s a bit embarrassing isn’t it? Still, one thing with all of these so far was that only a single processor was being maxed out.

I decided to try multiprocessing (this was easier for me in Python) to see how fast I could really process these images. I used multiprocessing + Queue w/ 8 processes for my cores (similar to this example).

Python MP + envoy + convert (ImageMagick 6.8.0-7 2013-02-19 Q16)
real	0m51.472s
user	4m44.998s
sys	0m19.737s

Python MP + PIL 1.1.7
real	0m18.123s
user	2m5.540s
sys	0m2.721s

Python MP + Wand (ImageMagick 6.8.0-7 2013-02-19 Q16)
real	0m39.012s
user	4m39.162s
sys	0m4.145s

Python MP + pgmagick (GraphicsMagick 1.3.17 2012-10-13 Q8)
real	0m17.148s
user	1m47.560s
sys	0m1.593s

Python MP + envoy + sips
real	0m52.984s
user	0m58.504s
sys	0m13.715s

The biggest surprise was that sips had virtually no gain and no effect on the actual processing. I wonder if there’s some pipelining going on or what the loss in subprocesses was… PIL and GraphicsMagick beat the pants of ImageMagick, both being over twice as fast in processor and wall time.

I would have liked to have tried comparing to freeimage, but alas couldn’t get wrappers to work. smc.freeimage and FreeImagePy had problems talking to the dylib, and I was able to get mhotas‘ freeimage wrapper mostly working but it was giving me fits on resizing. Maybe next time.

Python and ImageMagick

UPDATE 2013-10-27: Wand continues to have frequent updates and now supports sequences, line/text drawing, reading EXIF, chops, and some effects among other things. You can keep track w/ the latest CHANGELOG. I can highly recommend it if it does what you need.

I’m a big Python fan and it’s my preferred language these days, but sometimes you just have to shake your head and give up. One area where Python falls down is in its ImageMagick bindings. You can read more about the history of some of the libs here.

Here’s my experiences on OS X (10.6, 10.8) and MacPorts that hopefully will save some people time:

  • PythonMagick (BROKEN) – the official bindings, and somewhat up-to-date (last update 2012-09-19), I could get it to compile, but it threw TypeErrors when trying to run. You can compile it like so:

    ./configure --prefix=/opt/local CPPFLAGS="-I/opt/local/include -I/opt/local/Library/Frameworks/Python.framework/Versions/2.7/include/python2.7" LDFLAGS=-L/opt/local/lib

  • pythonmagickwand (BROKEN) – this shows up in searches, but it hasn’t been updated in 5 years. It’s as you can imagine, broken.
  • python-magickwand (BROKEN) – last updated 2012-01-22, it includes a nice README (w/ the aforementioned history) and examples and I wanted it to work, alas, I couldn’t get it to.
  • Wand (WORKS!) – Wand is under active development (last commit 2013-01-31), is Pythonic, has community contributions, and works! Sounds perfect, right? Alas, it doesn’t support many features currently (layers, effects, animation etc) although it’s on the roadmap.
  • pgmagick (WORKS!) – This lib was the closest to doing what I needed. It’s very active (last commit 2013-02-10) and is much more comprehensive than Wand.. however, while supposedly working for ImageMagick, I could only get it working w/ GraphicsMagick, which in my case, was missing features that I needed. There are decent docs but very little real code out there. Here btw, is how I got it running (it has some boost issues; also, pip doesn’t work):

    sudo port install boost
    cd /opt/local/lib
    sudo ln -s libboost_python-mt.a libboost_python.a
    sudo ln -s libboost_python-mt.dylib libboost_python.dylib
    sudo easy_install pgmagick

    After wrestling for quite a while, I threw in the towel and rewrote my code in Ruby w/ RMagick, which is well maintained and up-to-date, has comprehensive documentation, and lots of example code floating around the web.

    If you’re tied to Python, using PIL or subprocess/envoy to call convert/mogrify directly is probably your best bet, but if you are doing anything substantially complex, calling out to an RMagick script will probably save yourself a lot of pain.

MacPorts without XCode

Post-XCode 4.3 (when XCode was moved to the Mac App Store), the Command Line Tools are now a separate download (either from within XCode or from ADC). This also means that you can install the Command Line Tools without needing all 4.4GB of XCode thanks largely to Kenneth Reitz’s work on OSX-GCC-Installer. Pretty sweet, and designed to work with Homebrew. The easiest way to install the command line tools is of course, via the terminal:

xcode-select --install

MacPorts has served me well over the past few years without much fuss, but it’s apparently not done well for people upgrading XCode (see the Problem Hotlist and sample Stack Overflow answer if you have that problem). Now this is all fine and good with XCode, but what if you want to just use the Command Line Tools and skip XCode entirely?

Well, I’m glad you asked. Mostly it involves running the following:

xcode-select --switch /usr/bin

This makes xcrun point to the correct location when running binaries, however, if MacPorts is giving you guff about not having XCode installed this is what I did (as root):

cd /usr/bin
mv xcodebuild xcodebuild.orig
touch xcodebuild
chmod a+x xcodebuild

And for xcodebuild:

#!/bin/bash
if [[ $1 == '-version' ]]; then
  echo "Xcode 4.4"
  echo "Build version 4F250"
else
  # Pass Through
  /usr/bin/xcodebuild.orig $@
fi

MacPorts seems to use xcrun xcodebuild -version to check the XCode version, so I just get it to lie when it asks.

Now, this is quite ugly, and the proper way to do things would probably be to either actually install XCode or perhaps, finally make the switch to Homebrew, but I thought I’d post this in case it comes in handy for people…

New Windows Netbook: User Experience Report

TL;DR/SPOILER: Pretty Pathetic

Yesterday, I ended up helping a friend pick up a new PC at Fry’s. Not super high on my list of things to be doing on a Sunday, but I’m rolling with it. All we needed was a minimal computer to run a browser, so after looking at the laptop and nettop selection, we decide to go for a 10″ EeePC. There was a 12″, but we were told that it was out of stock, and after we decided on the 10″, we were told that was out of stock (and discontinued) as well. These netbooks were running Windows 7 Starter and I asked what the difference was (vs Home, Professional, or whatever), but the sales associate didn’t know. In the end, he brought out an also-discontinued but similar (single-core N455, not dual-core D525 Atom) netbook. At this point, I’m jonesing to get the hell out of dodge, and after another 20 minutes of dicking around, it’s sent to the front desk for checkout/pickup. Overall shopping experience grade: pathetic.

Anyway, I don’t want that to overshadow what’s coming next, so lets just move on (had I known I would have just told my friend to order online via Amazon or something else civilized). Now for the setup… It’s been close to a decade since I’ve unboxed and booted a retail Windows PC, so I was sort of looking forward to see how the experience has improved.

It doesn’t start off too bad. A nice bootup logo, some simple form fields to fill out, and then a Samsung installer that automatically runs to install some system software. We leave for lunch, and when we return, it’s… still… running. All told, it takes just under an hour before I reach the Desktop, after which the laptop (with 1GB of RAM) is almost unusably slow. Sure enough, looking at the Task Manager shows that it has 0 memory free. Interestingly, the Bing Bar is the app using the second most memory. After another hour+ of uninstalling the apps that presumably were just installed in the previous hour (Norton first, and then the Bing Bar, and the Samsung System Tools being some of the worst offenders), I downloaded Google Chrome, and ran the “boot performance” tool (another half-hour), and ended up with a usable laptop with a passable web browsing experience. Overall initial boot/setup experience grade: super pathetic.

Now granted, this is a <$300 device, but I'm honestly surprised at how horrible the first boot experience was. Much worse than I remembered, much less what I was expecting in 2011. How can a manufacturer get away delivering this sort of experience and still be in the business of selling computers? After a decade of using Macs (and occasionally imaging Linux systems on similar class hardware), my mind is just boggled. I wonder if people buying these things don't know any better, or if they fully understand the horror, but simply must endure it (like me in this case, I suppose). It certainly occurred to me more than once during this ordeal that if I had brought my USB stick, it would have been much faster to have wiped the netbook with an Ubuntu installation and be done with it.

HP Touchpad + webOS

So yeah, I went and ordered a TouchPad (a few actually, as they look like they’ll be useful as web/input devices). If you’re interested in picking one up for cheap, the epic SlickDeals thread (11K+ posts) has the latest stock info. (for general info, there’s another thread w/ some useful links, and the PreCentral TouchPad forums). It’s not for everyone, but $100 for a tablet w/ a 9.7″ XGA IPS screen, dual-core 1.2GHz Scorpion SoC (APQ8060 + Adreno 220), and 6300mAh battery that has a clean embedded Linux (and can easily chroot Ubuntu) is a steal.

Of course, if you’re not gonna be hacking on one, it’ll be a decent web browser or photoframe, and I have no doubt that the homebrew guys will keep plugging away for a while, but I’d treat it more as a disposable $100 purchase. (My thinking is the upcoming Amazon tablets will split the difference in pricing, but ultimately have much better longevity).

Now, back to the hardware for a bit. While there have been a rash of articles blaming the TouchPad’s performance on the hardware, I think that’s baloney. For those that aren’t regularly comparing ARM specs, all you need to know is that in terms of raw power, the Scorpion should hold it’s own – equivalent to current-gen Cortex-A9/GPU combo like Apple’s A5/SGX54x or Nvidia’s Tegra2 (maybe a little less memory bandwidth/IPC, but it has a faster clock). There’s an Anandtech article that does a good job summarizing.

The Anandtech article has a SunSpider comparison, which mirrors the launch benchmarks. The TouchPad is slow because the web layer is slow. Luna, webOS’s GUI, runs entirely on web layer. QED. This mirrors my cursory prelaunch SDK testing (NDA lifted 6/30).

I mostly gave up on webOS back in the summer of 2010, pre-HP acquisition, and although I retain a fondness for the idea of webOS, the execution has always caused ambivalence for me, primarily because of performance. I think Dion makes a bit of an understatement, when saying they should have spent more time profiling. More than any other feature or app (well, Maps), lag, OOM erros, and unresponsiveness was the primary issue that drove me away.

Although a lot of it comes down to doing (hard) low-level optimization work (or dumb easy stuff like turning off logging), I think at least some chunk is just due to running on old software. Last year at the Palm Developer Day, the excuse given about why webOS software was so out of date was due to recertification issues, but w/ webOS 3.x being a tablet-only fork, this obviously didn’t prove to be the ultimate reason.

Based on the 3.0.2 SDK Emulator, here’s a rundown of some of the stack:

Linux Kernel 2.6.26 was originally released Jul 13, 2008. In comparison, Android Honeycomb runs 2.6.36 (Oct 10, 2010). There is in fact an active project that’s done great work patching the kernel (better schedulers, governors, compcache), although I’m not sure if all the modules required to upgrade vs backport are available.

webOS reports using AppleWebKit/534.6. WebKit was tagged Safari-534.6 on Aug 27, 2010. This might not seem too bad when comparing w/ kernels, but to give some perspective, Chrome 7.0.517 was released with AppleWebKit/534.7 in Oct 21, 2010. I’m currently running Chrome 13.0.782.112, which uses AppleWebKit/535.1 (tagged on Aug 11, 2011). Safari 5.1 is using AppleWebKit/534.48.3 (tagged Jun 24, 2011). webOS has ACID compliance and other standards issues, and is lacking in many useful HTML5 features, which is somewhat ironic considering.

Probably more relevant to performance, however, is the V8 version. webOS’s node.js is compiled against V8 2.5.9.22-2 (released Nov 11, 2010). The current latest version, released last week, is 3.5.6. Especially for JS runtimes, improvements have been coming at a blistering pace. Running V8 Benchmark v6 on Chrome 13/Canary 15 (V8 3.3.10.25 and V8 3.5.6) on my desktop gave results in the 9400/9500 range. An old version of Chrome 7 (V8 2.3.11.22) scored… 5400 on the same test. (There BTW is your 2X performance.)

webOS 2.x+’s services are based on a node.js layer. That’s great. The version of node.js they are using is 0.2.3, which was released on Oct 02, 2010. The current version is 0.4.11 (stable) and 0.5.4 (unstable). node appears to run standalone, so that can probably be upgraded (and the JS tested) without too much trouble.

The much bigger challenge for people sticking with webOS is how to deal with all the custom-compiled/embedded bits. The biggest pieces (at least memory-wise) are the WebAppMgr, LunaSysMgr, and BrowserServer, but updating any the luna bits are completely dependent on the whim of HP.

If they don’t open source webOS, hopefully whoever’s left can push out as many of the low-level performance optimizations and maintain some sort of robust build/update system.

Sadly, the most likely scenario is that in a couple months we’ll just all be flashing an Android port.

Changing Volume in OS X in the Command Line

One of the things that seems to have disappeared recently (certainly doesn’t work in Lion) is half-increment volume changing. This is quite inconvenient when I’m using some more sensitive headphones.

That was the impetus for the latest addition to my bashrc, a helper function that lets you set volume in the command line (scale is 0-100):

vol () { osascript -e "set volume output volume $*"; }

How to Install Pida on OS X

For some reason, I got it into my head that I wanted to try out Pida (a Python IDE that embeds Vim or your editor of choice) on my Mac. Well, actually from the description, it sounds pretty cool, right? The screenshots are pretty neat too. Unfortunately, the end result on OS X is somewhat less than compelling.

However, it was a huge fight getting it setup, so I figured I’d write this down for posterity.

There is a PIDA MacPort, however there is no maintainer, it’s for Python 2.6 only, and it didn’t work out of the box for me. You’ll need to fight it enough that you might as well go whole hog. Here’s how I got Pida running w/ MacPorts python27.

First the ports:

sudo port install librsvg py27-gtk py27-gnome dbus-python27 py27-notify-python
sudo port install vte +python27
sudo port install vim +python27 +x11 +gtk2

Then the Python libraries:

sudo easy_install py
sudo easy_install pygtkhelpers
sudo easy_install Logbook
sudo easy_install bpython

Next, after grabbing the source, your build environment:

PKG_CONFIG_PATH="/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/pkgconfig" PATH="/opt/local/Library/Frameworks/Python.framework/Versions/2.7/bin:$PATH" python setup.py build_ext --inplace
running build_ext

Now, you’ll be able to run, but you may get a dbus error (which won’t let you select your editor among other things). Here’s how I made sure that dbus was running:

launchctl list | grep dbus
sudo launchctl load -w /Library/LaunchAgents/org.freedesktop.dbus-system.plist
launchctl load -w /Library/LaunchAgents/org.freedesktop.dbus-session.plist
launchctl list | grep dbus

Note above that dbus-system should be as root, and dbus-session should be loaded as the user.

Once I did this I was able to get up and running, however the Python shell subprocess throws an exception for me, and the font rendering and overall look, and of course all the non-vim keyboard shortcuts are painfully alien. Sadly, if you’re looking for a vim-like IDE-ish solution on the Mac, I think Vico, while quite new and still incomplete, is probably a better bet. If you’re looking for better Python introspection/debugging with a not-totally-awkward keyboard shortcuts (and incidentally, dead easy OS X installs), Reinteract and iep look to be the best choices I’ve found. (There’s also Spyder, which has a python26 Macport, but it depends on qt4-mac which may cause your MacPorts to build the world.)

Downtime, Ubuntu Sysadmin Notes

After 511 days of uptime, I decided it was time to bite the bullet and do a version upgrade. The `do-release-upgrade` command did what it said on the tin, and the upgrade from 9.10 to 10.04LTS was pretty straightforward (some downtime waiting for the disk to fsck, and requiring ops to manually reset). Unfortunately, the upgrade made WordPress pretty unhappy. Some combination of WP, APC, and potentially WP Super Cache? Instead of using Ubuntu’s APC (3.1.3p1-2) I switched to a pecl install (3.1.9). This didn’t solve things, so I bumped up the apc.shm_size to 128M…

I’ve been lackadaisical lately w/ my sysadmining, but with the unfriendly waters, I took some time to tighten the ship up a bit. I probably be publishing a little “hardening Ubuntu for really lazy/busy devs” guide soon.