Whamcloud - gitweb
b=16098
[fs/lustre-release.git] / lustre / tests / createdestroy.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
37 #include <stdlib.h>
38 #include <stdio.h>
39 #include <unistd.h>
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <fcntl.h>
43 #include <errno.h>
44 #include <string.h>
45 #include <sys/wait.h>
46 #include <time.h>
47 #include <sys/time.h>
48
49 int thread;
50
51 #define BAD_VERBOSE (-999999999)
52
53 #define difftime(a, b)                                          \
54         ((double)(a)->tv_sec - (b)->tv_sec +                    \
55          ((double)((a)->tv_usec - (b)->tv_usec) / 1000000))
56
57 static char *cmdname(char *func)
58 {
59         static char buf[512];
60
61         if (thread) {
62                 sprintf(buf, "%s-%d", func, thread);
63                 return buf;
64         }
65
66         return func;
67 }
68
69 static int be_verbose(int verbose, struct timeval *next_time,
70                       unsigned long num, unsigned long *next_num, int num_total)
71 {
72         struct timeval now;
73
74         if (!verbose)
75                 return 0;
76
77         if (next_time != NULL)
78                 gettimeofday(&now, NULL);
79
80         /* A positive verbosity means to print every X iterations */
81         if (verbose > 0 && (num >= *next_num || num >= num_total)) {
82                 *next_num += verbose;
83                 if (next_time) {
84                         next_time->tv_sec = now.tv_sec - verbose;
85                         next_time->tv_usec = now.tv_usec;
86                 }
87                 return 1;
88         }
89
90         /* A negative verbosity means to print at most each X seconds */
91         if (verbose < 0 && next_time != NULL && difftime(&now, next_time) >= 0){
92                 next_time->tv_sec = now.tv_sec - verbose;
93                 next_time->tv_usec = now.tv_usec;
94                 *next_num = num;
95                 return 1;
96         }
97
98         return 0;
99 }
100
101 static int get_verbose(char *func, const char *arg)
102 {
103         int verbose;
104         char *end;
105
106         if (!arg || arg[0] == 'v')
107                 verbose = 1;
108         else if (arg[0] == 's' || arg[0] == 'q')
109                 verbose = 0;
110         else {
111                 verbose = (int)strtoul(arg, &end, 0);
112                 if (*end) {
113                         fprintf(stderr, "%s: error: bad verbose option '%s'\n",
114                                 func, arg);
115                         return BAD_VERBOSE;
116                 }
117         }
118
119         if (verbose < 0)
120                 printf("Print status every %d seconds\n", -verbose);
121         else if (verbose == 1)
122                 printf("Print status every operation\n");
123         else if (verbose > 1)
124                 printf("Print status every %d operations\n", verbose);
125
126         return verbose;
127 }
128
129 int main(int argc, char *argv[])
130 {
131         char filename[1024];
132         int verbose = 0;
133         unsigned long count, i;
134         int threads = 0;
135         char *end;
136         int rc = 0;
137
138         if (argc < 3 || argc > 5) {
139                 fprintf(stderr,
140                         "usage: %s <filename> <count> [verbose [threads]]\n",
141                         argv[0]);
142                 exit(1);
143         }
144
145         count = strtoul(argv[2], &end, 0);
146         if (*end) {
147                 fprintf(stderr, "%s: error: bad iteration count '%s'\n",
148                         argv[0], argv[1]);
149                 exit(2);
150         }
151         if (argc == 4) {
152                 verbose = get_verbose(argv[0], argv[3]);
153                 if (verbose == BAD_VERBOSE)
154                         exit(2);
155         }
156         if (argc == 5) {
157                 threads = strtoul(argv[4], &end, 0);
158                 if (*end) {
159                         fprintf(stderr, "%s: error: bad thread count '%s'\n",
160                                 argv[0], argv[1]);
161                         exit(2);
162                 }
163         }
164
165         for (i = 1; i <= threads; i++) {
166                 rc = fork();
167                 if (rc < 0) {
168                         fprintf(stderr, "%s: error: #%ld - %s\n",
169                                 cmdname(argv[0]), i, strerror(rc = errno));
170                         break;
171                 } else if (rc == 0) {
172                         thread = i;
173                         break;
174                 } else
175                         printf("%s: thread #%ld (PID %d) started\n",
176                                cmdname(argv[0]), i, rc);
177                 rc = 0;
178         }
179
180         if (threads && thread == 0) {   /* parent process */
181                 int live_threads = threads;
182
183                 while (live_threads > 0) {
184                         int status;
185                         pid_t ret;
186
187                         ret = waitpid(0, &status, 0);
188                         if (ret == 0) {
189                                 continue;
190                         }
191
192                         if (ret < 0) {
193                                 fprintf(stderr, "%s: error: wait - %s\n",
194                                         argv[0], strerror(errno));
195                                 if (!rc)
196                                         rc = errno;
197                         } else {
198                                 /*
199                                  * This is a hack.  We _should_ be able to use
200                                  * WIFEXITED(status) to see if there was an
201                                  * error, but it appears to be broken and it
202                                  * always returns 1 (OK).  See wait(2).
203                                  */
204                                 int err = WEXITSTATUS(status);
205                                 if (err || WIFSIGNALED(status))
206                                         fprintf(stderr,
207                                                 "%s: error: PID %d had rc=%d\n",
208                                                 argv[0], ret, err);
209                                 if (!rc)
210                                         rc = err;
211
212                                 live_threads--;
213                         }
214                 }
215         } else {
216                 struct timeval start, end, next_time;
217                 unsigned long next_count;
218                 double diff;
219
220                 gettimeofday(&start, NULL);
221                 next_time.tv_sec = start.tv_sec - verbose;
222                 next_time.tv_usec = start.tv_usec;
223
224                 for (i = 0, next_count = verbose; i < count; i++) {
225                         if (threads)
226                                 sprintf(filename, "%s-%d-%ld",
227                                         argv[1], thread, i);
228                         else
229                                 sprintf(filename, "%s-%ld", argv[1], i);
230
231                         rc = mknod(filename, S_IFREG, 0);
232                         if (rc < 0) {
233                                 fprintf(stderr, "%s: error: mknod(%s): %s\n",
234                                         cmdname(argv[0]), filename,
235                                         strerror(errno));
236                                 rc = errno;
237                                 break;
238                         }
239                         if (unlink(filename) < 0) {
240                                 fprintf(stderr, "%s: error: unlink(%s): %s\n",
241                                         cmdname(argv[0]), filename,
242                                         strerror(errno));
243                                 rc = errno;
244                                 break;
245                         }
246                         if (be_verbose(verbose, &next_time,i,&next_count,count))
247                                 printf("%s: number %ld\n", cmdname(argv[0]), i);
248                 }
249
250                 gettimeofday(&end, NULL);
251                 diff = difftime(&end, &start);
252
253                 printf("%s: %ldx2 files in %.4gs (%.4g ops/s): rc = %d: %s",
254                        cmdname(argv[0]), i, diff, (double)i * 2 / diff,
255                        rc, ctime(&end.tv_sec));
256         }
257         return rc;
258 }