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