Сравнительный анализ (python и c++ с использованием BLAS) и (numpy)

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

Я хотел бы написать программу, которая широко использует функции линейной алгебры BLAS и LAPACK. Поскольку производительность является проблемой, я провел сравнительный анализ и хотел бы знать, является ли выбранный мной подход законным.

У меня есть, так сказать, три участника, и я хочу проверить их производительность с помощью простой матрицы-матрицы. умножение. Участниками являются:

  1. Numpy, использующий только функциональные возможности dot.
  2. Python, вызывающий функции BLAS через общий объект.
  3. C++, вызов функций BLAS через общий объект.

Сценарий

Я реализовал матричное умножение для разных измерений я. i работает от 5 до 500 с шагом 5, а матрицы m1 и m2 настроены следующим образом:

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

1. Numpy

Используемый код выглядит следующим образом:

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

2. Python, вызов BLAS через общий объект

С помощью функции

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

тестовый код выглядит так:

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++, вызов BLAS через общий объект

Теперь код на C++, естественно, немного длиннее, поэтому я сокращаю информацию до минимума.
Я загружаю функцию с помощью

void* handle = dlopen("libblas.so", RTLD_LAZY); void* Func = dlsym(дескриптор, "sgemm_"); 

Я измеряю время с помощью gettimeofday следующим образом:

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(начало, конец); 

где j — цикл, выполняемый 20 раз. Я вычисляю время, прошедшее с помощью

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

Результаты

Результат показан на графике ниже:

введите здесь описание изображения

Вопросы

  1. Считаете ли вы мой подход справедливым, или есть какие-то ненужные накладные расходы, которые я могу избежать?
  2. Вы ожидали, что результат покажет такое огромное расхождение между подходами C++ и Python? Оба используют общие объекты для своих вычислений.
  3. Поскольку я предпочитаю использовать Python для своей программы, что я могу сделать, чтобы повысить производительность при вызове подпрограмм BLAS или LAPACK?

Загрузить

Полный тест можно загрузить здесь. (JF Sebastian сделал эту ссылку возможной^^)