We will profile Cython and NumPy code that tries to approximate the Euler constant. You can refer to http://en.wikipedia.org/wiki/E_%28mathematical_constant%29 for the required formula.
This section demonstrates how to profile Cython code. To do this, go through the following steps:
import numpy import cProfile import pstats def approx_e(n=40): # array of [1, 2, ... n-1] arr = numpy.arange(1, n) # calculate the factorials and convert to floats arr = arr.cumprod().astype(float) # reciprocal 1/n arr = numpy.reciprocal(arr) print 1 + arr.sum() cProfile.runctx("approx_e()", globals(), locals(), "Profile.prof") s = pstats.Stats("Profile.prof") s.strip_dirs().sort_stats("time").print_stats()
The profiling output and the result for the e approximation is shown in the following snippet. Please refer to Chapter 7, Profiling and Debugging, for more information about the profiling output.
2.71828182846 7 function calls in 0.000 CPU seconds Ordered by: internal time ncalls tottime percall cumtime percall filename:lineno(function) 1 0.000 0.000 0.000 0.000 numpy_approxe.py:5(approx_e) 1 0.000 0.000 0.000 0.000 {method 'cumprod' of 'numpy.ndarray' objects} 1 0.000 0.000 0.000 0.000 {numpy.core.multiarray.arange} 1 0.000 0.000 0.000 0.000 {method 'sum' of 'numpy.ndarray' objects} 1 0.000 0.000 0.000 0.000 {method 'astype' of 'numpy.ndarray' objects} 1 0.000 0.000 0.000 0.000 <string>:1(<module>) 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
for
loop now. Also, we need to specify types for some of the variables. The code for the .pyx
file is shown as follows:def approx_e(int n=40): cdef double sum = 0. cdef double factorial = 1. cdef int k for k in xrange(1,n+1): factorial *= k sum += 1/factorial print 1 + sum
The following Python program imports the Cython module and does some profiling.
import pstats import cProfile import pyximport pyximport.install() import approxe cProfile.runctx("approxe.approx_e()", globals(), locals(), "Profile.prof") s = pstats.Stats("Profile.prof") s.strip_dirs().sort_stats("time").print_stats()
This is the profiling output of the Cython code:
2.71828182846 3 function calls in 0.000 CPU seconds Ordered by: internal time ncalls tottime percall cumtime percall filename:lineno(function) 1 0.000 0.000 0.000 0.000 {approxe.approx_e} 1 0.000 0.000 0.000 0.000 <string>:1(<module>) 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}