PyMT/Movid @THSP

THSP is a Festival in Toulouse, with lot of events and hackers, from the 28 to the 30 May.

Saturday, i’ll do a talk/introduction about PyMT and Movid. Jimi is doing a workshop during the whole event, to build another Wall, and some other Multitouch Table. It will be a nice playground for both software! Thanks to Marc Bruyere and Jimi Hertz for giving me the possibility to talk here 🙂

Read more about the event with the THSP Program May 2010.

Multitouch Linux Support for PyMT

Since the last week, i’ve done some jobs about supporting nativly multitouch screens in PyMT. Linux was missing in the native support, next to Windows and MacOSX, already available.

2 supports have been realized : HID Input Support, and MPX/XI2 Support.

1. Kernel Part

HID Input is the Input part of Linux Kernel. Since 2.6.34, lot of multitouch screens got their drivers integrated in the source code. Most of the drivers have been done by the Stephane Chatty from the ENAC Laboratory, inside the ShareIT project.

HID Input is reading the Event generated by the kernel, using /dev/input/eventX.

The Event are documented in the input.h. New event type have been added for Multitouch support: all the ABS_MT_. As today, we support :

  • ABS_MT_POSITION_X : X position
  • ABS_MT_POSITION_Y: Y position
  • ABS_MT_PRESSURE : pressure
  • ABS_MT_TOUCH_MAJOR : width of the object
  • ABS_MT_TOUCH_MINOR : height of the object

Other event are ignored, but would be interested to add the support, like ABS_MT_ORIENTATION. But right now, no device support them.

This work is available on the latest version of PyMT. Check our PyMT github repository. If you want to known how to use it, you can read the mail sent to the pymt-dev mailing list.

The result of my work : PyMT + HIDInput support on Linux

2. Xorg

Since Xorg 7.5, MPX is available. MPX is the support of Multi Pointer inside X. Benjamin (from the Enac too), have provided a modified evdev module for Xorg, to read Multitouch Event from kernel, and pass them to Xorg.
This work require a running daemon, actually called multitouchd (on the same page as evdev). The daemon detect all the devices with Multitouch support, and create by default 5 fake mouse device, attached to the main multitouch device. With this way, each touch control one fake mouse device.

Unfortunaly, this is not stable, and with a stantum screen, once i get more that 4 or 5 touch, Xorg crash.

Anyway, i’ve start the support in the PyMT branch input-xi2. This rely on python-xlib, but this library required some change to make our work run.
Since it’s really more complicated than HID Input, i’ll not explain all the work right now. Maybe in another blog post.

3. So, which screen i could buy to play with ?

That’s pretty simple. ENAC (again) maintain a full list of multitouch screen working on linux, and the status of the support in linux kernel.
For my part, i’m playing with an Acer T230H. A little bit bugged, and support only 2 points. But enough to play and debug with right now.

That’s all for the moment, enjoy !

Python: is X is better than Y ? Round 3, pure python VS cython

Round 3: pure python drawing VS cython

Benchmark code :

s = time.time()
for x in xrange(10000):
   drawRectangle(0, 0, 50, 50)
print 'result=', time.time() - s

Let’s take the Python version of simplified drawRectangle():

def drawRectangle(x, y, w, h):
   glVertex2f(x, y)
   glVertex2f(x + w, y)
   glVertex2f(x + w, y + h)
   glVertex2f(x, y + h)

I got the result on poor graphics card: average ~1.1268s

Let’s rewrite in Cython:

cdef extern from "GL/gl.h":
   ctypedef float         GLfloat
   ctypedef unsigned int  GLenum
   int GL_QUADS
   cdef void glBegin(GLenum mode)
   cdef void glEnd()
   cdef void glVertex2f(GLfloat x, GLfloat y)
def drawRectangle(float x, float y, float w, float h):
   glVertex2f(x, y)
   glVertex2f(x + w, y)
   glVertex2f(x + w, y + h)
   glVertex2f(x, y + h)

And the result : average ~0.0325s

PyMT Impact: rewriting graphx package 🙂

On a NVIDIA 9800 GT: with 1000000 (instead of 10000):

  • Python: 16.1
  • Python -O: 17.2
  • Python -OO: 16.9
  • Cython: 0.29

Very weird about -O / -OO…

Python: is X is better than Y ? Round 2, remove exception VS test in + remove

Round 2: catching remove exception VS test in + remove

Benchmark code :

from time import time

# exceptions vs list in
def bench_in_remove(count):
    for x in xrange(count):
        q = []
        for z in xrange(1000):
        for z in xrange(0, 500):
            if z in q:
def bench_exception(count):
    for x in xrange(count):
        q = []
        for z in xrange(1000):
        for z in xrange(0, 500):
            except ValueError:

def bench_remove(count):
    for x in xrange(count):
        q = []
        for z in xrange(1000):
        for z in xrange(0, 500):

def run(f, c=10000):
    t = time()
    print '%-15s time=%.8f count=%d' % (f.func_name, time() - t, c)


And the result :

bench_remove    time=4.20256305 count=10000
bench_in_remove time=4.49746203 count=10000
bench_exception time=4.33078504 count=10000

We can see a little improvement with testing exception instead of testing in.
We can also see the overhead due to the test before removing in list.

I’ve also tested with xrange(-500, 500) instead of (0, 500), to trigger invalid removal. Here is the result :

bench_in_remove time=12.42448401 count=1000
bench_exception time=14.26106405 count=1000

Triggering an exception cost much time than testing if value is in a list…

PyMT Impact: must check.

Python: is X is better than Y ? Round 1, deque vs list.

This week-end, i’ve spend some time about searching how to optimize PyMT code. And done some interesting benchmark. Next days, i’ll post some of them, in order to remember which is the better solution.

