Quick And Easy Execution Speed Testing

There have been many times when I've been programming, encounter a problem that probably involves a loop of some sort, and I think of two or more possible ways to achieve the same end result. At this point, I usually think about which one will probably be the fastest solution (execution-wise) while still being readable/maintainable. A lot of the time, the essentials of the problem can be tested in a few short lines of code.

A while back, I was perusing some Stack Overflow questions for work, and I stumbled upon what I consider one of the many hidden jewels in Python: the timeit module. Given a bit of code, this little guy will handle executing it in several loops and giving you the best time out of three trials (you can ask it to do more than 3 runs if you want). Once it completes its test, it will offer some very clean and useful output.

For example, today I encountered a piece of code that was making a comma-separated list of an arbitrary number of "%s". The code I saw essentially looked like this:

",".join(["%s"] * 50000)

Even though this code required no optimization, I thought, "Hey, that's neat... I wonder if a list comprehension could possibly be any faster." Here's an example of the contender:

",".join(["%s" for i in xrange(50000)])

I had no idea which would be faster, so timeit to the rescue!! Open up a terminal, type a couple one-line Python commands, and enjoy the results!

$ python -mtimeit 'l = ",".join(["%s"] * 50000)'
1000 loops, best of 3: 1.15 msec per loop
$ python -mtimeit 'l = ",".join(["%s" for i in xrange(50000)])'
100 loops, best of 3: 3.23 msec per loop

Hah, the list comprehension is certainly slower.

Now, for other more in-depth tests of performance, you might consider using the cProfile module. As far as I can tell, simple one-liners can't be tested directly from the command line using cProfile--they apparently need to be in a script. You can use something like:

python -mcProfile script.py

...in such situations. Or you can wrap function calls using cProfile.run():

import cProfile

def function_a():
    # something you want to profile

def function_b():
    # an alternative version of function_a to profile

if __name__ == '__main__':
    cProfile.run('function_a()')
    cProfile.run('function_b()')

I've used this technique for tests that I'd like to have "hard evidence" for in the future. The output of such a cProfile test looks something like this:

3 function calls in 6.860 CPU seconds

Ordered by: standard name

ncalls  tottime  percall  cumtime  percall filename:lineno(function)
     1    0.000    0.000    6.860    6.860 <string>:1(<module>)
     1    6.860    6.860    6.860    6.860 test_enumerate.py:5(test_enumerate)
     1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

This is useful when your code is calling other functions or methods and you want to find where your bottlenecks are. Hooray for Python!

What profiling techniques do you use?

Comments

Comments powered by Disqus

Navigation

Recent Articles

Tag Cloud

adsense  apache  arch  arduino  articles  auto-tagging  bash  bitbucket  blog  bluray  bonding  breadboard  c  cache  caching  chrome  cisco  command-line  css  database  death  design  desktop  diff  dillon  django  django-articles  django-tracking  documentation  docutils  downtime  driver  easy_install  eeepc  eth0  exec  face-tracking  fedora  feed  firefox  fishing  freelance  fujifilm  git  github  gnome  google  gstreamer  hooks  how-to  howto  html  idiocy  imap4  imgburn  internet  java  javascript  js  kara  kde  kernel  kurt  lcd  led  linux  logging  lvm  mac  macintosh  mail  matt  mercurial  middleware  mindy  mobile  motion  mouse  multiprocessing  network-manager  networking  news  novell  open-source  opencv  opensuse  optimization  osx  packt-publishing  performance  photography  php  picnic  pip  pir  pop3  profile  profiling  programming  projects  pycon  pygments  pypi  python  regex  regular-expression  resistor  rest  restructuredtext  review  rss  ruby  school  scm  scroll  sd-card  security  sed  selenium  servo  site-wide  slackware  sled  soldering  sparkfun  sphinx  ssd  step-by-step  stupid  style  subversion  suse  svn  syndication  templates  terminal  testing  thanks  tips  tornado  tutorial  twitter  unit-testing  unix  updates  utilities  v4l2loopback  vcs  version-control  vim  virtualbox  vista  vpn  web  web-development  webcam  webfaction  windows  wireless  wlan0  work  wxpython  xorg  xwindows