]> git.somenet.org - pub/jan/parprog.git/blob - scan/scan.c
mpiscan_grammar
[pub/jan/parprog.git] / scan / scan.c
1 /*
2  * Inclusive scan
3  */
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <ctype.h>
8 #include <getopt.h>
9 #include <unistd.h>
10 #include <sys/stat.h>
11 #include <mpi.h>
12 #include "scan.h"
13
14 // tag for control messages
15 #define KEY 1337 
16
17 /* This one's binary name. */
18 char* binname = "unset";
19
20 void usage () {
21         fprintf(stderr, "\nUsage: mpirun -node 1-32 -nnp 1 %s [-f <string>] [-n <number>]\n", binname);
22         fprintf(stderr, "\t -f: set the filename of the randfile. (defaults to \"numlist.bin\")\n");
23         fprintf(stderr, "\t -n: set the number count to read from randfile. (defaults to 0 = read all)\n");
24 #ifdef DEBUG
25         fprintf(stderr, "***** BIG RED WARNING: COMPILED WITH XDEBUG - YOU ARE ON YOUR OWN! *****\n");
26 #endif
27 #ifdef DEBUG
28         fprintf(stderr, "*** COMPILED WITH DEBUG - size is limited to 64 ***\n");
29         fprintf(stderr, "Compile with XDEBUG or without DEBUG to get past this limit.\n");
30         fprintf(stderr, "You might want to compile this without the DEBUG flag to get less noice.\n");
31 #endif
32         fprintf(stderr, "\nErrorcodes:\n");
33         fprintf(stderr, "\t0: Everything went OK.\n\t1: General error.\n\t2: Getopt/wrong usage error.\n\t3: Inputfile error.\n\t4: Memory error.\n\n");
34 }
35
36
37 void array_contents(unsigned long arr[], unsigned long size){
38         fprintf(stdout, "[%li", arr[0]);
39         for(unsigned long i = 1; i < size; i++){
40                 fprintf(stdout, ", %li", arr[i]);
41         }
42         fprintf(stdout, "]\n");
43 }
44
45
46 int main(int argc, char *argv[]){
47         int tmp;
48         int tmp2;
49         FILE *file = NULL;
50         MPI_Request request;
51         MPI_Status status;
52         unsigned long blocksize;
53         unsigned long *databuf;
54
55         /* timings. */
56         double startTime = 0;
57         double prepTime = 0;
58         double algoTime = 0;
59         double postpTime = 0;
60         double endTime = 0;
61
62         /* options */
63         unsigned long size = 0;
64         char *filename = "numlist.bin";
65
66         /* store out name for usage(); */
67         binname = argv[0];
68
69         /* node info stuff*/
70         int rank, nodes;
71         char name[MPI_MAX_PROCESSOR_NAME];
72         MPI_Init(&argc,&argv);
73         MPI_Comm_size(MPI_COMM_WORLD,&nodes);
74         MPI_Comm_rank(MPI_COMM_WORLD,&rank);
75         MPI_Get_processor_name(name,&tmp);
76 #ifdef DEBUG
77         fprintf(stderr, "***** BIG RED WARNING: COMPILED WITH XDEBUG - YOU ARE ON YOUR OWN! *****\n");
78 #endif
79 #ifdef DEBUG
80         fprintf(stderr, "*** COMPILED WITH DEBUG - size is limited to 64 ***\n");
81         fprintf(stderr, "Compile with XDEBUG or without DEBUG to get past this limit.\n");
82         fprintf(stdout, "[%d/%d:%s] openMPI initialised.\n",rank,nodes,name);
83 #endif
84
85         /* getopt stuff */
86         int c;
87         opterr = 0;
88         while ((c = getopt (argc, argv, "n:f:")) != -1) switch (c){
89                 case 'n':
90                         size = strtoul (optarg,NULL,0);
91                         break;
92                 case 'f':
93                         filename = optarg;
94                         break;
95                 case '?':
96                         if (optopt == 'f' || optopt == 'n')
97                                 fprintf (stderr, "Option -%c requires an argument.\n", optopt);
98                         else if (isprint (optopt))
99                                 fprintf (stderr, "Unknown option `-%c'.\n", optopt);
100                         else
101                                 fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt);
102                         if (rank == 0)usage();
103                         MPI_Finalize();
104                         exit(2);
105                         
106                 default:
107                         if (rank == 0)usage();
108                         MPI_Finalize();
109                         exit(2);
110         }
111
112         /* sanize size, calculate blocksize, init databuf. */
113         if ((file = fopen(filename, "r"))) {
114                 fclose(file);
115                 file = NULL;
116                 struct stat st;
117                 stat(filename, &st);
118
119                 if (size == 0){
120                         size = st.st_size;
121                 }
122 #ifdef DEBUG
123 #ifndef XDEBUG
124                 if (size > 64) size = 64;
125 #endif
126 #endif
127                 if (size < 0 || size > st.st_size){
128                         if(rank == 0){
129                                 fprintf (stderr, "[%d/%d:%s] Cannot read %li numbers from \"%s\" - only has %li bytes.\n",rank,nodes,name,size,filename,st.st_size);
130                                 usage();
131                         }
132                         MPI_Finalize();
133                         exit(3);
134                 }
135         }else{
136                 if(rank == 0){
137                         fprintf (stderr, "[%d/%d:%s] File %s does not exist.\n",rank,nodes,name,filename);
138                         usage();
139                 }
140                 MPI_Finalize();
141                 exit(3);
142         }
143
144         databuf = malloc(size * sizeof(unsigned long));
145         if(databuf == NULL) {
146                 fprintf(stdout, "[%d/%d:%s] malloc for databuf failed.\n",rank,nodes,name);
147                 MPI_Finalize();
148                 exit(4);
149         }
150
151         blocksize = size/nodes;
152         if(blocksize*nodes < size){
153                 blocksize++;
154                 if(rank == 0)
155                         fprintf(stderr, "[%d/%d:%s] perfect split impossible: n:%d, s:%li -> bs:%li (off: %li)\n",rank,nodes,name,nodes,size,blocksize,(nodes*blocksize)-size);
156         }
157
158         if(rank == 0){
159                 fprintf(stdout, "[%d/%d:%s] INFO s: %li n: %d bs: %li n*b: %li n*(b+1): %li\n",rank,nodes,name,size,nodes,blocksize,nodes*blocksize, nodes*(blocksize+1));
160
161                 /* read file. */
162                 if ((file = fopen(filename, "r"))) {
163                         for (unsigned long i = 0; i < size; i++) {
164                                 databuf[i] = fgetc(file);
165                         }
166                         fclose(file);
167                 }else{
168                         fprintf (stderr, "[%d/%d:%s] File %s could not be read.\n",rank,nodes,name,filename);
169                         usage();
170                         MPI_Finalize();
171                         exit(3);
172                 }
173 #ifdef DEBUG
174                 fprintf(stdout, "[%d/%d:%s] file read - distributing work.\n",rank,nodes,name);
175 #endif
176                 startTime = MPI_Wtime();
177                 MPI_Isend(databuf, size-1, MPI_LONG, 0, KEY, MPI_COMM_WORLD, &request);
178         }
179
180         /* receive work and propagate to next node, if not last node. */
181         if (startTime == 0) startTime = MPI_Wtime();
182         tmp = rank -1;
183         if(tmp < 0) tmp = 0;
184         MPI_Recv(databuf, size, MPI_LONG, tmp, KEY, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
185         if(rank +1 < nodes) MPI_Send(databuf, size, MPI_LONG, rank+1, KEY, MPI_COMM_WORLD);
186         prepTime = MPI_Wtime();
187
188         /* do actual work here. */
189         for(unsigned long i = (rank*blocksize+1); i < ((rank+1)*blocksize) && i < size; i++){
190                 databuf[i] = databuf[(i-1)] + databuf[i];
191         }
192         algoTime = MPI_Wtime();
193 #ifdef DEBUG
194         fprintf(stdout, "[%d/%d:%s] proc array ",rank,nodes,name);
195         array_contents(databuf, size);
196 #endif
197
198
199         /* receive sums */
200         if(rank != 0){
201                 MPI_Recv(databuf, rank*blocksize, MPI_LONG, tmp, KEY, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
202 #ifdef DEBUG
203                 fprintf(stdout, "[%d/%d:%s] rcv array ",rank,nodes,name);
204                 array_contents(databuf, size);
205 #endif
206                 for(unsigned long i = rank*blocksize; i < ((rank+1)*blocksize) && i < size; i++){
207                         databuf[i] += databuf[((rank*blocksize)-1)];
208                 }
209 #ifdef DEBUG
210                 fprintf(stdout, "[%d/%d:%s] added array ",rank,nodes,name);
211                 array_contents(databuf, size);
212 #endif
213         }
214         postpTime = MPI_Wtime();
215
216         tmp = rank +1;
217         if(tmp >= nodes) tmp = 0;
218         tmp2 = ((rank+1)*blocksize);
219         if(tmp2 > size) tmp2 = size;
220         MPI_Isend(databuf, tmp2, MPI_LONG, tmp, KEY, MPI_COMM_WORLD,&request);
221
222         /* receive result by root */
223         if(rank == 0){
224                 MPI_Recv(databuf, size, MPI_LONG, nodes-1, KEY, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
225                 endTime = MPI_Wtime();
226                 fprintf(stdout, "[%d/%d:%s] result: %li\n",rank,nodes,name,databuf[size-1]);
227                 fprintf(stdout, "[%d/%d:%s] timings: prep:%f algo:%f postp:%f end:%f\n",rank,nodes,name,prepTime-startTime,algoTime-startTime,postpTime-startTime,endTime-startTime);
228 #ifdef DEBUG
229                 fprintf(stdout, "[%d/%d:%s] res array ",rank,nodes,name);
230                 array_contents(databuf, size);
231 #endif
232         }
233
234 #ifdef DEBUG
235         if(endTime == 0) endTime = MPI_Wtime();
236         fprintf(stdout, "[%d/%d:%s] timings: prep:%f algo:%f postp:%f end:%f\n",rank,nodes,name,prepTime-startTime,algoTime-startTime,postpTime-startTime,endTime-startTime);
237 #endif
238         MPI_Wait(&request, &status);
239         MPI_Finalize();
240         return 0;
241 }
242