Whamcloud - gitweb
LU-6142 tests: Fix style issues for write_disjoint.c
[fs/lustre-release.git] / lustre / tests / mpi / write_disjoint.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.gnu.org/licenses/gpl-2.0.html
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2012, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  * Lustre is a trademark of Sun Microsystems, Inc.
31  *
32  * lustre/tests/write_disjoint.c
33  *
34  * Each loop does 3 things:
35  *   - rank 0 truncates to 0
36  *   - all ranks agree on a random chunk size
37  *   - all ranks race to write their pattern to their chunk of the file
38  *   - rank 0 makes sure that the resulting file size is ranks * chunk size
39  *   - rank 0 makes sure that everyone's patterns went to the right place
40  *
41  * compile: mpicc -g -Wall -o write_disjoint write_disjoint.c
42  * run:     mpirun -np N -machlist <hostlist file> write_disjoint
43  *  or:     pdsh -w <N hosts> write_disjoint
44  *  or:     prun -n N [-N M] write_disjoint
45  */
46
47 #include <stdlib.h>
48 #include <stdio.h>
49 #include <sys/types.h>
50 #include <sys/stat.h>
51 #include <fcntl.h>
52 #include <string.h>
53 #include <errno.h>
54 #include <unistd.h>
55 #include <stdarg.h>
56 #include <time.h>
57 #include "mpi.h"
58
59 /* Chosen arbitrarily.  Actually running this large will take a long time.*/
60 #define CHUNK_MAX_SIZE (1024 * 1024 * 16)
61
62 void rprintf(int rank, int loop, const char *fmt, ...)
63 {
64         va_list ap;
65
66         printf("rank %d, loop %d: ", rank, loop);
67
68         va_start(ap, fmt);
69
70         vprintf(fmt, ap);
71
72         MPI_Abort(MPI_COMM_WORLD, -1); /* This will exit() according to man */
73 }
74
75 #define CHUNK_SIZE(n) chunk_size[(n) % 2]
76
77 int main(int argc, char *argv[])
78 {
79         int i, n, fd, c;
80         unsigned long chunk_size[2];
81         int rank, noProcessors, done;
82         int error;
83         off_t offset;
84         char **chunk_buf;
85         char *read_buf;
86         struct stat stat_buf;
87         ssize_t ret;
88         char *filename = "/mnt/lustre/write_disjoint";
89         int numloops = 1000;
90         int max_size = CHUNK_MAX_SIZE;
91         int random = 0;
92         unsigned int seed = 0;
93         int seed_provided = 0;
94
95         error = MPI_Init(&argc, &argv);
96         if (error != MPI_SUCCESS)
97                 rprintf(-1, -1, "MPI_Init failed: %d\n", error);
98         /* Parse command line options */
99         while ((c = getopt(argc, argv, "f:n:m:s:")) != EOF) {
100                 errno = 0;
101                 switch (c) {
102                 case 'f':
103                         filename = optarg;
104                         break;
105                 case 'n':
106                         numloops = strtoul(optarg, NULL, 0);
107                         break;
108                 case 'm':
109                         max_size = strtoul(optarg, NULL, 0);
110                         if (max_size > CHUNK_MAX_SIZE)
111                                 rprintf(-1, -1, "Chunk size larger than %d.\n",
112                                         CHUNK_MAX_SIZE);
113                         break;
114                 case 's':
115                         seed = strtoul(optarg, NULL, 0);
116                         seed_provided = 1;
117                         break;
118                 }
119         }
120
121         MPI_Comm_size(MPI_COMM_WORLD, &noProcessors);
122         MPI_Comm_rank(MPI_COMM_WORLD, &rank);
123
124         chunk_buf = malloc(noProcessors * sizeof(chunk_buf[0]));
125         for (i = 0; i < noProcessors; i++) {
126                 chunk_buf[i] = malloc(max_size);
127                 memset(chunk_buf[i], 'A' + i, max_size);
128         }
129         read_buf = malloc(noProcessors * max_size);
130
131         if (rank == 0) {
132                 fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
133                 if (fd < 0)
134                         rprintf(rank, -1, "open() returned %s\n",
135                                 strerror(errno));
136         }
137         MPI_Barrier(MPI_COMM_WORLD);
138
139         fd = open(filename, O_RDWR);
140         if (fd < 0)
141                 rprintf(rank, -1, "open() returned %s\n", strerror(errno));
142
143         if (rank == 0) {
144                 if (!seed_provided)
145                         seed = (unsigned int)time(NULL);
146                 printf("random seed: %d\n", seed);
147                 srand(seed);
148         }
149
150         for (n = 0; n < numloops; n++) {
151                 /* reset the environment */
152                 if (rank == 0) {
153                         ret = truncate(filename, 0);
154                         if (ret != 0)
155                                 rprintf(rank, n, "truncate() returned %s\n",
156                                         strerror(errno));
157
158                         random = rand();
159                 }
160                 MPI_Bcast(&random, 1, MPI_INT, 0, MPI_COMM_WORLD);
161                 CHUNK_SIZE(n) = random % max_size;
162
163                 if (n % 1000 == 0 && rank == 0)
164                         printf("loop %d: chunk_size %lu\n", n, CHUNK_SIZE(n));
165
166                 if (stat(filename, &stat_buf) < 0)
167                         rprintf(rank, n, "error stating %s: %s\n",
168                                 filename, strerror(errno));
169
170                 if (stat_buf.st_size != 0)
171                         rprintf(rank, n,
172                                 "filesize = %lu. Should be zero after truncate\n",
173                                 stat_buf.st_size);
174
175                 MPI_Barrier(MPI_COMM_WORLD);
176
177                 /* Do the race */
178                 offset = rank * CHUNK_SIZE(n);
179                 lseek(fd, offset, SEEK_SET);
180
181                 done = 0;
182                 do {
183                         ret = write(fd, chunk_buf[rank] + done,
184                                     CHUNK_SIZE(n) - done);
185                         if (ret < 0 && errno != EINTR)
186                                 rprintf(rank, n, "write() returned %s\n",
187                                         strerror(errno));
188                         if (ret > 0)
189                                 done += ret;
190                 } while (done != CHUNK_SIZE(n));
191
192                 MPI_Barrier(MPI_COMM_WORLD);
193
194                 /* Check the result */
195                 if (stat(filename, &stat_buf) < 0)
196                         rprintf(rank, n, "error stating %s: %s\n",
197                                 filename, strerror(errno));
198
199                 if (stat_buf.st_size != CHUNK_SIZE(n) * noProcessors) {
200                         if (n > 0)
201                                 printf("loop %d: chunk_size %lu, file size was %lu\n",
202                                        n - 1, CHUNK_SIZE(n - 1),
203                                        CHUNK_SIZE(n - 1) * noProcessors);
204                         rprintf(rank, n,
205                                 "invalid file size %lu instead of %lu = %lu * %u\n",
206                                 (unsigned long)stat_buf.st_size,
207                                 CHUNK_SIZE(n) * noProcessors,
208                                 CHUNK_SIZE(n), noProcessors);
209                 }
210
211                 if (rank == 0) {
212                         if (lseek(fd, 0, SEEK_SET) < 0)
213                                 rprintf(rank, n, "error seeking to 0: %s\n",
214                                         strerror(errno));
215
216                         done = 0;
217                         do {
218                                 ret = read(fd, read_buf + done,
219                                            CHUNK_SIZE(n) * noProcessors - done);
220                                 if (ret < 0)
221                                         rprintf(rank, n, "read returned %s\n",
222                                                 strerror(errno));
223
224                                 done += ret;
225                         } while (done != CHUNK_SIZE(n) * noProcessors);
226
227                         for (i = 0; i < noProcessors; i++) {
228                                 char command[4096];
229                                 int j;
230
231                                 if (!memcmp(read_buf + (i * CHUNK_SIZE(n)),
232                                             chunk_buf[i], CHUNK_SIZE(n)))
233                                         continue;
234
235                                 /* print out previous chunk sizes */
236                                 if (n > 0)
237                                         printf("loop %d: chunk_size %lu\n",
238                                                n - 1, CHUNK_SIZE(n - 1));
239
240                                 printf("loop %d: chunk %d corrupted with chunk_size %lu, page_size %d\n",
241                                        n, i, CHUNK_SIZE(n), getpagesize());
242                                 printf("ranks:\tpage boundry\tchunk boundry\tpage boundry\n");
243                                 for (j = 1 ; j < noProcessors; j++) {
244                                         int b = j * CHUNK_SIZE(n);
245
246                                         printf("%c -> %c:\t%d\t%d\t%d\n",
247                                                'A' + j - 1, 'A' + j,
248                                                b & ~(getpagesize() - 1), b,
249                                                (b + getpagesize()) &
250                                                ~(getpagesize() - 1));
251                                 }
252
253                                 sprintf(command, "od -Ad -a %s", filename);
254                                 ret = system(command);
255                                 rprintf(0, n, "data check error - exiting\n");
256                         }
257                 }
258                 MPI_Barrier(MPI_COMM_WORLD);
259         }
260
261         printf("Finished after %d loops\n", n);
262         MPI_Finalize();
263         return 0;
264 }