FreeNOS
MpiPrime.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2020 Niek Linnenbank
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include <Log.h>
19#include <String.h>
20#include <SystemClock.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <errno.h>
25#include <mpi.h>
26#include <math.h>
27#include <unistd.h>
28#include "MpiPrime.h"
29
30MpiPrime::MpiPrime(int argc, char **argv)
31 : SievePrime(argc, argv)
32 , m_mpiInitResult(MPI_Init(&m_argc, &m_argv))
33 , m_id(0)
34{
35 parser().setDescription("Calculate prime numbers in parallel");
36}
37
39{
40 DEBUG("");
41}
42
44{
46 {
47 ERROR("failed to initialize MPI: result = " << m_mpiInitResult);
48 return IOError;
49 }
50
51 int result = MPI_Comm_rank(MPI_COMM_WORLD, &m_id);
52 if (result != MPI_SUCCESS)
53 {
54 ERROR("failed to lookup MPI rank: result = " << result);
55 return IOError;
56 }
57
58 result = MPI_Comm_size(MPI_COMM_WORLD, (int *) &m_cores);
59 if (result != MPI_SUCCESS)
60 {
61 ERROR("failed to lookup total number of cores: result = " << result);
62 return IOError;
63 }
64
65 return Success;
66}
67
69{
70 int n, k;
71 u8 *root_map, *map;
73 SystemClock t1, t2;
74
75 // Retrieve maximum number (n)
76 t1.now();
77 n = atoi(arguments().get("NUMBER"));
78
79 // Make sure n is divisible by the number of workers
80 if ((n % m_cores) != 0)
81 {
82 n += m_cores;
83 n -= (n % m_cores);
84 }
85
86 int n_root = sqrt(n);
87 m_numbersPerCore = (n - n_root) / m_cores;
88 m_numberStart = n_root + (m_id * m_numbersPerCore);
90
91 // Allocate memory for root map
92 if ((root_map = (u8 *) malloc(n_root * sizeof(u8))) == NULL)
93 {
94 ERROR("malloc failed: " << strerror(errno));
95 return IOError;
96 }
97
98 // Initialize root map. Clear all entries
99 for (int i = 0; i < n_root; i++)
100 root_map[i] = 1;
101
102 // Try to allocate memory for results
103 if ((map = (u8 *) malloc(m_numbersPerCore * sizeof(u8))) == NULL)
104 {
105 ERROR("malloc failed: " << strerror(errno));
106 return IOError;
107 }
108
109 // Initialize results map. Clear all entries
110 for (Size i = 0; i < m_numbersPerCore; i++)
111 map[i] = 1;
112
113 // We start with 2
114 k = 2;
115 t2.now();
116
117 if (m_id == 0)
118 {
119 printf("Setup: ");
120 t1.printDiff(t2);
121 }
122
123 // Search for primes until done
124 t1.now();
125 searchParallel(k, n, root_map, map);
126 t2.now();
127
128 printf("Search_parallel: ");
129 t1.printDiff(t2);
130 t1.now();
131
132 // Free resources
133 MPI_Finalize();
134 free(map);
135
136 if (m_id == 0)
137 {
138 t2.now();
139 printf("Finalize: ");
140 t1.printDiff(t2);
141 }
142
143 return Success;
144}
145
146MpiPrime::Result MpiPrime::searchParallel(int k, int n, u8 *rootMap, u8 *map)
147{
148 SystemClock t1, t2;
149 int sqrt_of_n = sqrt(n);
150
151 // Find all primes below sqrt(n) sequentially
152 t1.now();
153 searchSequential(sqrt_of_n, rootMap);
154
155 if (m_id == 0)
156 {
157 t2.now();
158 printf("sequential: ");
159 t1.printDiff(t2);
160
161 t1.now();
162 }
163
164 // Every worker calculates all primes k .. sqrt(n) sequentially
165 // and uses the result to mark it's part of the map, concurrently
166 // Note that no communication is needed
167 while (k < sqrt_of_n)
168 {
169 // Prime number?
170 if (!rootMap[k])
171 {
172 k++;
173 continue;
174 }
175
176 // Mark multiples of k in my range
177 for (Size i = m_numberStart; i < m_numberEnd; i++)
178 {
179 // Do we need to unmark this number? (no prime)
180 if (!(i % k))
181 {
182 map[i - m_numberStart] = 0;
183 }
184 }
185
186 // Look for the next prime
187 k++;
188 }
189
190 if (m_id == 0)
191 {
192 t2.now();
193 printf("parallel: ");
194 t1.printDiff(t2);
195 }
196
197 // Collect results of all workers
198 t1.now();
199 collect(n, rootMap, map);
200
201 if (m_id == 0)
202 {
203 t2.now();
204 printf("collect: ");
205 t1.printDiff(t2);
206
207 t1.now();
208 }
209
210 return Success;
211}
212
214{
215 MPI_Status status;
216 const int sqrt_of_n = sqrt(n);
217
218 // Every worker sends it's results to the master
219 if (m_id != 0)
220 {
221 // Send mybuf to the master
223 }
224 // The master gathers the parts of the list from every worker
225 else
226 {
227 Size resultsWritten = 0;
228 reportResult(sqrt_of_n, rootMap, resultsWritten);
229 reportResult(m_numbersPerCore, map, resultsWritten, sqrt_of_n);
230
231 for (Size i = 1; i < m_cores; i++)
232 {
233 // Receive from worker
235
236 // Only the master reports the results.
237 reportResult(m_numbersPerCore, map, resultsWritten, (m_numbersPerCore * i) + sqrt_of_n);
238 }
239
240 write(1, "\r\n", 2);
241 }
242
243 // Cleanup
244 return Success;
245}
Result
Result codes.
Definition Application.h:54
const ArgumentContainer & arguments() const
Get program arguments.
ArgumentParser & parser()
Get program arguments parser.
void setDescription(const String &desc)
Set program description.
Size m_cores
Total number of cores.
Definition MpiPrime.h:99
Result searchParallel(int k, int n, u8 *rootMap, u8 *map)
Calculate prime numbers in parallel.
Definition MpiPrime.cpp:146
MpiPrime(int argc, char **argv)
Constructor.
Definition MpiPrime.cpp:30
Size m_numberEnd
Prime numbers array range end for this core.
Definition MpiPrime.h:108
int m_id
MPI core identifier (rank) of the current process.
Definition MpiPrime.h:96
virtual Result exec()
Execute the application.
Definition MpiPrime.cpp:68
int m_mpiInitResult
Result of MPI initialization.
Definition MpiPrime.h:93
virtual Result initialize()
Initialize the application.
Definition MpiPrime.cpp:43
virtual ~MpiPrime()
Destructor.
Definition MpiPrime.cpp:38
Size m_numberStart
Prime numbers array range start for this core.
Definition MpiPrime.h:105
Result collect(int n, u8 *rootMap, u8 *map)
Collect prime number results.
Definition MpiPrime.cpp:213
Size m_numbersPerCore
Prime numbers calculated per core.
Definition MpiPrime.h:102
virtual Result output(const char *string) const
Print text to output.
Compute prime numbers using the Sieve of Eratosthenes algorithm.
Definition SievePrime.h:32
Result reportResult(const int n, const u8 *map, Size &resultsWritten, const Size offsetNumber=0) const
Report the calculated results.
Result searchSequential(const int n, u8 *map) const
Perform sequential search for prime numbers.
Abstraction of strings.
Definition String.h:42
Provides an abstract interface to the system clock.
Definition SystemClock.h:35
Result now()
Get the current time.
void printDiff(const SystemClock &clock) const
Print difference between two clocks to stdout.
C int MPI_Send(const void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm)
Definition mpi.cpp:36
C int MPI_Comm_rank(MPI_Comm comm, int *rank)
Definition mpi.cpp:59
C int MPI_Comm_size(MPI_Comm comm, int *size)
Definition mpi.cpp:66
C int MPI_Recv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status)
Definition mpi.cpp:47
C int MPI_Init(int *argc, char ***argv)
Definition mpi.cpp:24
uint MPI_Status
Status holder.
Definition mpi.h:41
C int MPI_Finalize(void)
Definition mpi.cpp:30
@ MPI_UNSIGNED_CHAR
Definition mpi.h:52
@ MPI_COMM_WORLD
Definition mpi.h:64
@ MPI_SUCCESS
Definition mpi.h:73
C int atoi(const char *nptr)
Convert a string to an integer.
Definition atoi.cpp:21
C u32 sqrt(u32 number)
Compute the square root of a number.
Definition sqrt.cpp:20
C char * strerror(int errnum)
The strerror function maps the number in errnum to a message string.
Definition strerror.cpp:20
C int errno
The lvalue errno is used by many functions to return error values.
C int printf(const char *format,...)
Output a formatted string to standard output.
Definition printf.cpp:22
C void * malloc(size_t size)
A memory allocator.
Definition malloc.cpp:22
C ssize_t write(int fildes, const void *buf, size_t nbyte)
Write on a file.
Definition write.cpp:22
C void free(void *ptr)
Free allocated memory.
Definition free.cpp:22
#define NULL
NULL means zero.
Definition Macros.h:39
#define ERROR(msg)
Output an error message.
Definition Log.h:61
unsigned int Size
Any sane size indicator cannot go negative.
Definition Types.h:128
#define DEBUG(msg)
Output a debug message to standard output.
Definition Log.h:89
unsigned char u8
Unsigned 8-bit number.
Definition Types.h:59