consideri il seguente esempio minimo:Cython boundscheck = True veloce di boundscheck = False
#cython: language_level=3, boundscheck=False, wraparound=False, initializedcheck=False, cdivision=True
cimport cython
from libc.stdlib cimport malloc
def main(size_t ni, size_t nt, size_t nx):
cdef:
size_t i, j, t, x, y
double[:, :, ::1] a = <double[:ni, :ni, :nx]>malloc(ni * ni * nx * sizeof(double))
double[:, :, ::1] b = <double[:nt, :ni, :nx]>malloc(nt * ni * nx * sizeof(double))
size_t[:, :, ::1] best = <size_t[:nt, :ni, :nx]>malloc(nt * ni * nx * sizeof(size_t))
size_t mxi
double s, mxs
for t in range(nt):
for j in range(ni):
for y in range(nx): # this loops does nothing but is needed for the effect below.
mxs = -1e300
for i in range(ni):
for x in range(nx):
with cython.boundscheck(False): # Faster!?!?
s = b[t, i, x] + a[i, j, x]
if s >= mxs:
mxs = s
mxi = i
best[t + 1, j, y] = mxi
return best[0, 0, 0]
essenzialmente sommando due matrici 2D lungo alcuni assi specifici e trovare l'indice massimizzazione lungo un altro asse.
Quando è compilato con gcc -O3 e chiamato con gli argomenti (1, 2000, 2000), aggiungendo il boundscheck = True risulta in un'esecuzione due volte più veloce di quando boundscheck = False.
Qualche suggerimento sul perché questo sarebbe il caso? (Beh, posso probabilmente immaginare che questo abbia di nuovo a che fare con l'autovectorization di GCC ...)
Grazie in anticipo.
(Cross-postato da Cython utenti)
Nel mio test, la versione con 'con cython.boundscheck (True)' è di circa 3 volte più lento. Penso che la memoria di 'a',' b', 'best' non sia inizializzata a causa di' malloc'. L'ho modificato in una chiamata equivalente a 'calloc'. Inoltre, la riga 'best [t + 1, j, y]' sembra indicizzare memoria non valida quando 't == nt - 1'. –
Cambiare mallocs in callocs e sostituire 't + 1' con' t' non cambia (qualitativamente) i risultati per me. Il mio 'setup.py' ha' extra_compile_args = ["- O3"] 'e sto usando gcc 5.1.0. – antony
OK, ho provato con -O3, e ottengo la stessa velocità con entrambe le versioni. Sto usando gcc 4.9.1. Osservando il codice C generato, penso che sia possibile che gcc sia abbastanza intelligente da sapere che i controlli extra bound non verranno mai attivati (a causa della condizione for loop). Non so perché si ottengono così diverse velocità. –