Benchmarking (python vs c++ avec BLAS) et (numpy)

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

Je voudrais écrire un programme qui utilise largement les fonctionnalités d'algèbre linéaire de BLAS et LAPACK. Étant donné que la performance est un problème, j'ai fait quelques analyses comparatives et j'aimerais savoir si l'approche que j'ai adoptée est légitime.

J'ai, pour ainsi dire, trois candidats et je veux tester leurs performances avec une simple matrice-matrice multiplication. Les concurrents sont :

  1. Numpy, utilisant uniquement la fonctionnalité de point.
  2. Python, appelant les fonctionnalités de BLAS via un objet partagé.
  3. C++, appelant les fonctionnalités de BLAS via un objet partagé.

Scénario

J'ai implémenté une multiplication matrice-matrice pour différentes dimensions je. i va de 5 à 500 avec un incrément de 5 et les matrices m1 et m2 sont configurées comme ceci :

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

1. Numpy

Le code utilisé ressemble à ceci :

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

2. Python, appelant BLAS via un objet partagé

Avec la fonction

_blaslib = ctypes.cdll.LoadLibrary("libblas.so") def Mul(m1, m2, i , r): no_trans = c_char("n") n = c_int(i) un = c_float(1.0) zéro = 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)) 

le code de test ressemble à ceci :

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. ajouter((i, tBlas.repeat(20, 1))) 

3. c++, appelant BLAS via un objet partagé

Maintenant, le code c++ est naturellement un peu plus long donc je réduis les informations au minimum.
Je charge la fonction avec

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

Je mesure le temps avec gettimeofday comme ceci :

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(start, end); 

j est une boucle exécutée 20 fois. Je calcule le temps passé avec

double CalcTime(timeval start, timeval end) { double factor = 1000000; retour (((double)end.tv_sec) * facteur + ((double)end.tv_usec) - (((double)start.tv_sec) * facteur + ((double)start.tv_usec))) / facteur ; } 

Résultats

Le résultat est affiché dans le graphique ci-dessous :

enter image description here

Questions

  1. Pensez-vous que mon approche est juste, ou y a-t-il des frais généraux inutiles que je peux éviter ?
  2. Vous attendriez-vous à ce que le résultat montre un écart aussi énorme entre l'approche c++ et python ? Les deux utilisent des objets partagés pour leurs calculs.
  3. Puisque je préférerais utiliser python pour mon programme, que pourrais-je faire pour augmenter les performances lors de l'appel des routines BLAS ou LAPACK ?

Télécharger

Le benchmark complet peut être téléchargé ici. (JF Sebastian a rendu ce lien possible^^)