2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




Начать новую тему Ответить на тему
 
 Умножение матрицы на вектор MPI
Сообщение19.04.2020, 10:16 


20/10/17
107
Здравствуйте, ниже приведена MPI программа, выполняющая умножение матрицы на вектор. Проблема в том, что на 1 ПЭ (процессорный элемент) она выполняется быстрее, чем на всех остальных. Почему так происходит понятия не имею. Запускаю в Windows 10 через Visual Studio 2017. Версия MPI 8.0.12438.

Результаты тестов:
1 ПЭ: time = 0.004967
2 ПЭ: time = 0.0048281
4 ПЭ: time = 0.0091244
8 ПЭ: time = 0.0116354

код: [ скачать ] [ спрятать ]
Используется синтаксис C++
#include <stdio.h>
#include <stdlib.h>
#include "mpi.h"
#include <iostream>
using namespace std;


int main(int argc, char** argv)
{
        // Умножение матрицы на вектор
        int rank, size;
        int i, j, n = 1024;
        MPI_Init(&argc, &argv);
        MPI_Comm_size(MPI_COMM_WORLD, &size);
        MPI_Comm_rank(MPI_COMM_WORLD, &rank);
        int n_partial = n / size;
        //cout << "n/size=" << n_partial << endl;
        double * a_partial = new double[n_partial*n];//блоки строк исходной матрицы на каждом процессе
        double * x =  new double[n]; //исходный вектор
        double * y_partial = new double[n_partial];//блоки результирующего вектора на каждом процессе
        double * y_total = new double[n];// вектор-результат
        double * a = new double[n*n];//исходная матрица
        if (rank == 0)
        {
                //FILE *f1 = fopen("matrix.txt", "w");
                //fprintf(f1, "Matrix\n");
                //матрицу удобнее рассматривать как одномерный массив но с индексами i*n+j
                for (i = 0; i < n; i++)
                {
                        for (j = 0; j < n; j++)
                        {
                                if (i == j)
                                        a[i*n + j] = 1;
                                else
                                        a[i*n + j] = 2;
                                //fprintf(f1, "%f\t", a[i*n + j]);
                        }
                        //fprintf(f1, "\n");
                }
                //fprintf(f1, "Vector\n");
                for (i = 0; i < n; i++)
                {
                        x[i] = i+1;
                        //fprintf(f1, "%f\t", x[i]);
                }
                //fclose(f1);
        }
        double t = MPI_Wtime();
        //рассылаем вектор x
        MPI_Bcast(x, n, MPI_DOUBLE, 0, MPI_COMM_WORLD);
        /*for (i = 0; i < n; i++)
                cout << x[i] << "\t";
        cout << endl;*/

        //разделяем матрицу на горизонтальные полосы
        //шириной n_partial и отправляем процессам
        MPI_Scatter(a, n_partial * n, MPI_DOUBLE, a_partial, n_partial * n, MPI_DOUBLE, 0, MPI_COMM_WORLD);
        /*for (i = 0; i < n_partial; i++)
        {
                for (j = 0; j < n; j++)
                        cout << a_partial[i*n + j] << "\t";
                cout << "\n";
        }*/

        for (i = 0; i < n_partial; i++)
        {
                y_partial[i] = 0.0;
                for (j = 0; j < n; j++)
                        y_partial[i] += a_partial[i*n + j] * x[j];
        }
        /*      for (i = 0; i < n_partial; i++)
                cout << y_partial[i] << "\t";
        cout << endl;*/

        //собираем результат в нулевом процессе
        MPI_Gather(y_partial, n_partial, MPI_DOUBLE, y_total, n_partial, MPI_DOUBLE, 0, MPI_COMM_WORLD);
        t = MPI_Wtime() - t;
        if (rank == 0)
        {
                //FILE *f2 = fopen("result.txt", "w");
                //for (i = 0; i < n; i++)
                        //fprintf(f2,"%10.5f\n", y_total[i]);
                //fclose(f2);
                cout << "time = " << t;
        }
        delete[] a_partial;
        delete[] a;
        delete[] x;
        delete[] y_partial;
        delete[] y_total;

        MPI_Finalize();
        return 0;
}
 

 Профиль  
                  
 
 Re: Умножение матрицы на вектор MPI
Сообщение19.04.2020, 10:42 
Заслуженный участник
Аватара пользователя


06/10/08
6422
У Вас вся матрица занимает 8МБ, подозреваю, что нет никакого смысла ее делить, больше потратится на накладные расходы. Попробуйте поменять размер матрицы, посмотрите, меняется ли результат.

 Профиль  
                  
 
 Re: Умножение матрицы на вектор MPI
Сообщение19.04.2020, 11:17 


20/10/17
107
Xaositect в сообщении #1455956 писал(а):
У Вас вся матрица занимает 8МБ, подозреваю, что нет никакого смысла ее делить, больше потратится на накладные расходы. Попробуйте поменять размер матрицы, посмотрите, меняется ли результат.

Изменение размера матрицы, не влияет на результат. С увеличением числа ПЭ время продолжает увеличиваться. Пробовал брать n=2048,4096,8192.

 Профиль  
                  
 
 Re: Умножение матрицы на вектор MPI
Сообщение19.04.2020, 11:40 
Заслуженный участник
Аватара пользователя


06/10/08
6422
Странно. У меня Ваша программа ускоряется (Linux x86-64 5.5.13-2, openmpi 4.0.3, Celeron N2840):
N=1:
time = 0.0265745
time = 0.0263963
time = 0.0268941
time = 0.0275035
N=2:
time = 0.0185283
time = 0.0180142
time = 0.0210538
time = 0.0179255
А вот при n=4096:
N=1:
time = 0.418527
time = 0.417751
time = 0.417479
time = 0.418688
N=2:
time = 0.277126
time = 0.277128
time = 0.277451
time = 0.277393

 Профиль  
                  
 
 Re: Умножение матрицы на вектор MPI
Сообщение19.04.2020, 11:55 


20/10/17
107
Xaositect в сообщении #1455964 писал(а):
Странно. У меня Ваша программа ускоряется (Linux x86-64 5.5.13-2, openmpi 4.0.3, Celeron N2840):
N=1:
time = 0.0265745
time = 0.0263963
time = 0.0268941
time = 0.0275035
N=2:
time = 0.0185283
time = 0.0180142
time = 0.0210538
time = 0.0179255
А вот при n=4096:
N=1:
time = 0.418527
time = 0.417751
time = 0.417479
time = 0.418688
N=2:
time = 0.277126
time = 0.277128
time = 0.277451
time = 0.277393

Вы запускаете на каждом ПЭ по 4 раза?
Почему тогда в Windows так?
Изображение

 Профиль  
                  
 
 Re: Умножение матрицы на вектор MPI
Сообщение19.04.2020, 11:59 
Заслуженный участник
Аватара пользователя


06/10/08
6422
Я запускаю четыре раза, чтобы проверить стабильность времени выполнения. N=1 это на одном ПЭ, N=2 на двух. На моем селероне только два ядра без HT, так что дальше в настоящее время проверить не могу.
Проверяйте, действительно ли у Вас запускаются несколько процессов когда Вы свою программу из Visual Studio запускаете.

 Профиль  
                  
 
 Re: Умножение матрицы на вектор MPI
Сообщение19.04.2020, 12:55 


20/10/17
107
Xaositect в сообщении #1455972 писал(а):
Я запускаю четыре раза, чтобы проверить стабильность времени выполнения. N=1 это на одном ПЭ, N=2 на двух. На моем селероне только два ядра без HT, так что дальше в настоящее время проверить не могу.
Проверяйте, действительно ли у Вас запускаются несколько процессов когда Вы свою программу из Visual Studio запускаете.

Как можно проверить, сколько процессов запускаются?

 Профиль  
                  
 
 Re: Умножение матрицы на вектор MPI
Сообщение21.04.2020, 22:03 
Экс-модератор
Аватара пользователя


23/12/05
12064
Я не работал с MPI, и сейчас лишь поверхностно пробежался, поэтому предположения могут быть ошибочны.

1) Я правильно понимаю, что в каждой полоске считается результат в свой массив y_partial, а затем копируется в результрующий y_total? Если это действительно так, то для таких простых операций, которые вы проводите (всего лишь умножение и сложение), вполне реально больше времени потерять на копирования, чем на само вычисление. Надо сделать так, чтобы результат сразу писался в нужное место.

2)
Цитата:
Используется синтаксис C++
y_partial[i] = 0.0;
for (j = 0; j < n; j++)
    y_partial[i] += a_partial[i*n + j] * x[j];

Это не очень хорошо. Может, конечно, компилятор и соптимизирует, но лучше ему помочь. Если у вас какие-то предубеждения против использования std::inner_product(), можете i*n+j заменить на какой-нибудь k, чтобы избавиться от лишней операции:

Цитата:
Используется синтаксис C++
size_t k = 0;
        for (i = 0; i < n_partial; i++)
        {
                y_partial[i] = 0.0;
                for (j = 0; j < n; j++)
               {
                        y_partial[i] += a_partial[k++] * x[j];
               }
        }

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 8 ] 

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group