/
matrix_multiplication_parallel.cpp
126 lines (100 loc) · 3.05 KB
/
matrix_multiplication_parallel.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/* matrix_multiplication.cpp *
* Parallel matrix multiplication *
* By: Gareth Ferneyhough *
* University of Nevada, Reno */
#define BOOST_CHRONO_HEADER_ONLY
#include <algorithm>
#include <string>
#include <fstream>
#include <boost/chrono.hpp>
#include <boost/mpi.hpp>
#include <boost/mpi/collectives.hpp>
#include <boost/serialization/serialization.hpp>
#include "matrix.h"
namespace mpi = boost::mpi;
using std::string;
using std::cout;
using std::endl;
void runMaster(mpi::communicator, int size, int grid_dimension);
void runSlave(mpi::communicator);
MatrixCrossSection getCrossSection(const Matrix& mat, int row_begin, int col_begin, int num_cols_and_rows);
int main(int argc, char* argv[])
{
assert(argc == 2);
int size = atoi(argv[1]);
mpi::environment env(argc, argv);
mpi::communicator world;
const int my_rank = world.rank();
int grid_dimension = sqrt(world.size() -1);
if (grid_dimension != 0)
assert( size % grid_dimension == 0);
// Main Loop
if (my_rank == 0) runMaster(world, size, grid_dimension);
else runSlave(world);
return 0;
}
void runMaster(mpi::communicator world, int size, int grid_dimension)
{
// Start timer and go.
boost::chrono::system_clock::time_point start = boost::chrono::system_clock::now();
// Send
Matrix A(Size(size, size));
Matrix result(Size(size, size));
for(int row = 0; row < A.size.rows; ++row){
for(int col = 0; col < A.size.cols; ++col){
A.data[row][col] = (row % 11) + (col % 11);
}
}
//cout << A << endl;
//cout << "\nProduct:\n" << A*A << endl;
// Do sequential
if (grid_dimension == 0)
A.square(result);
// Else parallel
else{
// Split matrix up and send to slaves
int slave_id = 1;
int sub_matrix_sizes = size / grid_dimension;
for(int i = 0; i < size; i += sub_matrix_sizes){
for(int j = 0; j < size; j += sub_matrix_sizes){
MatrixCrossSection cs = getCrossSection( A, i, j, sub_matrix_sizes);
world.send(slave_id, 0, cs);
slave_id ++;
}
}
// Recieve
std::vector<Matrix> saved;
int num_slaves = world.size() -1;
for(int i = 1; i <= num_slaves; ++i){
Matrix r;
world.recv(i, 0, r);
result.insertSubMatrix(r);
}
}
// Done
boost::chrono::duration<double> sec = boost::chrono::system_clock::now() - start;
cout << sec.count() << endl;
// Print Result
//cout << "\nResult:\n" << result << endl;
//assert ( result == A*A);
}
void runSlave(mpi::communicator world)
{
// Recieve
MatrixCrossSection cs;
world.recv(0, 0, cs);
Matrix subMatrix(Size(cs.row_data.size(), cs.row_data.size()));
cs.calculateVectorProduct(subMatrix);
world.send(0, 0, subMatrix);
}
MatrixCrossSection getCrossSection(const Matrix& mat, int row_begin, int col_begin, int num_cols_and_rows)
{
MatrixCrossSection cs;
cs.row_id = row_begin;
cs.col_id = col_begin;
for(int i = 0; i < num_cols_and_rows; ++i){
cs.row_data.push_back( mat.getRow(row_begin + i) );
cs.col_data.push_back( mat.getCol(col_begin + i) );
}
return cs;
}