For the first round: let’s test Deque from collections package VS Python List !


from time import time

# collections VS list
def bench_deque(count):
    from collections import deque
    q = deque()
    for x in xrange(count):
        for z in xrange(1000):
        while True:

def bench_list(count):
    q = []
    for x in xrange(count):
        for z in xrange(1000):
        for y in xrange(len(q)):

def run(f, c=100000):
    t = time()
    print '%-15s time=%.8f count=%d' % (f.func_name, time() - t, c)


And the result :

bench_deque     time=35.61677003 count=100000
bench_list      time=78.20481586 count=100000

Impact for PyMT: wm_pen, wm_touch.

Color swapping and Python

For PyMT, Sharath need BGR support into PyMT, while his graphic card don’t support GL_BGR.
Well, after adapting swap code from Pyglet sourcecode, he say: “< patali> it works but very slow”

The goal is to swap a string from ‘bgrbgrbgr’ to ‘rgbrgbrgb’. Just let’s do a rapid benchmark.

import sys
import re
import time

swap1_pattern = re.compile('(.)(.)(.)', re.DOTALL)
swap1_repl = r'\3\2\1'
def swap1(bytes):
    return swap1_pattern.sub(swap1_repl, bytes)

def swap2(bytes):
    out = ''
    for i in xrange(0, len(bytes), 3):
        b, g, r = bytes[i:i+3]
        out += r
        out += g
        out += b
    return out

def swap3(bytes):
    bytes = list(bytes)
    for i in xrange(0, len(bytes), 3):
        b, g, r = bytes[i:i+3]
        bytes[i:i+3] = r, g, b
    return ''.join(bytes)

def swap4(bytes):
    blues = bytes[0::3]
    greens = bytes[1::3]
    reds = bytes[2::3]
    return ''.join(''.join(x) for x in zip(reds, greens, blues))

def swap5(bytes):
    from array import array
    a = array('b', bytes)
    a[0::3], a[2::3] = a[2::3], a[0::3]
    return a.tostring()

def swap6(bytes):
    import numpy
    a = numpy.array(bytes, 'c')
    b = a[...,::-1]
    return b.tostring()

def swap7(bytes):
    a = list(bytes)
    a[0::3], a[2::3] = a[2::3], a[0::3]
    return ''.join(a)

def bench(func, bytes):
    sys.stderr.write('Bench %s: ' % str(func))

    start = time.time()
    for i in xrange(20):
        ret = func(bytes)
        if ret[:3] != 'rgb' or ret[-3:] != 'rgb':
            sys.stderr.write('INVALID DATA, start=%s, end=%s' %
                            (ret[:3], ret[-3:]))

    end = time.time() - start
    sys.stderr.write('| Finished in %.4f
' % end)
    return ret

bytes = 'bgr' * 256 * 256
bench(swap1, bytes)
bench(swap2, bytes)
bench(swap3, bytes)
bench(swap4, bytes)
bench(swap5, bytes)
bench(swap6, bytes)
bench(swap7, bytes)

Swap1() is actually the way of pyglet. swap2/swap3 is from me, and others is found on some threads in pygame mailing list.

So, who win ?

21:09 tito@ashaka ~ $ python 
Bench <function swap1 at 0x7f1d154632a8>: ....................| Finished in 3.2713
Bench <function swap2 at 0x7f1d15463230>: ....................| Finished in 1.2860
Bench <function swap3 at 0x7f1d15470cf8>: ....................| Finished in 0.6535
Bench <function swap4 at 0x7f1d15470e60>: ....................| Finished in 0.6475
Bench <function swap5 at 0x7f1d15470ed8>: ....................| Finished in 0.0367
Bench <function swap6 at 0x7f1d15470f50>: ....................| Finished in 0.1959
Bench <function swap7 at 0x7f1d15473050>: ....................| Finished in 0.1482

The array solution is a lot faster than any other implementation ! And it’s python standard 🙂 Let’s take this…

Edit: thanks for Milan to come with another awesome solution !

def swap0(bytes):
  return bytes[::-1]

Result is: 0.0059 !

Spreading PyMT toolkit

I’ve been some week without blogging, but lot of things happened ! Finally, i’ve been able to see Thomas in IRL at Google Mentor Summit in San Francisco. It was an awesome week-end, funny, creative and geeky ! Lot of ideas, and goal : making PyMT more stable and well designed : the roadmap of PyMT 0.4 is finally available. We’ve also done a little session too at summit.

Thomas is now 3 days to ITS 2009 in Banff Canada, for a conference about PyMT. The paper will be available for everyone soon 🙂 And this week-end, i’m going to Edinburgh with Lucie to meet Mark, and see the awesome new multitouch room of Napier University. Sharath is also going next week to a FOSS in India to spread PyMT too 🙂

Theses days are really cool 🙂

San Francisco, i’m coming !

Here is a very good news, Christian, Pawel and Nuigroup support me to go on the Google Mentor Summit, in 23/24 October ! I’ll finally meet all of them, and specially Thomas, the creator of awesome PyMT framework 🙂

This is the result to take care of Sharath during his GSOC 🙂

I’ll stay 2 days more with Thomas, to hack the future PyMT :p (well, work isn’t the real word… i want to see California a little :p)

Thanks Guys !

Experimenting widget animation with Fbo

PyMT provide 2 way to make animations :

  • property animation with Animation() class, can be created with start_animation() / stop_animation(),
  • inner animation, that watch changes on a property and start automatically an animation.

They are things we cannot do actually :

  • Fade in/out a widget and their children
  • Scale the widget content

So, i was thinking to use Fbo to make more complex animation on a widget.

Before starting the how-to, here a demo-video.

PyMT – New desktop with menu animation