Profiling Cython code

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.

How to do it...

This section demonstrates how to profile Cython code. To do this, go through the following steps:

  • NumPy approximation of e: For the NumPy approximation of e perform the following steps:
    1. First, we will create an array of 1 to n (n is 40 in our example).
    2. Then, we will compute the cumulative product of this array, which happens to be the factorial.
    3. After that, we take the reciprocal of the factorials.
    4. Finally, we apply the formula from the Wikipedia page. At the end, we put standard profiling code, giving us the following program:
      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}
  • Cython approximation of e: The Cython code uses the same algorithm as in the previous step, but the implementation is different. There are less convenience functions, and we actually need a 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}

How it works...

We profiled NumPy and Cython code. NumPy is heavily optimized for speed, so we should not be surprised that both NumPy and Cython programs are high-performing programs.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset