Posts

Profiling is the first step to improving the performance of code. Suppose we want to profile the Python script below which is based on the example here. It prints out the first 20 Fibonacci numbers and is unoptimized to make the profile exaggerated.

def fib(n):
    if n == 0:
        return 0
    elif n == 1:
        return 1
    else:
        return fib(n-1) + fib(n-2)

def fib_seq(n):
    seq = [ ]
    if n > 0:
        seq.extend(fib_seq(n-1))
    seq.append(fib(n))
    return seq

print(fib_seq(20))

To generate a profile of the script, we can run the module via cProfile.

python -m cProfile -o profile.out fibonacci.py

This will generate a profile of the runtime of fibonacci.py and save it to the profile.out file. Now we need to translate the profile into a format that QCacheGrind can read. The bash script below was written by a colleague of mine and will do that conversion and launch QCacheGrind. pyprof2calltree is needed for this script to run and it can be installed via pip install pyprof2calltree.

#!/bin/bash

PROF_FILE=$(basename "$1")
PROF_DIR=$(dirname "$1")
echo $PROF_DIR
PROF_DIR="${PROF_DIR:-.}"
CACHEGRIND_FILE="callgrind-${PROF_FILE}"

pyprof2calltree -i "${PROF_DIR}/${PROF_FILE}" -o "${PROF_DIR}/${CACHEGRIND_FILE}"
qcachegrind "${PROF_DIR}/${CACHEGRIND_FILE}"

This script takes a single argument which is the output of the previous step.

./profile profile.out

QCacheGrind Profile

And that’s all there is to it. Overall, QCacheGrid is a very useful tool for finding bottlenecks and performance issues and this simple script nicely ties it into Python.