Как мне выполнить резьбовое разреженное матрично-векторное умножение с использованием MKL?

Мне нужно выполнить матричное векторное умножение, где матрица является сложной, симметричной и имеет четыре недиагональных ненулевых полосы. До сих пор я использовал редкую процедуру BLAS mkl_zdiasymv для выполнения умножения, и она отлично работает на одном ядре. Я хотел бы попробовать, если я могу получить повышение производительности с помощью многопоточности (например, openMP). Насколько я понял, некоторые (многие?) Из подпрограмм MKL являются многопоточными. Однако, если я использую
mkl_set_num_threads (4)
моя программа все еще работает в одном потоке

В качестве конкретного примера приведу небольшую тестовую программу, которую я компилирую (используя icc 14.01):

icc mkl_test_mp.cpp -mkl -std=c++0x -openmp

mkl_test_mp.cpp:

#include <complex>
#include <vector>
#include <iostream>
#include <chrono>

typedef std::complex<double> complex;
using std::vector;
using namespace std::chrono;

#define MKL_Complex16 std::complex<double>
#include "mkl.h"
int vector_dimension = 10000000;
int number_of_multiplications = 100;

vector<complex> initialize_matrix() {

complex value_main_diagonal          = complex(1, 2);
complex value_sub_and_super_diagonal = complex(3, 4);
complex value_far_off_diagonal       = complex(5, 6);

std::vector<complex> matrix;
matrix.resize(1 * vector_dimension, value_main_diagonal);
matrix.resize(2 * vector_dimension, value_sub_and_super_diagonal);
matrix.resize(3 * vector_dimension, value_far_off_diagonal);

return matrix;
}

vector<complex> perform_matrix_vector_calculation(vector<complex>& matrix, const vector<complex>& x) {

mkl_set_num_threads(4);

vector<complex> result(vector_dimension);

char uplo = 'L';   // since the matrix is symmetric we only need to declare one triangular part of the matrix (here the lower one)
int number_of_nonzero_diagonals = 3;
vector<int> matrix_diagonal_offsets = {0, -1, -int(sqrt(vector_dimension))};

complex *x_data = const_cast<complex* >(x.data()); // I do not like this, but mkl expects non const pointer (??)

mkl_zdiasymv (
&uplo,
&vector_dimension,
matrix.data(),
&vector_dimension,
matrix_diagonal_offsets.data(),
&number_of_nonzero_diagonals,
x_data,
result.data()
);
return result;
}

void print(vector<complex>& x) {
for(complex z : x)
std::cerr << z;
std::cerr << std::endl;
}

void run() {
vector<complex> matrix = initialize_matrix();
vector<complex> current_vector(vector_dimension, 1);

for(int i = 0; i < number_of_multiplications; ++i) {
current_vector = perform_matrix_vector_calculation(matrix, current_vector);
}
std::cerr << current_vector[0] << std::endl;
}

int main() {

auto start = steady_clock::now();

run();

auto end = steady_clock::now();
std::cerr << "runtime = " << duration<double, std::milli> (end - start).count() << " ms" << std::endl;
std::cerr << "runtime per multiplication = " << duration<double, std::milli> (end -     start).count()/number_of_multiplications << " ms" << std::endl;
}

Возможно ли даже распараллелить этот путь? Что я делаю неправильно ? Есть ли другие предложения по ускорению умножения?

2

Решение

Поскольку вы не показываете, как вы компилируете код, можете проверить, что вы ссылаетесь на многопоточные библиотеки Intel MKL и, например, Pthreads?

Например (это для более старой версии MKL):

THREADING_LIB="$(MKL_PATH)/libmkl_$(IFACE_THREADING_PART)_thread.$(EXT)"OMP_LIB = -L"$(CMPLR_PATH)" -liomp5

В вашем дистрибутиве MKL должен быть каталог примеров, например intel/composer_xe_2011_sp1.10.319/mkl/examples, Там вы можете проверить содержимое spblasc/makefile чтобы увидеть, как правильно связать многопоточные библиотеки для конкретной версии MKL.

Другим предложением, которое должно ускорить процесс, является добавление флагов оптимизации компилятора, например

OPT_FLAGS = -xHost -O3

позволять icc генерировать оптимизированный код для вашей архитектуры, чтобы ваша строка получилась:

icc mkl_test_mp.cpp -mkl -std=c++0x -openmp -xHost -O3

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]