-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathq3.cpp
More file actions
141 lines (115 loc) · 3.35 KB
/
q3.cpp
File metadata and controls
141 lines (115 loc) · 3.35 KB
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#include <iostream>
#include <random>
#include <vector>
#include <cmath>
#include <mpi.h>
#define R_MIN 0
#define R_MAX 1000
#define N 1000000000
int num_threads = 1;
// Generates sample space and returns mean
std::pair<std::vector<int>, int64_t> generate_sample_space(int rank)
{
int n_per_proc = N / num_threads;
if (rank == num_threads-1) n_per_proc += N - (n_per_proc*(num_threads-1));
std::random_device rd;
std::mt19937 mt(rd());
std::uniform_int_distribution<int> dist(R_MIN, R_MAX);
// Generate sample space.
std::vector<int> sample_space;
for (int i = 0; i < n_per_proc; ++i)
{
auto r = dist(mt);
sample_space.push_back(r);
}
auto mean = std::accumulate(sample_space.begin(), sample_space.end(), 0LL) / sample_space.size();
return {sample_space, mean};
}
int64_t find_sum_squares(std::pair<std::vector<int>, int64_t> sample_space_pair)
{
int64_t sum_squares = 0;
auto sample_space = sample_space_pair.first;
auto mean = sample_space_pair.second;
auto n_per_proc = sample_space.size();
for (int i = 0; i < n_per_proc; ++i)
{
sum_squares += (sample_space[i] - mean)*(sample_space[i] - mean);
}
return sum_squares;
}
void do_work(int rank)
{
auto sample_space_pair = generate_sample_space(rank);
auto sample_space = sample_space_pair.first;
auto mean = sample_space_pair.second;
// send mean back to server so it can be incorporated with other nodes' results.
MPI_Send(&mean, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
// receive new mean from server.
MPI_Recv(&mean, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
auto sum_squares = find_sum_squares({sample_space, mean});
MPI_Send(&sum_squares, 1, MPI_LONG_LONG, 0, 0, MPI_COMM_WORLD);
}
double myclock() {
static time_t t_start = 0; // Save and subtract off each time
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
if( t_start == 0 ) t_start = ts.tv_sec;
return (double) (ts.tv_sec - t_start) + ts.tv_nsec * 1.0e-9;
}
int main(int argc, char** argv)
{
int rc;
int rank;
double tstart, ttotal;
if ((rc = MPI_Init(&argc, &argv)) != MPI_SUCCESS)
{
std::cout << "error: cannot start mpi" << std::endl;
MPI_Abort(MPI_COMM_WORLD, rc);
}
MPI_Comm_size(MPI_COMM_WORLD,&num_threads);
MPI_Comm_rank(MPI_COMM_WORLD,&rank);
if (rank == 0)
{
tstart = myclock();
tstart = myclock();
int64_t sum_squares = 0;
if (num_threads > 1)
{
std::vector<int> means;
for (int i = 1; i < num_threads; ++i)
{
int mean;
MPI_Recv(&mean, 1, MPI_INT, i, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
means.push_back(mean);
}
auto new_mean = std::accumulate(means.begin(), means.end(), 0LL) / means.size();
for (int i = 1; i < num_threads; ++i)
{
MPI_Send(&new_mean, 1, MPI_INT, i, 0, MPI_COMM_WORLD);
}
for (int i = 1; i < num_threads; ++i)
{
int64_t result;
MPI_Recv(&result, 1, MPI_LONG_LONG, i, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
sum_squares += result;
}
}
else
{
// single threaded...
sum_squares = find_sum_squares(generate_sample_space(rank));
}
// Compute standard deviation.
auto sd = std::sqrt(sum_squares / (N-1));
ttotal = myclock() - tstart;
std::cout << "Standard deviation: " << sd << std::endl;
std::cout << "Time: " << ttotal << " seconds" << std::endl;
std::cout << "Cores: " << num_threads << std::endl;
}
else
{
do_work(rank);
}
MPI_Finalize();
return 0;
}