[IPython-dev] GUI support added.

Fernando Perez Fernando.Perez at berkeley.edu
Thu Aug 26 02:01:35 EDT 2010

[ Cc-ing the dev list so the power figures below get recorded where
Google will find them ]

On Wed, Aug 25, 2010 at 22:08, Brian Granger <ellisonbg at gmail.com> wrote:
> I just pushed GUI support for Qt, Tk and Wx into ipython/newkernel.  I
> think we are doing pretty good overall with the GUI support for now.
> We just need lots of testing.  I have tried many of the matplotlib
> examples and most of them work fine.  Evan, if you can try some big
> trait apps, that would be great.  We should also try some Mayavi
> examples as well.  Right now I have tuned the polling time on the GUI
> timers so that the CPU usage is below 1% for the kernel.  This is
> about what the frontend itself is as well.

This is fantastic, great job!

As I mentioned before, CPU load isn't the only metric we need to look
at, the key one is the number of CPU wakeups-from-idle per second
induced by an app, that's what kills battery life.  A linux laptop
running on battery (you don't get this info on AC power) has the
'powertop' utility written by Intel to show who's keeping the CPU
awake.  Some numbers I've seen from quick testing on my new laptop
(core i5 ultra low voltage, running in 'powersave' mode):

- plain python shell: doesn't even register in powertop.
- IPython 0.10.1, no pylab/thread support: same
- IPython 0.10.1, with pylab using qt4 backend: same
- IPython 0.10.1, with pylab using Wx backend: 10 wakeups per second.
- IPython newkernel at the terminal (no zmq), no pylab: doesn't register
- IPython newkernel at the terminal (no zmq), with pylab/qt4: same

This is *fantastic* news.  I'm not sure what changes are in the code
that may explain this, but it seems that the one-process one (with
pyosinputhook and qt4) is behaving better than I remember it from a
while ago.  Maybe it's just my memory, but I seem to recall it showed
up more in powertop.  Or maybe not, Qt has been OK all along and it's
Wx that's the bad guy:

- IPython newkernel at the terminal (no zmq), with pylab/wx: bad news:
~50 wakeups per second, the worst offender program in the whole
computer, only second to the (linux) kernel itself.

Indeed, Wx is bad: with -wthread it already gave ~10 wakeups per
second, and with PyOSInputHook it's ~50.  Nasty...  Basically, Wx is a
wakeup hog that will kill any battery.

The good news is that in one process, even Qt is very well behaved and
gives no detectable power signature.

Now, when we run ipythonqt, which brings out two processes, messages
flying around and a full qt app, we do eat more power. Here are the
numbers (in all cases we have the Qt app for the frontend, zmq, and
possibly some gui toolkit active in the kernel):

- no pylab: ~37
- pylab tk: same
- pylab qt: same
- pylab wx: same

The good news from this: enabling gui support in the new system has no
net power cost. The bad news: even with no gui support, the power
signature of the combined qt frontend/zmq communications/2 processes
is pretty noticeable.

One more reason to keep around the lightweight one-process guy: if
you're on a plane trying to get every last ounce of battery out, it's
a good option.  Similar to how I switch window managers from Gnome to
Awesome when I need to maximize battery life, this simply means that
we'll have a range of interface options.  The fancier ones have a
power cost, and the more spartan ones will be very efficient.

> Some notes:
> * Wx and Tk work out of the box with the matplotlib in EPD.


> * For Qt, we are going to have to patch matplotlib.  I am attaching my
> patched qt backend.  This is just a draft of the patch and we may have
> to add additional logic.

OK, let's work on this one a bit, and when ready we'll get in touch with MPL.

> * During the process of merging with newkernel I found some things:
>  - The default color scheme for the crash handler was set to Linux.
> I have changed this to LightBR on the Mac so the crash tracebacks are
> not invisible.

Yes, good call.  Sorry I forgot to do that yesterday, I enabled it and
never went back to clean it up.

>  - I ran PyFlakes on some files and found some bugs (ultratb,
> entry_point, etc.).  These bugs were not discovered because they were
> in parts of the code
>    that are not run usually.  Let's make it a habit of running
> PyFlakes before any merge.  It is amazing the things that it will
> catch!

Yup, good point! I keep it on my Emacs setup all the time, I just
forgot to run it (it's just a keystroke, I don't know why I got out of
the habit).  Pyflakes is definitely something to run regularly.

>  - The names rprint/rprinte are great for quick debugging shortcuts.
> But these are now showing up in production code.  Could we alias them
> to raw_print_out and
>    raw_print_err and use the longer names in production code so 6
> months from now we don't have to go looking up what these functions
> do?   I am fine keeping the
>    short names around for quick debugging though.

Yup.   In fact, I'll rename them just raw_print and raw_print_err, the
normal one doesn't really need a separate name.

> # Patch to backend_qt4.py
> # I have changed the _create_aApp function to the following:

def _create_qApp():
   Only one qApp can exist at a time, so check before creating one.
   if QtGui.QApplication.startingUp():
       if DEBUG: print "Starting up QApplication"
       global qApp
       app = QtGui.QApplication.instance()
       if app is None:
           qApp = QtGui.QApplication( [" "] )
           QtCore.QObject.connect( qApp, QtCore.SIGNAL( "lastWindowClosed()" ),
                               qApp, QtCore.SLOT( "quit()" ) )
           #remember that matplotlib created the qApp - will be used by show()
           _create_qApp.qAppCreatedHere = True
           qApp = app
           _create_qApp.qAppCreatedHere = False

OK, we'll pound on the Qt code a little more until it feels robust.

Cheers, and thanks again for the great job!


More information about the IPython-dev mailing list