Whamcloud - gitweb
LU-8648 all: remove all Sun license and URL references
[fs/lustre-release.git] / lustre / tests / writemany.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) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  */
26 /*
27  * This file is part of Lustre, http://www.lustre.org/
28  * Lustre is a trademark of Sun Microsystems, Inc.
29  */
30
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <unistd.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <signal.h>
37 #include <fcntl.h>
38 #include <errno.h>
39 #include <string.h>
40 #include <sys/wait.h>
41 #include <time.h>
42 #include <sys/time.h>
43
44
45 #define difftime(a, b)                                          \
46         ((double)(a)->tv_sec - (b)->tv_sec +                    \
47          ((double)((a)->tv_usec - (b)->tv_usec) / 1000000))
48
49
50
51 char cmdname[512];
52 int o_abort = 0;
53 int o_quiet = 0;
54
55 void usage(char *name)
56 {
57         fprintf(stderr, "usage: %s [opts] <dirname> <seconds> <threads>\n",
58                 name);
59         fprintf(stderr, "  -q quiet\n");
60         fprintf(stderr, "  -a abort other children on first err\n");
61         exit(1);
62 }
63
64
65 struct kid_list_t {
66         pid_t kid;
67         struct kid_list_t *next;
68 };
69
70 struct kid_list_t *head = NULL;
71
72 int push_kid(pid_t kid)
73 {
74         struct kid_list_t *new;
75         new = (struct kid_list_t *)malloc(sizeof(struct kid_list_t));
76         if (new == NULL)
77                 return 1;
78
79         new->kid = kid;
80         new->next = head;
81         head = new;
82         return 0;
83 }
84
85 void kill_kids(void)
86 {
87         while(head) {
88                 kill(head->kid, SIGTERM);
89                 head = head->next;
90         }
91 }
92
93 static int usr1_received;
94 void usr1_handler(int unused)
95 {
96         usr1_received = 1;
97         kill_kids();
98 }
99
100 int wait_for_threads(int live_threads)
101 {
102         int rc = 0;
103
104         while (live_threads > 0) {
105                 int status;
106                 pid_t ret;
107
108                 ret = waitpid(0, &status, 0);
109                 if (ret == 0) {
110                         continue;
111                 }
112
113                 if (ret < 0) {
114                         fprintf(stderr, "%s: error: wait - %s\n",
115                                 cmdname, strerror(errno));
116                         if (!rc)
117                                 rc = errno;
118                 } else {
119                         /*
120                          * This is a hack.  We _should_ be able to use
121                          * WIFEXITED(status) to see if there was an
122                          * error, but it appears to be broken and it
123                          * always returns 1 (OK).  See wait(2).
124                          */
125                         int err = WEXITSTATUS(status);
126                         if (err)
127                                 fprintf(stderr,
128                                         "%s: error: PID %d had rc=%d\n",
129                                         cmdname, ret, err);
130                         /* Record first error */
131                         if (!rc)
132                                 rc = err;
133
134                         /* Give up on first error */
135                         if (rc && o_abort) {
136                                 kill_kids();
137                                 break;
138                         }
139
140                         live_threads--;
141                 }
142         }
143         if (!o_quiet)
144                 printf("%s done, rc = %d\n", cmdname, rc);
145         return rc;
146 }
147
148 void print_err(char *op, char *filename, struct timeval *time, int err)
149 {
150         fprintf(stderr, "%s: %d.%.06d error: %s(%s): %s\n",
151                 cmdname, (int)(time->tv_sec), (int)(time->tv_usec), op,
152                 filename, strerror(errno));
153 }
154
155 int run_one_child(char *file, int thread, int seconds)
156 {
157         struct timeval start, cur;
158         double diff;
159         char filename[1024];
160         char buf[1024];
161         int fd, rc = 0, rand, maxrand, len;
162         long nfiles = 0, nbytes = 0;
163
164         if (!o_quiet)
165                 printf("%s: running thread #%d\n", cmdname, thread);
166
167         srandom(thread);
168         /* Higher thread numbers will produce bigger random files.
169            Thread 1 will produce only 0-len files. */
170         maxrand = 1; rand = thread;
171         while (--rand)
172                 maxrand *= 10;
173
174         gettimeofday(&start, NULL);
175         cur = start;
176
177         while(!rc) {
178                 if (usr1_received)
179                         break;
180
181                 gettimeofday(&cur, NULL);
182                 if (seconds) {
183                         if (cur.tv_sec > (start.tv_sec + seconds))
184                                 break;
185                 }
186                 
187                 snprintf(filename, sizeof(filename), "%s-%d-%ld",
188                          file, thread, nfiles);
189
190                 fd = open(filename, O_RDWR | O_CREAT, 0666);
191                 if (fd < 0) {
192                         print_err("open", filename, &cur, errno);
193                         rc = errno;
194                         break;
195                 }
196
197                 sprintf(buf, "%s %010ld %.19s.%012d\n", cmdname,
198                         nfiles++, ctime(&cur.tv_sec), (int)cur.tv_usec);
199                 len = strlen(buf);
200
201                 rand = random() % maxrand;
202                 while (rand-- > 0) {
203                         if (write(fd, buf, len) != len) {
204                                 print_err("write", filename, &cur, errno);
205                                 rc = errno;
206                                 break;
207                         }
208                         nbytes += len;
209                 }
210
211                 if (close(fd) < 0) {
212                         print_err("close", filename, &cur, errno);
213                         rc = errno;
214                         break;
215                 }
216                 if (unlink(filename) < 0) {
217                         print_err("unlink", filename, &cur, errno);
218                         if (errno == ENOENT) {
219                                 printf("Ignoring known bug 6082\n");
220                         } else {
221                                 rc = errno;
222                                 break;
223                         }
224                 }
225         }
226
227         diff = difftime(&cur, &start);
228         if (!o_quiet)
229                 printf("%s: %7ld files, %4ld MB in %.2fs (%7.2f files/s, "
230                        "%5.2f MB/s): rc = %d\n",
231                        cmdname, nfiles, nbytes >> 20, diff,
232                        diff == 0 ? (double)0 : (double)nfiles / diff,
233                        diff == 0 ? (double)0 : (double)nbytes/1024/1024 / diff,
234                        rc);
235
236         return rc;
237 }
238
239 int main(int argc, char *argv[])
240 {
241         unsigned long duration;
242         int threads = 0;
243         char *end;
244         char *directory;
245         int i = 1, rc = 0;
246
247         snprintf(cmdname, sizeof(cmdname), "%s", argv[0]);
248
249         while((i < argc) && (argv[i][0] == '-')) {
250                 switch (argv[i][1]) {
251                 case 'q':
252                         o_quiet++;
253                         break;
254                 case 'a':
255                         o_abort++;
256                         break;
257                 }
258                 i++;
259         }
260
261         if ((argc - i) < 3)
262                 usage(argv[0]);
263
264         directory = argv[i];
265         duration = strtoul(argv[++i], &end, 0);
266         if (*end) {
267                 fprintf(stderr, "%s: error: bad number of seconds '%s'\n",
268                         cmdname, argv[i]);
269                 exit(2);
270         }
271
272         threads = strtoul(argv[++i], &end, 0);
273         if (*end) {
274                 fprintf(stderr, "%s: error: bad thread count '%s'\n",
275                         cmdname, argv[i]);
276                 exit(2);
277         }
278
279         signal(SIGUSR1, usr1_handler);
280
281         for (i = 1; i <= threads; i++) {
282                 rc = fork();
283                 if (rc < 0) {
284                         if (!o_quiet)
285                                 fprintf(stderr, "%s: error: #%d - %s\n",
286                                         cmdname, i, strerror(rc = errno));
287                         return (rc);
288                 }
289                 if (rc == 0) {
290                         /* children */
291                         snprintf(cmdname, sizeof(cmdname), "%s-%d", argv[0], i);
292                         return (run_one_child(directory, i, duration));
293                 } else {
294                         /* parent */
295                         rc = push_kid(rc);
296                         if (rc != 0) {
297                                 kill_kids();
298                                 exit(3);
299                         }
300                 }
301         }
302         /* parent process */
303         if (!o_quiet)
304                 printf("%s will run for %ld minutes\n", cmdname, duration/60);
305         return (wait_for_threads(threads));
306 }