tungwaiyip.info

home

about me

links

my software

Media

Yucatán Photos

St Lucia Photos

Photo Album

Videos

Blog

< July 2009 >
SuMoTuWeThFrSa
    1 2 3 4
5 6 7 8 91011
12131415161718
19202122232425
262728293031 

past articles »

Click for San Francisco, California Forecast

San Francisco, USA

 

ctype performance benchmark

I have done some performance benchmarking for Python's ctypes library. I am planning to use ctypes as an alternative to writing C extension module for performance enhancement. Therefore my use case is slight different from the typical use case for accessing existing third party C libraries. In this case I am both the user and the implementer of the C library.

In order to determine what is the right granularity for context switching between Python and C, I have done some benchmarking. I mainly want to measure the function call overhead. So the test functions are trivial function like returning the first character of a string. I compare a pure Python function versus C module function versus ctypes function. The tests are ran under Python 2.6 on Windows XP with Intel 2.33Ghz Core Duo.

First of all I want to compare the function to get the first character of a string. The most basic case is to reference it as the 0th element of a sequence without calling any function. The produce the fastest result at 0.0659 usec per loop.

  $ timeit "'abc'[0]"

  10000000 loops, best of 3: 0.0659 usec per loop

As soon as I build a function around it, the cost goes up substantially. Both pure Python and C extension method shows similar performance at around 0.5 usec. ctypes function takes about 2.5 times as long at 1.37 usec.

  $ timeit -s "f=lambda s: s[0]"  "f('abc')"

  1000000 loops, best of 3: 0.506 usec per loop

  $ timeit -s "import mylib" "mylib.py_first('abc')"

  1000000 loops, best of 3: 0.545 usec per loop

  $ timeit -s "import ctypes; dll = ctypes.CDLL('mylib.pyd')"
              "dll.first('abc')"

  1000000 loops, best of 3: 1.37 usec per loop

I repeated the test with a long string (1MB). There are not much difference in performance. So I can be quite confident that the parameter is passed by reference (of the internal buffer).

  $ timeit -s "f=lambda s: s[0]; lstr='abcde'*200000"
              "f(lstr)"

  1000000 loops, best of 3: 0.465 usec per loop

  $ timeit -s "import mylib; lstr='abcde'*200000"
              "mylib.py_first(lstr)"

  1000000 loops, best of 3: 0.539 usec per loop

  $ timeit -s "import ctypes; dll = ctypes.CDLL('mylib.pyd')"
           -s "lstr='abcde'*200000"
              "dll.first(lstr)"

  1000000 loops, best of 3: 1.4 usec per loop

Next I have make some attempts to speed up ctypes performance. A measurable improvement can be attained by eliminating the attribute look up for the function. Curiously this shows no improvement in the similar case for C extension.

  $ timeit -s "import ctypes; dll = ctypes.CDLL('mylib.pyd');
           -s "f=dll.first"
              "f('abcde')"

  1000000 loops, best of 3: 1.18 usec per loop

Secondary I have tried to specify the ctypes function prototype. This actually decrease the performance significantly.

  $ timeit -s "import ctypes; dll = ctypes.CDLL('mylib.pyd')"
           -s "f=dll.first"
           -s "f.argtypes=[ctypes.c_char_p]"
           -s "f.restype=ctypes.c_int"
              "f('abcde')"

  1000000 loops, best of 3: 1.57 usec per loop

Finally I have tested passing multiple parameters into the function. One of the parameter is passed by reference in order to return a value. Performance decrease as the number of parameter increase.

  $ timeit -s "charAt = lambda s, size, pos: s[pos]"
           -s "s='this is a test'"
              "charAt(s, len(s), 1)"

  1000000 loops, best of 3: 0.758 usec per loop

  $ timeit -s "import mylib; s='this is a test'"
              "mylib.py_charAt(s, len(s), 1)"

  1000000 loops, best of 3: 0.929 usec per loop

  $ timeit -s "import ctypes"
           -s "dll = ctypes.CDLL('mylib.pyd')"
           -s "s='this is a test'"
           -s "ch = ctypes.c_char()"
              "dll.charAt(s, len(s), 1, ctypes.byref(ch))"

  100000 loops, best of 3: 2.5 usec per loop

One style of coding that improve the performance somewhat is to build a C struct to hold all the parameters.

  $ timeit -s "from test_mylib import dll, charAt_param"
           -s "s='this is a test'"
           -s "obj = charAt_param(s=s, size=len(s), pos=3, ch='')"
              "dll.charAt_struct(obj)"

  1000000 loops, best of 3: 1.71 usec per loop

