Cobry
Cobry

Reputation: 4548

cython times 10 slower

I am trying to boost up some calculations in python by using cython ... In my calculations I will be doing double loops or more plus I can't always use numpy vectorization so I need to boost up the python loops with cython.

here I benchmark some simple calculation and it shows so far that cython is 10 times slower than using numpy. I am sure that numpy is optimized to the max and I doubt I could be able to beat its performance but still factor of 10 slower means I am doing something wrong. Suggestions ?

test.py

import numpy as np
from histogram import distances
import time

REPEAT = 10

def printTime(message, t):
    print "%s total: %.7f(s) --> average: %.7f(s)    %.7f(Ms)"%(message, t, t/REPEAT, 1000000*t/REPEAT)

DATA = np.array( np.random.random((10000, 3)), dtype=np.float32)
POINT = np.array( np.random.random((1,3)), dtype=np.float32)

# numpy histogram
r = REPEAT
startTime = time.clock()
while r:
    diff = (DATA-POINT)%1
    diffNumpy = np.where(diff<0, diff+1, diff)
    distNumpy = np.sqrt( np.add.reduce(diff**2,1) )
    r-=1
printTime("numpy", time.clock()-startTime)

# cython test
r = REPEAT
startTime = time.clock()
while r:
    distCython = distances(POINT, DATA)
    r-=1
printTime("cython", time.clock()-startTime)

histogram.pyx

import numpy as np
import cython
cimport cython
cimport numpy as np

DTYPE=np.float32
ctypedef np.float32_t DTYPE_C

@cython.nonecheck(False)
@cython.boundscheck(False)
@cython.wraparound(False)
def distances(np.ndarray[DTYPE_C, ndim=2] point, np.ndarray[DTYPE_C, ndim=2] data):
    # declare variables
    cdef int i
    cdef float x,y,z
    cdef np.ndarray[DTYPE_C,  mode="c", ndim=1] dist = np.empty((data.shape[0]),   dtype=DTYPE)

    # loop
    for i from 0 <= i < data.shape[0]:
        # calculate distance
        x = (data[i,0]-point[0,0])%1
        y = (data[i,1]-point[0,1])%1
        z = (data[i,2]-point[0,2])%1
        # fold between 0 and 1
        if x<0: x+=1
        if y<0: y+=1
        if z<0: z+=1
        # assign to array
        dist[i] = np.sqrt(x**2+y**2+z**2)
    return dist

setup.py

from distutils.core import setup
from Cython.Build import cythonize
import numpy as np
setup(
    ext_modules = cythonize("histogram.pyx"),
    include_dirs=[np.get_include()]
)

to compile do the following python setup.py build_ext --inplace

to launch benchmarch python test.py

My results are

numpy total: 0.0153390(s) --> average: 0.0015339(s)    1533.9000000(Ms)
cython total: 0.1509920(s) --> average: 0.0150992(s)    15099.2000000(Ms)

Upvotes: 0

Views: 263

Answers (1)

Veedrac
Veedrac

Reputation: 60137

Your problem is almost definitely

np.sqrt(x**2+y**2+z**2)

You should use the C sqrt function. It will look something like

from libc.math cimport sqrt

sqrt(x*x + y*y + z*z)

Upvotes: 2

Related Questions