2015-06-01 19 views
7

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)

+1

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'. –

+0

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

+1

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à. –

risposta

-1

Boundscheck è un controllo di sicurezza che si accede indici all'interno dei limiti dei vettori. Se non ti preoccupi di controllare se gli indici possono andare fuori limite, allora è più veloce. Ci vuole tempo per eseguire il controllo.

Cioè, se boundcheck è true, controllerà se l'indice è all'interno dell'intervallo del vettore prima di leggere o scrivere in memoria. E se no, genererà un errore. Se boundcheck è falso, leggerà o scriverà sul puntatore anche se l'indice è fuori limite, dati falsi dati leggendo e scrivendo nella memoria corrompendo i dati scrivendo.

Dalla documentazione:

Le ricerche matrice sono ancora rallentati da due fattori: viene eseguita

1) controllo dei limiti.

2) Gli indici negativi vengono controllati e gestiti correttamente.

Le conseguenze di non vincolati dell'essere controllo:

Ora controllo dei limiti non viene eseguita (e, come effetto collaterale, se '' non '' capita di accedere fuori dai limiti si vuole nel migliore dei casi si blocca il programma e nel peggiore dei casi i dati corrotti).

Ove ciò sia particolarmente importante, è possibile disporre di Nessuno vettore. Ecco l'avvertimento dalla documentazione:

Attenzione

velocità viene fornito con un certo costo. Soprattutto può essere pericoloso impostare oggetti digitati (come f, geh nel nostro codice campione) su Nessuno. L'impostazione di di tali oggetti su Nessuno è del tutto legale, ma tutto ciò che puoi fare con loro è controllare se sono Nessuno. Tutti gli altri usi (ricerca attributi o indicizzazione ) possono potenzialmente segfault o dati corrotti (piuttosto che che generano eccezioni come in Python).

Le regole attuali sono un po 'più complicate ma il messaggio principale è chiaro: non utilizzare oggetti digitati senza sapere che non sono impostati su Nessuna .

http://docs.cython.org/src/userguide/numpy_tutorial.html

+2

Penso che la ragione per cui è stata posta la domanda sia che in questo caso 'boundscheck (True)' è più veloce, il che è contro-intuitivo. – DavidW

+0

Ohh !!!!! Buon punto! È così contro intuitivo che ho persino letto la domanda sbagliata! Ho pensato che la domanda chiedesse il contrario. –

Problemi correlati