Benchmarking (python vs. c++ usando BLAS) e (numpy)

| | | | | | | | | | | | | | | | | | | | | | | | | | |

Vorrei scrivere un programma che faccia ampio uso delle funzionalità di algebra lineare BLAS e LAPACK. Poiché le prestazioni sono un problema, ho fatto un po' di benchmarking e vorrei sapere se l'approccio che ho adottato è legittimo.

Ho, per così dire, tre concorrenti e voglio testare le loro prestazioni con una semplice matrice-matrice moltiplicazione. I concorrenti sono:

  1. Numpy, che utilizza solo la funzionalità di dot.
  2. Python, che chiama le funzionalità BLAS tramite un oggetto condiviso.
  3. C++, chiamando le funzionalità BLAS tramite un oggetto condiviso.

Scenario

Ho implementato una moltiplicazione matrice-matrice per diverse dimensioni io. i va da 5 a 500 con un incremento di 5 e le matrici m1 e m2 sono così impostate:

m1 = numpy.random.rand(i,i).astype(numpy.float32) m2 = numpy.random.rand(i,i).astype(numpy.float32) 

1. Numpy

Il codice utilizzato è simile al seguente:

tNumpy = timeit.Timer("numpy.dot(m1, m2)", "import numpy; from __main__ import m1 , m2") rNumpy.append((i, tNumpy.repeat(20, 1))) 

2. Python, chiamando BLAS tramite un oggetto condiviso

Con la funzione

_blaslib = ctypes.cdll.LoadLibrary("libblas.so") def Mul(m1, m2, i , r): no_trans = c_char("n") n = c_int(i) uno = c_float(1.0) zero = c_float(0.0) _blaslib.sgemm_(byref(no_trans), byref(no_trans), byref(n), byref (n), byref(n), byref(one), m1.ctypes.data_as(ctypes.c_void_p), byref(n), m2.ctypes.data_as(ctypes.c_void_p), byref(n), byref(zero) , r.ctypes.data_as(ctypes.c_void_p), byref(n)) 

il codice del test è simile al seguente:

r = numpy.zeros ((i,i), numpy.float32) tBlas = timeit.Timer("Mul(m1, m2, i, r)", "import numpy; from __main__ import i, m1, m2, r, Mul") rBlas. append((i, tBlas.repeat(20, 1))) 

3. c++, chiamando BLAS tramite un oggetto condiviso

Ora il codice c++ è naturalmente un po' più lungo quindi riduco le informazioni al minimo.
Carico la funzione con

void* handle = dlopen("libblas.so", RTLD_LAZY); void* Func = dlsym(handle, "sgemm_"); 

Misuro il tempo con gettimeofday in questo modo:

gettimeofday(&start, NULL); f(&no_trans, &no_trans, &dim, &dim, &dim, &one, A, &dim, B, &dim, &zero, Return, &dim); gettimeofday(&end, NULL); dTimes[j] = CalcTime(inizio, fine); 

dove j è un ciclo in esecuzione 20 volte. Calcolo il tempo trascorso con

double CalcTime(inizio timeval, fine timeval) { double factor = 1000000; ritorno (((doppio)end.tv_sec) * fattore + ((doppio)end.tv_usec) - (((doppio)inizio.tv_sec) * fattore + ((doppio)inizio.tv_usec))) / fattore; } 

Risultati

Il risultato è mostrato nel grafico seguente:

inserisci qui la descrizione dell'immagine

Domande

  1. Pensi che il mio approccio sia giusto o ci sono delle spese generali inutili che posso evitare?
  2. Ti aspetteresti che il risultato mostri una tale discrepanza tra l'approccio c++ e python? Entrambi usano oggetti condivisi per i loro calcoli.
  3. Dato che preferirei usare python per il mio programma, cosa potrei fare per aumentare le prestazioni quando chiamo le routine BLAS o LAPACK?

Download

Il benchmark completo può essere scaricato qui. (JF Sebastian ha reso possibile quel collegamento^^)