2012-03-27 9 views
5

Scrivo un'app di elaborazione delle immagini che deve eseguire più operazioni e deve eseguirle il più possibile in tempo reale. L'acquisizione dei dati e il loro trattamento vengono eseguiti in processi separati (principalmente per motivi di prestazioni). I dati stessi sono piuttosto grandi (immagini a 16 bit in scala di grigi a 16 bit).Allineamento della memoria per FFT veloce in Python utilizzando arresti condivisi

Posso condividere matrici tra processi come descritto in questo post: How do I pass large numpy arrays between python subprocesses without saving to disk? (utilizzo lo script shmarray dal pacchetto numpy-shared). Posso eseguire Numpy FFT fornito su quei dati senza problemi, ma è piuttosto lento.

Chiamare FFTW sarebbe probabilmente molto più veloce, ma per trarne il massimo vantaggio, dovrei eseguire le mie operazioni su array allineati in memoria.

La domanda: esiste un modo per creare e condividere matrici simili a Numpy tra processi, che sono, allo stesso tempo, garantiti per l'allineamento della memoria?

+1

Cosa binding Python FFTW si usa? Questi collegamenti dovrebbero fornire un modo per allocare blocchi di memoria correttamente allineati. –

+0

Hai ragione, ma la parte difficile è che ho bisogno di condividere quegli array tra più processi. Sono abbastanza sicuro che quelle funzioni non creano array "condivisi". – bubla

risposta

6

Il trucco standard più semplice per ottenere una memoria allineata correttamente consiste nell'allocare un po 'più del necessario e saltare i primi pochi byte se l'allineamento è sbagliato. Se ricordo male, gli array NumPy saranno sempre allineati a 8 byte e FFTW richiede un aligment a 16 byte per ottenere il massimo. Quindi si dovrebbero semplicemente allocare 8 byte più del necessario e saltare i primi 8 byte se necessario.

Modifica: è piuttosto semplice da implementare. Il puntatore ai dati è disponibile come numero intero nell'attributo ctypes.data di un array NumPy. L'uso del blocco spostato può essere ottenuto tagliando, visualizzando come un tipo di dati diverso e rimodellando - tutti questi non copieranno i dati, ma piuttosto riutilizzeranno lo stesso buf.

Per assegnare un 16-byte allineato matrice 1000x1000 di numeri in virgola mobile a 64 bit, si potrebbe usare questo codice:

m = n = 1000 
dtype = numpy.dtype(numpy.float64) 
nbytes = m * n * dtype.itemsize 
buf = numpy.empty(nbytes + 16, dtype=numpy.uint8) 
start_index = -buf.ctypes.data % 16 
a = buf[start_index:start_index + nbytes].view(dtype).reshape(m, n) 

Ora, a è un array con le proprietà desiderate, come si può verificare dal controllando che a.ctypes.data % 16 sia effettivamente 0.

+0

Potresti fornire un esempio, per favore? Supponiamo, per esempio, di voler trattare array di numeri complessi 2D. – bubla

+0

Nota è necessario liberare/eliminare il puntatore originale. –

+0

Qui vedo due problemi: 1. Come scoprire quanti byte saltare? 2. Come eseguire il salto e ottenere una matrice rettangolare di dimensioni desiderate come uscita? 3. Pensi che contribuire a questo (forse abbastanza semplice) trucco per il modulo shmarray avrebbe senso? (https://bitbucket.org/cleemesser/numpy-sharedmem/raw/5ca092f8222a/shmarray.py)? – bubla

1

Generalizzando sulla risposta di Sven, questa funzione restituisce una copia allineata (se necessario) di qualsiasi array NumPy:

import numpy as np 
def aligned(a, alignment=16): 
    if (a.ctypes.data % alignment) == 0: 
     return a 

    extra = alignment/a.itemsize 
    buf = np.empty(a.size + extra, dtype=a.dtype) 
    ofs = (-buf.ctypes.data % alignment)/a.itemsize 
    aa = buf[ofs:ofs+a.size].reshape(a.shape) 
    np.copyto(aa, a) 
    assert (aa.ctypes.data % alignment) == 0 
    return aa 
Problemi correlati