This may work because most of the fields in the charAt_param struct are invariant in the loop. Having them in the same struct object save them from getting rebuilt each time.

My overall observation is that ctypes function has an overhead that is 2 to 3 times to a similar C extension function. This may become a limiting factor if the function calls are fine grained. Using ctypes for performance enhancement is a lot more productive if the interface can be made to medium or coarse grained.

A snapshot of the source code used for testing is available for download. This is also useful if you want a boiler plate for building your own ctypes library.

2009.07.16 [] - comments

 

 

blog comments powered by Disqus

past articles »

 

BBC News

 

Anger mounts as Gaza toll rises (30 Jul 2014)

 

G7 says Russia faces more sanctions (30 Jul 2014)

 

Ebola: Liberia shuts all schools (30 Jul 2014)

 

Dozens trapped by Indian landslide (30 Jul 2014)

 

Tor attack may have unmasked users (30 Jul 2014)

 

Six dead in Nigeria college blast (30 Jul 2014)

 

US economic growth surges by 4% (30 Jul 2014)

 

France evacuates expats from Libya (30 Jul 2014)

 

Somali 'killed for not wearing veil' (30 Jul 2014)

 

House to vote to sue President Obama (30 Jul 2014)

more »

 

Slashdot News for nerds, stuff that matters

 

Amazon's eBook Math (2014-07-30T22:12:00Z)

 

The Problems With Drug Testing (2014-07-30T21:30:00Z)

 

Is the App Store Broken? (2014-07-30T20:47:00Z)

 

Meet Apache Software Foundation VP Rich Bowen (Video) (2014-07-30T20:05:00Z)

 

More Quantum Strangeness: Particles Separated From Their Properties (2014-07-30T19:20:00Z)

 

Jesse Jackson: Tech Diversity Is Next Civil Rights Step (2014-07-30T18:38:00Z)

 

Raspberry Pi-Compatible Development Board Released (2014-07-30T17:55:00Z)

 

Quiet Cooling With a Copper Foam Heatsink (2014-07-30T17:13:00Z)

more »

 

TechPsychic Tech Rumors and Invented News

more »

 

SF Gate

 

Bay Area News (7 Jan 2012)

 

City Insider (11 Feb 2012)

 

Crime Scene (13 Feb 2012)

 

C.W Newius Column (10 Jan 2012)

 

C.W. Nevius Blog (11 Feb 2012)

 

Education News (10 Jan 2012)

 

KALW (11 Feb 2012)

 

Matier and Ross Blog (11 Feb 2012)

 

Jerry Brown quietly taking care of business in Mexico (29 Jul 2014)

 

U.S. homeownership falls to 64.7% (29 Jul 2014)

 

,000-per-pill Sovaldi now hepatitis treatment of choice (29 Jul 2014)

 

Android 'Fake ID' flaw could let hackers hijack device (29 Jul 2014)

 

Snapdeal founder keeps close eye on Alibaba IPO (29 Jul 2014)

 

Twitter's stock soars as user growth climbs (29 Jul 2014)

more »

 

Asia Times Online

 

THE ROVING EYE Crime (Israel) and punishment (Russia) (Wed 30 Jul 2014 11:00:00 GMT)

 

Vietnam buckles under Chinese pressure (Wed 30 Jul 2014 11:00:00 GMT)

 

Dozens of Uyghurs killed in Xinjiang clashes (Wed 30 Jul 2014 11:00:00 GMT)

 

http://www.atimes.com/atimes/Middle_East/MID-01-300714.html (Wed 30 Jul 2014 11:00:00 GMT)

 

CHAN AKYA An era of thugs (Wed 30 Jul 2014 11:00:00 GMT)

 

The Pashtun factor in Pakistan's insurgency (Wed 30 Jul 2014 11:00:00 GMT)

 

BOOK REVIEW Pakistan's proclivity for war (Wed 30 Jul 2014 11:00:00 GMT)

 

JOHN PILGER Palestine, war and lethal reporting (Wed 30 Jul 2014 11:00:00 GMT)

 

Russia told to pay in Yukos case (Wed 30 Jul 2014 11:00:00 GMT)

 

Central Asia clash mars China gas plan (Wed 30 Jul 2014 11:00:00 GMT)

 

THE BEAR'S LAIR Business and free markets (Wed 30 Jul 2014 11:00:00 GMT)

more »

 


Site feed Updated: 2014-Jul-30 16:00