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