Commit 2bb1e147 authored by Robert Bradshaw's avatar Robert Bradshaw

More work on quickstart.

--HG--
rename : src/tutorial/htmlreport.png => src/quickstart/htmlreport.png
parent 6e0a3823
...@@ -20,7 +20,8 @@ point types, complex numbers, structs, unions and pointer types. ...@@ -20,7 +20,8 @@ point types, complex numbers, structs, unions and pointer types.
Cython can automatically and correctly convert between the types on Cython can automatically and correctly convert between the types on
assignment. This also includes Python's arbitrary size integer types, assignment. This also includes Python's arbitrary size integer types,
where value overflows on conversion to a C type will raise a Python where value overflows on conversion to a C type will raise a Python
``OverflowError`` at runtime. The generated C code will handle the ``OverflowError`` at runtime. (It does not, however, check for overflow
when doing arithmetic.) The generated C code will handle the
platform dependent sizes of C types correctly and safely in this case. platform dependent sizes of C types correctly and safely in this case.
Types are declared via the cdef keyword. Types are declared via the cdef keyword.
...@@ -31,10 +32,8 @@ Typing Variables ...@@ -31,10 +32,8 @@ Typing Variables
Consider the following pure Python code:: Consider the following pure Python code::
from math import sin
def f(x): def f(x):
return sin(x**2) return x**2-x
def integrate_f(a, b, N): def integrate_f(a, b, N):
s = 0 s = 0
...@@ -43,16 +42,14 @@ Consider the following pure Python code:: ...@@ -43,16 +42,14 @@ Consider the following pure Python code::
s += f(a+i*dx) s += f(a+i*dx)
return s * dx return s * dx
Simply compiling this in Cython merely gives a 5% speedup. This is Simply compiling this in Cython merely gives a 35% speedup. This is
better than nothing, but adding some static types can make a much larger better than nothing, but adding some static types can make a much larger
difference. difference.
With additional type declarations, this might look like:: With additional type declarations, this might look like::
from math import sin
def f(double x): def f(double x):
return sin(x**2) return x**2-x
def integrate_f(double a, double b, int N): def integrate_f(double a, double b, int N):
cdef int i cdef int i
...@@ -69,7 +66,7 @@ in arithmetic withing the for-loop; typing ``b`` and ``N`` makes less of a ...@@ -69,7 +66,7 @@ in arithmetic withing the for-loop; typing ``b`` and ``N`` makes less of a
difference, but in this case it is not much extra work to be difference, but in this case it is not much extra work to be
consistent and type the entire function. consistent and type the entire function.
This results in a 24 times speedup over the pure Python version. This results in a 4 times speedup over the pure Python version.
Typing Functions Typing Functions
---------------- ----------------
...@@ -83,12 +80,15 @@ argument in order to pass it. ...@@ -83,12 +80,15 @@ argument in order to pass it.
Therefore Cython provides a syntax for declaring a C-style function, Therefore Cython provides a syntax for declaring a C-style function,
the cdef keyword:: the cdef keyword::
cdef double f(double) except *: cdef double f(double) except? -2:
return sin(x**2) return x**2-x
Some form of except-modifier should usually be added, otherwise Cython Some form of except-modifier should usually be added, otherwise Cython
will not be able to propagate exceptions raised in the function (or a will not be able to propagate exceptions raised in the function (or a
function it calls). Above ``except *`` is used which is always function it calls). The ``except? -2`` means that an error will be checked
for if ``-2`` is returned (though the ``?`` indicates that ``-2`` may also
be used as a valid return value).
Alternatively, the slower ``except *`` is always
safe. An except clause can be left out if the function returns a Python safe. An except clause can be left out if the function returns a Python
object or if it is guaranteed that an exception will not be raised object or if it is guaranteed that an exception will not be raised
within the function call. within the function call.
...@@ -102,13 +102,25 @@ objects). ...@@ -102,13 +102,25 @@ objects).
Note also that it is no longer possible to change ``f`` at runtime. Note also that it is no longer possible to change ``f`` at runtime.
Speedup: 45 times over pure Python. Speedup: 150 times over pure Python.
.. figure:: htmlreport.png Determining where to add types
------------------------------
Using the ``-a`` switch to the ``cython`` command line program (or Because static typing is often the key to large speed gains, beginners
following a link from the Sage notebook) results in an HTML report often have a tendency to type everything in site. This cuts down on both
of Cython code interleaved with the generated C code. Lines are readability and flexibility. On the other hand, it is easy to kill
colored according to the level of "typedness" -- white lines performance by forgetting to type a critical loop variable. Two essential
translates to pure C without any Python API calls. This report tools to help with this task are profiling and annotation.
is invaluable when optimizing a function for speed. Profiling should be the first step of any optimization effort, and can
tell you where you are spending your time. Cython's annotation can then
tell you why your code is taking time.
Using the ``-a`` switch to the ``cython`` command line program (or
following a link from the Sage notebook) results in an HTML report
of Cython code interleaved with the generated C code. Lines are
colored according to the level of "typedness" -- white lines
translates to pure C without any Python API calls. This report
is invaluable when optimizing a function for speed.
.. figure:: htmlreport.png
from time import time
from math import sin
cdef double first_time = 0
def timeit(f, label):
global first_time
t = time()
f(1.0, 2.0, 10**7)
cdef double elapsed = time() - t
if first_time == 0:
first_time = elapsed
print label, elapsed, (100*elapsed/first_time), '% or', first_time/elapsed, 'x'
# Pure Python
py_funcs = {'sin': sin}
py_funcs.update(__builtins__.__dict__)
exec """
def f(x):
return x**2-x
def integrate_f(a, b, N):
s = 0
dx = (b-a)/N
for i in range(N):
s += f(a+i*dx)
return s * dx
""" in py_funcs
timeit(py_funcs['integrate_f'], "Python")
# Just compiled
def f0(x):
return x**2-x
def integrate_f0(a, b, N):
s = 0
dx = (b-a)/N
for i in range(N):
s += f0(a+i*dx)
return s * dx
timeit(integrate_f0, "Cython")
# Typed vars
def f1(double x):
return x**2-x
def integrate_f1(double a, double b, int N):
cdef int i
cdef double s, dx
s = 0
dx = (b-a)/N
for i in range(N):
s += f1(a+i*dx)
return s * dx
timeit(integrate_f1, "Typed vars")
# Typed func
cdef double f2(double x) except? -2:
return x**2-x
def integrate_f2(double a, double b, int N):
cdef int i
cdef double s, dx
s = 0
dx = (b-a)/N
for i in range(N):
s += f2(a+i*dx)
return s * dx
timeit(integrate_f2, "Typed func")
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment