Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Improve cython array indexing speed

I'm have a pretty simple function which I need to speed up. Essentially I have a big array of 16 bit numbers with some holes in it. (About 10%) I need to traverse the array, find areas where there are 2 0's in a row, then fill them in with the average of the previous and next elements. This takes only a few milliseconds in C, but Python is doing way worse.

I've switched from regular python arrays to numpy arrays, and then compiled my code using cython, but I'm still really far from my target. I was hoping someone with more experience might look at what I'm doing and give me some feedback.

My regular python code looks like this:

self.rawData = numpy.fromfile(ql, numpy.uint16, 50000)
[snip]
def fixZeroes(self):
    for x in range(2,len(self.rawData)):
        if self.rawData[x] == 0 and self.rawData[x-1] == 0:
            self.rawData[x] = (self.rawData[x-2] + self.rawData[x+2]) / 2
            self.rawData[x-1] = (self.rawData[x-3] + self.rawData[x+1]) /2

My Cython code looks very similar:

import numpy as np
cimport numpy as np
DTYPE = np.uint16
ctypedef np.uint16_t DTYPE_t

@cython.boundscheck(False)
def fix_zeroes(np.ndarray[DTYPE_t, ndim=1] raw):
    assert raw.dtype == DTYPE
    cdef int len = 50000
    
    for x in range(2,len):
        if raw[x] == 0 and raw[x-1] == 0:
            raw[x] = (raw[x-2] + raw[x+2]) / 2
        raw[x-1] = (raw[x-3] + raw[x+1]) /2
    return raw

When I run this code, the performance is still way slower than I'd like:

Starting cython zero fix

Finished: 0:00:36.983681

starting python zero fix

Finished: 0:00:41.434476

I really think I must be doing something wrong. Most every article I've seen talks about the huge performance gains numpy and cython add, but I'm barely breaking 10%.

like image 214
Maxwell Bottiger Avatar asked Mar 19 '23 16:03

Maxwell Bottiger


1 Answers

You should declare the x variable that you are using to index the raw array:

cdef int x

you can also use other directives that usually provide a performance boost:

@cython.wraparound(False)
@cython.cdivision(True)
@cython.nonecheck(False)
like image 103
Saullo G. P. Castro Avatar answered Mar 27 '23 11:03

Saullo G. P. Castro