1+ #include < boost/sort/spreadsort/float_sort.hpp>
2+ #include < cstdio>
3+ #include < cstdlib>
4+ #include < mpi.h>
5+
6+ /* merge to array "a" */
7+ int merge_front (float *a, int a_num, float *b, int b_num, float *t)
8+ {
9+ int t_num = 0 , check = 0 ;
10+ float *t_i = t;
11+ while (a_num--)
12+ {
13+ if (!t_num)
14+ {
15+ if (b_num && *a > *b)
16+ {
17+ check = 1 ;
18+ *t_i++ = *a;
19+ *a = *b++;
20+ ++t_num;
21+ --b_num;
22+ }
23+ }
24+ else
25+ {
26+ if (b_num && *b < *t)
27+ {
28+ if (*a > *b)
29+ {
30+ check = 1 ;
31+ *t_i++ = *a;
32+ *a = *b++;
33+ ++t_num;
34+ --b_num;
35+ }
36+ }
37+ else
38+ {
39+ if (*a > *t)
40+ {
41+ check = 1 ;
42+ *t_i++ = *a;
43+ *a = *t++;
44+ }
45+ }
46+ }
47+ ++a;
48+ }
49+ return check;
50+ }
51+
52+ /* merge to array "b" */
53+ int merge_rear (float *a, int a_num, float *b, int b_num, float *t)
54+ {
55+ int t_num = 0 , check = 0 ;
56+ float *t_i = t;
57+ a = a + a_num - 1 ;
58+ b = b + b_num - 1 ;
59+ while (b_num--)
60+ {
61+ if (!t_num)
62+ {
63+ if (a_num && *b < *a)
64+ {
65+ check = 1 ;
66+ *t_i++ = *b;
67+ *b = *a--;
68+ ++t_num;
69+ --a_num;
70+ }
71+ }
72+ else
73+ {
74+ if (a_num && *a > *t)
75+ {
76+ if (*b < *a)
77+ {
78+ check = 1 ;
79+ *t_i++ = *b;
80+ *b = *a--;
81+ ++t_num;
82+ --a_num;
83+ }
84+ }
85+ else
86+ {
87+ if (*b < *t)
88+ {
89+ check = 1 ;
90+ *t_i++ = *b;
91+ *b = *t++;
92+ }
93+ }
94+ }
95+ --b;
96+ }
97+ return check;
98+ }
99+
100+ int main (int argc, char **argv)
101+ {
102+ int rank, size, global_data_n, local_data_n, remain_data_n, trans_next_data_n, trans_before_data_n, local_data_start, last_process_id;
103+ MPI_Group WORLD_GROUP, USED_GROUP;
104+ MPI_Comm USED_COMM = MPI_COMM_WORLD;
105+ MPI_File inputFile, outputFile;
106+
107+ MPI_Init (&argc, &argv);
108+ MPI_Comm_rank (MPI_COMM_WORLD, &rank);
109+ MPI_Comm_size (MPI_COMM_WORLD, &size);
110+
111+ /* handle arbitrary number of processes */
112+ global_data_n = atoi (argv[1 ]);
113+ if (global_data_n < size)
114+ {
115+ MPI_Comm_group (MPI_COMM_WORLD, &WORLD_GROUP);
116+ int range[1 ][3 ] = {{0 , global_data_n - 1 , 1 }};
117+ MPI_Group_range_incl (WORLD_GROUP, 1 , range, &USED_GROUP);
118+ MPI_Comm_create (MPI_COMM_WORLD, USED_GROUP, &USED_COMM);
119+ // if task isn't in "USED_GROUP", its "USED_COMM" is "MPI_COMM_NULL".
120+ if (USED_COMM == MPI_COMM_NULL)
121+ {
122+ MPI_Finalize ();
123+ return 0 ;
124+ }
125+ size = global_data_n;
126+ }
127+ last_process_id = size - 1 ;
128+
129+ /* distribute input data to different process */
130+ local_data_n = global_data_n / size;
131+ remain_data_n = global_data_n % size;
132+ float *recv = new float [local_data_n + 1 ]; // use to receive
133+ float *temp = new float [local_data_n + 1 ]; // use to merge
134+ if (rank < remain_data_n)
135+ {
136+ ++local_data_n;
137+ local_data_start = rank * local_data_n;
138+ }
139+ else
140+ {
141+ local_data_start = rank * local_data_n + remain_data_n;
142+ }
143+ float *data = new float [local_data_n];
144+
145+ /* calculate how many data change in each phase */
146+ int div = 2 ;
147+ if (rank + 1 == remain_data_n)
148+ trans_next_data_n = (local_data_n - 1 ) / div;
149+ else
150+ trans_next_data_n = local_data_n / div;
151+ trans_before_data_n = local_data_n / div;
152+ if (!trans_next_data_n)
153+ trans_next_data_n = 1 ;
154+ if (!trans_before_data_n)
155+ trans_before_data_n = 1 ;
156+ float *phase_process_data_offset = data + local_data_n - trans_next_data_n;
157+
158+ /* read data from inputfile */
159+ MPI_File_open (USED_COMM, argv[2 ], MPI_MODE_RDONLY, MPI_INFO_NULL, &inputFile);
160+ MPI_File_read_at (inputFile, sizeof (float ) * local_data_start, data, local_data_n, MPI_FLOAT, MPI_STATUS_IGNORE);
161+ MPI_File_close (&inputFile);
162+
163+ /* execute odd-even sort */
164+ boost::sort::spreadsort::float_sort (data, data + local_data_n);
165+ int even_check = 0 , odd_check = 0 , check = 0 , terminate = 1 ;
166+ while (terminate)
167+ {
168+ /* even phase */
169+ // if rank is even and isn't last process, it needs to send and receive data with (rank + 1).
170+ if (!(rank & 1 ) && rank != last_process_id)
171+ {
172+ MPI_Sendrecv (phase_process_data_offset, trans_next_data_n, MPI_FLOAT, rank + 1 , 0 ,
173+ recv, trans_next_data_n, MPI_FLOAT, rank + 1 , 0 , USED_COMM, MPI_STATUS_IGNORE);
174+ even_check = merge_front (data, local_data_n, recv, trans_next_data_n, temp);
175+ }
176+ // if rank is odd, it needs to send and receive data with (rank - 1).
177+ else if (rank & 1 )
178+ {
179+ MPI_Sendrecv (data, trans_before_data_n, MPI_FLOAT, rank - 1 , 0 ,
180+ recv, trans_before_data_n, MPI_FLOAT, rank - 1 , 0 , USED_COMM, MPI_STATUS_IGNORE);
181+ even_check = merge_rear (recv, trans_before_data_n, data, local_data_n, temp);
182+ }
183+
184+ /* odd phase */
185+ // if rank is odd and isn't last process, it needs to send and receive data with (rank + 1).
186+ if ((rank & 1 ) && rank != last_process_id)
187+ {
188+ MPI_Sendrecv (phase_process_data_offset, trans_next_data_n, MPI_FLOAT, rank + 1 , 0 ,
189+ recv, trans_next_data_n, MPI_FLOAT, rank + 1 , 0 , USED_COMM, MPI_STATUS_IGNORE);
190+ odd_check = merge_front (data, local_data_n, recv, trans_next_data_n, temp);
191+ }
192+ // if rank is even and isn't first process, it needs to send and receive data with (rank - 1).
193+ else if (!(rank & 1 ) && rank != 0 )
194+ {
195+ MPI_Sendrecv (data, trans_before_data_n, MPI_FLOAT, rank - 1 , 0 ,
196+ recv, trans_before_data_n, MPI_FLOAT, rank - 1 , 0 , USED_COMM, MPI_STATUS_IGNORE);
197+ odd_check = merge_rear (recv, trans_before_data_n, data, local_data_n, temp);
198+ }
199+ check = odd_check | even_check;
200+ MPI_Allreduce (&check, &terminate, 1 , MPI_INT, MPI_SUM, USED_COMM);
201+ }
202+
203+ /* write data to outputfile */
204+ MPI_File_open (USED_COMM, argv[3 ], MPI_MODE_CREATE | MPI_MODE_WRONLY, MPI_INFO_NULL, &outputFile);
205+ MPI_File_write_at (outputFile, sizeof (float ) * local_data_start, data, local_data_n, MPI_FLOAT, MPI_STATUS_IGNORE);
206+ MPI_File_close (&outputFile);
207+
208+ delete data, recv;
209+ MPI_Finalize ();
210+ return 0 ;
211+ }
0 commit comments