Whamcloud - gitweb
LU-6245 libcfs: remove types.h from userland code
[fs/lustre-release.git] / lustre / tests / mpi / mdsrate.c
1 /*
2  * 2003, Copyright, Hewlett-Packard Development Compnay, LP.
3  *
4  * Developed under the sponsorship of the U.S. Government
5  *     under Subcontract No. B514193
6  */
7
8 /*
9  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
10  * Use is subject to license terms.
11  *
12  * Copyright (c) 2012, 2015, Intel Corporation.
13  */
14
15 #include <stdio.h>
16 #include <getopt.h>
17 #include <libgen.h>
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <time.h>
21 #include <limits.h>
22 #include <errno.h>
23 #include <string.h>
24 #include <fcntl.h>
25 #include <unistd.h>
26 #include <stdlib.h>
27 #include <stdarg.h>
28 #include <signal.h>
29 #include <sys/ioctl.h>
30 #include <dirent.h>
31 #include <sys/xattr.h>
32
33 #include "mpi.h"
34
35 /* lustre */
36 #include <lustre/lustreapi.h>        /* for O_LOV_DELAY_CREATE */
37
38 #define CHECK_COUNT 10000
39 #define DISPLAY_COUNT (CHECK_COUNT * 10)
40 #define DISPLAY_TIME 100
41
42 enum {
43         CREATE          = 'c',
44         LOOKUP          = 'l',
45         MKNOD           = 'm',
46         OPEN            = 'o',
47         STAT            = 's',
48         UNLINK          = 'u',
49         BEGIN           = 'b',
50         ITERS           = 'i',
51         TIME            = 't',
52         DIRFMT          = 'd',
53         NDIRS           = 'D',
54         FILEFMT         = 'f',
55         NFILES          = 'F',
56         NOEXCL          = 'X',
57         STRIPES         = 'S',
58         SEED            = 'r',
59         SEEDFILE        = 'R',
60         RANDOM          = 'A',
61         READDIR         = 'B',
62         RECREATE        = 'C',
63         SETXATTR        = 'x',
64         SMALLWRITE      = 'w',
65         IGNORE          = 'E',
66         VERBOSE         = 'V',
67         DEBUG           = 'v',
68         HELP            = 'h',
69         MNT             = 'M',
70         MNTCOUNT        = 'N',
71         MDTCOUNT        = 'T',
72 };
73
74 struct option longOpts[] = {
75         {"create",              0, NULL, CREATE     },
76         {"lookup",              0, NULL, LOOKUP     },
77         {"mknod",               0, NULL, MKNOD      },
78         {"open",                0, NULL, OPEN       },
79         {"stat",                0, NULL, STAT       },
80         {"unlink",              0, NULL, UNLINK     },
81         {"begin",               1, NULL, BEGIN      },
82         {"iters",               1, NULL, ITERS      },
83         {"time",                1, NULL, TIME       },   /* seconds */
84         {"dirfmt",              1, NULL, DIRFMT     },
85         {"ndirs",               1, NULL, NDIRS      },
86         {"filefmt",             1, NULL, FILEFMT    },
87         {"nfiles",              1, NULL, NFILES     },
88         {"noexcl",              0, NULL, NOEXCL     },
89         {"stripes",             1, NULL, STRIPES    },
90         {"seed",                1, NULL, SEED       },
91         {"seedfile",            1, NULL, SEEDFILE   },
92         {"random_order",        0, NULL, RANDOM     },
93         {"readdir_order",       0, NULL, READDIR    },
94         {"recreate",            0, NULL, RECREATE   },
95         {"setxattr",            0, NULL, SETXATTR   },
96         {"smallwrite",          0, NULL, SMALLWRITE },
97         {"ignore",              0, NULL, IGNORE     },
98         {"verbose",             0, NULL, VERBOSE    },
99         {"debug",               0, NULL, DEBUG      },
100         {"help",                0, NULL, HELP       },
101         {"mdtcount",            1, NULL, MDTCOUNT   },
102         {"mntcount",            1, NULL, MNTCOUNT   },
103         {"mntfmt",              1, NULL, MNT        },
104         { 0,                    0, NULL, 0          }
105 };
106
107 int foo1, foo2;
108
109 char   shortOpts[128];
110 int    myrank = -1;
111 int    nthreads = -1;
112 char * prog;
113 char   hostname[512] = "unknown";
114 char   mode;
115 char * cmd;
116 int    openflags = O_RDWR|O_CREAT|O_EXCL;
117 int    ndirs = 1;
118 char * dirfmt;
119 char   dir[PATH_MAX];
120 char   mkdir_cmd[PATH_MAX+14];
121 int    dirthreads;
122 int    dirnum;
123 DIR *  directory;
124 struct dirent *dir_entry;
125 int    nfiles;
126 char   filefmt[PATH_MAX];
127 char   filename[PATH_MAX];
128 char   path[PATH_MAX];
129 int    stripes = -1;
130 int    begin;
131 int    beginsave;
132 int    end;
133 int    iters;
134 int    seconds;
135 int    alarm_caught;
136 struct sigaction act;
137 int    order = RANDOM;
138 int    seed;
139 int    recreate;
140 int    ignore;
141 int    verbose;
142 int    debug;
143 struct stat statbuf;
144 bool   with_xattr;
145 char   xattrname[] = "user.mdsrate";
146 char   xattrbuf[4096];
147 /* max xattr name + value length is block size, use 4000 here to avoid ENOSPC */
148 int    xattrlen = 4000;
149 bool   smallwrite;
150 int    mnt_count = -1;
151 int    mdt_count = 1;
152 char  *mntfmt;
153
154 #define dmesg if (debug) printf
155
156 #define DISPLAY_PROGRESS() {                                                \
157         if (verbose && (nops % CHECK_COUNT == 0)) {                         \
158                 curTime = MPI_Wtime();                                      \
159                 interval = curTime - lastTime;                              \
160                 if (interval > DISPLAY_TIME || nops % DISPLAY_COUNT == 0) { \
161                         rate = (double)(nops - lastOps)/interval;           \
162                         printf("Rank %d: %.2f %ss/sec %.2f secs "           \
163                                "(total: %d %ss %.2f secs)\n",               \
164                                myrank, rate, cmd, interval,                 \
165                                nops, cmd, curTime - startTime);             \
166                         lastOps = nops;                                     \
167                         lastTime = curTime;                                 \
168                 }                                                           \
169         }                                                                   \
170 }
171
172 char *usage_msg = "usage: %s\n"
173                   "    { --create [ --noexcl | --setxattr | --smallwrite ] |\n"
174                   "      --lookup | --mknod [ --setxattr ] | --open |\n"
175                   "      --stat | --unlink [ --recreate ] [ --ignore ] |\n"
176                   "      --setxattr }\n"
177                   "    [ --help ] [ --verbose ] [ --debug ]\n"
178                   "    { [ --begin <num> ] --nfiles <num> }\n"
179                   "    [ --iters <num> ] [ --time <secs> ]\n"
180                   "    [ --dirfmt <str> ] [ --ndirs  <num> ]\n"
181                   "    [ --filefmt <str> ] [ --stripes <num> ]\n"
182                   "    [ --random_order [--seed <num> | --seedfile <file>] ]\n"
183                   "    [ --readdir_order ] [ --mntfmt <str> ]\n"
184                   "    [ --mntcount <num> ] [ --mdtcount <num> ]\n"
185                   "    [ --setxattr ] }\n";
186
187 static void
188 usage(FILE *stream, char *fmt, ...)
189 {
190         if (myrank == 0) {
191                 if (fmt != NULL) {
192                         va_list       ap;
193
194                         fprintf(stream, "%s: ", prog);
195                         va_start(ap, fmt);
196                         vfprintf(stderr, fmt, ap);
197                         va_end(ap);
198                 }
199                 fprintf(stream, usage_msg, prog);
200         }
201
202         MPI_Finalize();
203         exit(stream == stderr);
204 }
205
206 /* Print process myrank and message, and exit (i.e. a fatal error) */
207 static int
208 fatal(int rank, const char *fmt, ...)
209 {
210         if (rank == myrank) {
211                 va_list       ap;
212
213                 fprintf(stderr, "rank %d: ", rank);
214                 va_start(ap, fmt);
215                 vfprintf(stderr, fmt, ap);
216                 va_end(ap);
217         }
218
219         MPI_Abort(MPI_COMM_WORLD, 1);
220         exit(1);
221 }
222
223 static void
224 sigalrm_handler(int signum)
225 {
226         alarm_caught++;
227 }
228
229 /* HAVE_LLAPI_FILE_LOOKUP is defined by liblustreapi.h if this function is
230  * defined therein.  Otherwise we can do the equivalent operation via ioctl
231  * if we have access to a complete lustre build tree to get the various
232  * definitions - then compile with USE_MDC_LOOKUP defined. */
233 #if defined(HAVE_LLAPI_FILE_LOOKUP)
234 #define HAVE_MDC_LOOKUP
235 #elif defined(USE_MDC_LOOKUP)
236 #include <config.h>
237 #include <lustre_ioctl.h>
238
239 int llapi_file_lookup(int dirfd, const char *name)
240 {
241         struct obd_ioctl_data data = { 0 };
242         char rawbuf[8192];
243         char *buf = rawbuf;
244         int rc;
245
246         if (dirfd < 0 || name == NULL)
247                 return -EINVAL;
248
249         data.ioc_version = OBD_IOCTL_VERSION;
250         data.ioc_len = sizeof(data);
251         data.ioc_inlbuf1 = name;
252         data.ioc_inllen1 = strlen(name) + 1;
253
254         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
255         if (rc) {
256                 fatal(myrank, "ioctl_pack failed: rc = %d\n", rc);
257                 return rc;
258         }
259
260         return ioctl(fd, IOC_MDC_LOOKUP, buf);
261 }
262 #define HAVE_MDC_LOOKUP
263 #endif
264
265 static void
266 process_args(int argc, char *argv[])
267 {
268         char   *cp, *endptr;
269         int    i, index, offset, tmpend, rc;
270         char   tmp[16];
271         FILE * seed_file;
272         struct option *opt;
273
274         setbuf(stdout, 0);
275         setbuf(stderr, 0);
276         prog = basename(argv[0]);
277         strcpy(filefmt, "f%d");
278         gethostname(hostname, sizeof(hostname));
279
280         /* auto create shortOpts rather than maintaining a static string. */
281         for (opt = longOpts, cp = shortOpts; opt->name != NULL; opt++, cp++) {
282                 *cp = opt->val;
283                 if (opt->has_arg)
284                         *++cp = ':';
285         }
286
287         while ((rc = getopt_long(argc,argv, shortOpts, longOpts,&index)) != -1) {
288                 switch (rc) {
289                 case OPEN:
290                         openflags &= ~(O_CREAT|O_EXCL);
291                 case CREATE:
292 #ifdef HAVE_MDC_LOOKUP
293                 case LOOKUP:
294 #endif
295                 case MKNOD:
296                 case STAT:
297                 case UNLINK:
298                         if (cmd != NULL) {
299                                 fatal(0, "Invalid - more than one operation "
300                                            "specified: --%s\n",
301                                         longOpts[index].name);
302                         }
303                         mode = rc;
304                         cmd = (char *)longOpts[index].name;
305                         break;
306                 case NOEXCL:
307                         if (mode != CREATE && mode != MKNOD) {
308                                 usage(stderr, "--noexcl only applies to "
309                                               "--create or --mknod.\n");
310                         }
311                         openflags &= ~O_EXCL;
312                         break;
313                 case RECREATE:
314                         if (mode != UNLINK) {
315                                 usage(stderr, "--recreate only makes sense"
316                                               "with --unlink.\n");
317                         }
318                         recreate++;
319                         break;
320                 case SETXATTR:
321                         if (cmd == NULL) {
322                                 mode = SETXATTR;
323                                 cmd = (char *)longOpts[index].name;
324                         } else if (mode == CREATE || mode == MKNOD) {
325                                 with_xattr = true;
326                         } else {
327                                 usage(stderr, "--setxattr only makes sense "
328                                       "with --create, --mknod or alone.\n");
329                         }
330                         break;
331                 case SMALLWRITE:
332                         if (mode != CREATE)
333                                 usage(stderr, "--smallwrite only applies to "
334                                               "--create.\n");
335                         smallwrite = true;
336                         break;
337                 case BEGIN:
338                         begin = strtol(optarg, &endptr, 0);
339                         if ((*endptr != 0) || (begin < 0)) {
340                                 fatal(0, "Invalid --start value.\n");
341                         }
342                         break;
343                 case ITERS:
344                         iters = strtol(optarg, &endptr, 0);
345                         if ((*endptr != 0) || (iters <= 0)) {
346                                 fatal(0, "Invalid --iters value.\n");
347                         }
348                         if (mode != LOOKUP && mode != OPEN) {
349                                 usage(stderr, "--iters only makes sense with "
350                                               "--lookup or --open.\n");
351                         }
352                         break;
353                 case TIME:
354                         seconds = strtol(optarg, &endptr, 0);
355                         if ((*endptr != 0) || (seconds <= 0)) {
356                                 fatal(0, "Invalid --time value.\n");
357                         }
358                         break;
359                 case DIRFMT:
360                         if (strlen(optarg) > (PATH_MAX - 16)) {
361                                 fatal(0, "--dirfmt too long\n");
362                         }
363                         dirfmt = optarg;
364                         break;
365                 case NDIRS:
366                         ndirs = strtol(optarg, &endptr, 0);
367                         if ((*endptr != 0) || (ndirs <= 0)) {
368                                 fatal(0, "Invalid --ndirs value.\n");
369                         }
370                         if ((ndirs > nthreads) &&
371                             ((mode == CREATE) || (mode == MKNOD))) {
372                                 fatal(0, "--ndirs=%d must be less than or "
373                                       "equal to the number of threads (%d).\n",
374                                       ndirs, nthreads);
375                         }
376                         break;
377                 case FILEFMT:
378                         if (strlen(optarg) > 4080) {
379                                 fatal(0, "--filefmt too long\n");
380                         }
381
382                         /* Use %%d where you want the file # in the name. */
383                         sprintf(filefmt, optarg, myrank);
384                         break;
385                 case NFILES:
386                         nfiles = strtol(optarg, &endptr, 0);
387                         if ((*endptr != 0) || (nfiles <= 0)) {
388                                 fatal(0, "Invalid --nfiles value.\n");
389                         }
390                         break;
391                 case STRIPES:
392                         stripes = strtol(optarg, &endptr, 0);
393                         if ((*endptr != 0) || (stripes < 0)) {
394                                 fatal(0, "Invalid --stripes value.\n");
395                         }
396
397                         if (stripes == 0) {
398                                 openflags |= O_LOV_DELAY_CREATE;
399                         } else {
400                                 fatal(0, "non-zero --stripes value "
401                                          "not yet supported.\n");
402                         }
403
404                         break;
405                 case SEED:
406                         seed = strtoul(optarg, &endptr, 0);
407                         if (*endptr) {
408                                 fatal(0, "bad --seed option %s\n", optarg);
409                         }
410                         break;
411                 case SEEDFILE:
412                         seed_file = fopen(optarg, "r");
413                         if (!seed_file) {
414                               fatal(myrank, "fopen(%s) error: %s\n",
415                                       optarg, strerror(errno));
416                         }
417
418                         for (i = -1; fgets(tmp, 16, seed_file) != NULL;) {
419                                 if (++i == myrank)
420                                         break;
421                         }
422
423                         if (i == myrank) {
424                                 rc = sscanf(tmp, "%d", &seed);
425                                 if ((rc != 1) || (seed < 0)) {
426                                         fatal(myrank, "Invalid seed value '%s' "
427                                               "at line %d in %s.\n",
428                                               tmp, i, optarg);
429                                 }
430                         } else {
431                                 fatal(myrank, "File '%s' too short. Does not "
432                                       "contain a seed for thread %d.\n",
433                                       optarg, myrank);
434                         }
435
436                         fclose(seed_file);
437                         break;
438                 case RANDOM:
439                 case READDIR:
440                         if (mode != LOOKUP && mode != OPEN)  {
441                                 fatal(0, "--%s can only be specified with "
442                                          "--lookup, or --open.\n",
443                                       (char *)longOpts[index].name);
444                         }
445                         order = rc;
446                         break;
447                 case IGNORE:
448                         ++ignore;
449                         break;
450                 case DEBUG:
451                         ++debug;
452                 case VERBOSE:
453                         ++verbose;
454                         break;
455                 case HELP:
456                         usage(stdout, NULL);
457                         break;
458                 case MNT:
459                         if (strlen(optarg) > (PATH_MAX - 16))
460                                 fatal(0, "--mnt too long\n");
461                         mntfmt = optarg;
462                         break;
463                 case MNTCOUNT:
464                         mnt_count = strtol(optarg, &endptr, 0);
465                         if ((*endptr != 0) || (mnt_count <= 0)) {
466                                 fatal(0, "Invalid --mnt_count value %s.\n",
467                                       optarg);
468                         }
469                         break;
470                 case MDTCOUNT:
471                         mdt_count = strtol(optarg, &endptr, 0);
472                         if ((*endptr != 0) || (mdt_count <= 0)) {
473                                 fatal(0, "Invalid --mdt_count value %s.\n",
474                                       optarg);
475                         }
476                         break;
477                 default:
478                         usage(stderr, "unrecognized option: '%c'.\n", optopt);
479                 }
480         }
481
482         if (optind < argc) {
483                 usage(stderr, "too many arguments %d >= %d.\n", optind, argc);
484         }
485
486         if ((mnt_count != -1 && mntfmt == NULL) ||
487             (mnt_count == -1 && mntfmt != NULL)) {
488                 usage(stderr, "mnt_count and mntfmt must be specified at the "
489                              "same time\n");
490         }
491
492         if (mode == CREATE || mode == MKNOD || mode == UNLINK ||
493             mode == STAT || mode == SETXATTR) {
494                 if (seconds != 0) {
495                         if (nfiles == 0)
496                                 nfiles = INT_MAX;
497                 } else if (nfiles == 0) {
498                         usage(stderr, "--nfiles or --time must be specified "
499                                       "with %s.\n", cmd);
500                 }
501         } else if (mode == LOOKUP || mode == OPEN) {
502                 if (seconds != 0) {
503                         if (iters == 0)
504                                 iters = INT_MAX;
505                 } else if (iters == 0) {
506                         usage(stderr, "--iters or --time must be specifed "
507                                       "with %s.\n", cmd);
508                 }
509
510                 if (nfiles == 0) {
511                         usage(stderr, "--nfiles must be specifed with --%s.\n",
512                               cmd);
513                 }
514
515                 if (seed == 0) {
516                         int fd = open("/dev/urandom", O_RDONLY);
517
518                         if (fd >= 0) {
519                                 if (read(fd, &seed, sizeof(seed)) <
520                                     sizeof(seed))
521                                         seed = time(0);
522                                 close(fd);
523                         } else {
524                                 seed = time(0);
525                         }
526                 }
527
528                 srand(seed);
529
530                 dmesg("%s: rank %d seed %d (%s).\n", prog, myrank, seed,
531                       (order == RANDOM) ? "random_order" : "readdir_order");
532         } else {
533                 usage(stderr, "one --create, --mknod, --open, --stat,"
534 #ifdef HAVE_MDC_LOOKUP
535                       " --lookup,"
536 #endif
537                       " --unlink or --setxattr must be specifed.");
538         }
539
540         /* support for multiple threads in a dir, set begin/end appropriately.*/
541         dirnum = myrank % ndirs;
542         dirthreads = nthreads / ndirs;
543         if (nthreads > (ndirs * dirthreads + dirnum))
544                 ++dirthreads;
545
546         offset = myrank / ndirs;
547
548         tmpend = begin + nfiles - 1;
549         if (tmpend <= 0)
550                 tmpend = INT_MAX;
551
552         end = begin + (nfiles / dirthreads) * dirthreads + offset;
553         if ((end > tmpend) || (end <= 0))
554                 end -= dirthreads;
555
556         /* make sure mnt_count <= nthreads, otherwise it might div 0 in
557          * the following test */
558         if (mnt_count > nthreads)
559                 mnt_count = nthreads;
560
561         begin += offset;
562         if (begin < 0)
563                 begin = INT_MAX;
564
565         beginsave = begin;
566
567         dmesg("%d: iters %d nfiles %d time %d begin %d end %d dirthreads %d."
568               "\n", myrank, iters, nfiles, seconds, begin, end, dirthreads);
569
570         if (dirfmt == NULL) {
571                 strcpy(dir, ".");
572         } else {
573                 int dir_len = 0;
574
575                 if (mntfmt != NULL) {
576                         sprintf(dir, mntfmt, (myrank / (nthreads/mnt_count)));
577                         strcat(dir, "/");
578                         dir_len = strlen(dir);
579                 }
580                 sprintf(dir + dir_len, dirfmt, dirnum);
581
582                 if (mdt_count > 1) {
583                         struct stat sb;
584                         if (stat(dir, &sb) == 0) {
585                                 if (!S_ISDIR(sb.st_mode))
586                                         fatal(myrank, "'%s' is not dir\n", dir);
587                         } else if (errno == ENOENT) {
588                                 sprintf(mkdir_cmd, "lfs mkdir -i %d %s",
589                                         myrank % mdt_count, dir);
590                         } else {
591                                 fatal(myrank, "'%s' stat failed\n", dir);
592                         }
593                 } else {
594                         sprintf(mkdir_cmd, "mkdir -p %s", dir);
595                 }
596
597                 dmesg("%d: %s\n", myrank, mkdir_cmd);
598 #ifdef _LIGHTWEIGHT_KERNEL
599                 printf("NOTICE: not running system(%s)\n", mkdir_cmd);
600 #else
601                 rc = system(mkdir_cmd);
602                 if (rc)
603                         fatal(myrank, "'%s' failed.\n", mkdir_cmd);
604 #endif
605
606                 rc = chdir(dir);
607                 if (rc) {
608                         fatal(myrank, "unable to chdir to '%s'.\n", dir);
609                 }
610         }
611 }
612
613 static inline char *next_file()
614 {
615         if (order == RANDOM) {
616                 sprintf(filename, filefmt, random() % nfiles);
617                 return(filename);
618         }
619
620         /* readdir order */
621
622         dir_entry = readdir(directory);
623         if (dir_entry == NULL) {
624                 rewinddir(directory);
625                 while ((dir_entry = readdir(directory)) != NULL) {
626                         if (dir_entry->d_name[0] != '.')
627                                 return(dir_entry->d_name);
628                 }
629
630                 fatal(myrank, "unable to read directory %s (%s).\n",
631                       dir, strerror(errno));
632         }
633
634         return(dir_entry->d_name);
635 }
636
637 int
638 main(int argc, char *argv[])
639 {
640         int    i, j, fd, rc, nops, lastOps;
641         int ag_ops = 0;
642         double ag_interval = 0;
643         double ag_rate = 0;
644         double rate, avg_rate, effective_rate;
645         double startTime, curTime, lastTime, interval;
646         time_t timestamp;
647         char * file;
648
649         rc = MPI_Init(&argc, &argv);
650         if (rc != MPI_SUCCESS)
651                 fatal(myrank, "MPI_Init failed: %d\n", rc);
652
653         rc = MPI_Comm_size(MPI_COMM_WORLD, &nthreads);
654         if (rc != MPI_SUCCESS)
655                 fatal(myrank, "MPI_Comm_size failed: %d\n", rc);
656
657         rc = MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
658         if (rc != MPI_SUCCESS)
659                 fatal(myrank, "MPI_Comm_rank failed: %d\n", rc);
660
661         process_args(argc, argv);
662
663         timestamp = time(0);
664         if ((myrank == 0) || debug) {
665                 printf("%d: %s starting at %s",
666                        myrank, hostname, ctime(&timestamp));
667         }
668
669         /* if we're not measuring creation rates then precreate
670          * the files we're operating on. */
671         if ((mode != CREATE) && (mode != MKNOD) && !ignore &&
672             (mode != UNLINK || recreate)) {
673                 /* create the files in reverse order. When we encounter
674                  * a file that already exists, assume the remainder of 
675                  * the files exist to save time. The timed performance
676                  * test scripts make use of this behavior. */
677                 for (i = end, j = 0; i >= begin; i -= dirthreads) {
678                         sprintf(filename, filefmt, i);
679                         fd = open(filename, openflags, 0644);
680                         if (fd < 0) {
681                                 if (errno == EEXIST)
682                                         break;
683                                 rc = errno;
684                                 fatal(myrank, "precreate open(%s) error: %s\n",
685                                       filename, strerror(rc));
686                         }
687                         j++;
688                         close(fd);
689                 }
690                 dmesg("%d: %s pre-created %d files.\n",myrank,hostname,j);
691
692                 rc = MPI_Barrier(MPI_COMM_WORLD);
693                 if (rc != MPI_SUCCESS)
694                         fatal(myrank, "prep MPI_Barrier failed: %d\n", rc);
695         }
696
697         if (order == READDIR) {
698                 directory = opendir(dir);
699                 if (directory == NULL) {
700                         rc = errno;
701                         fatal(myrank, "opendir(%s) error: %s\n",
702                               dir, strerror(rc));
703                 }
704
705                 timestamp = time(0);
706                 j = random() % nfiles;
707                 dmesg("%d: %s initializing dir offset %u: %s",
708                       myrank, hostname, j, ctime(&timestamp));
709
710                 for (i = 0; i <= j; i++) {
711                         if ((dir_entry = readdir(directory)) == NULL) {
712                                 fatal(myrank, "could not read entry number %d "
713                                       "in directory %s.\n", i, dir);
714                         }
715                 }
716
717                 timestamp = time(0);
718                 dmesg("%d: index %d, filename %s, offset %ld: "
719                       "%s initialization complete: %s",
720                       myrank, i, dir_entry->d_name, telldir(directory),
721                       hostname, ctime(&timestamp));
722         }
723
724         if (seconds) {
725                 act.sa_handler = sigalrm_handler;
726                 (void)sigemptyset(&act.sa_mask);
727                 act.sa_flags = 0;
728                 sigaction(SIGALRM, &act, NULL);
729                 alarm(seconds);
730         }
731
732         rc = MPI_Barrier(MPI_COMM_WORLD);
733         if (rc != MPI_SUCCESS)
734                 fatal(myrank, "prep MPI_Barrier failed: %d\n", rc);
735
736         startTime = lastTime = MPI_Wtime();
737         nops = lastOps = 0;
738
739         switch (mode) {
740         case CREATE:
741                 for (; begin <= end && !alarm_caught; begin += dirthreads) {
742                         snprintf(filename, sizeof(filename), filefmt, begin);
743                         fd = open(filename, openflags, 0644);
744                         if (fd < 0) {
745                                 rc = errno;
746                                 if (rc == EINTR && alarm_caught)
747                                         break;
748                                 fatal(myrank, "open(%s) error: %s\n",
749                                       filename, strerror(rc));
750                         }
751
752                         if (with_xattr) {
753                                 rc = fsetxattr(fd, xattrname, xattrbuf,
754                                                xattrlen, XATTR_CREATE);
755                                 if (rc) {
756                                         rc = errno;
757                                         if (rc == EINTR && alarm_caught)
758                                                 break;
759                                         fatal(myrank,
760                                               "setxattr(%s) error: %s\n",
761                                               filename, strerror(rc));
762                                 }
763                         }
764                         if (smallwrite) {
765                                 rc = write(fd, xattrbuf, xattrlen);
766                                 if (rc < 0) {
767                                         rc = errno;
768                                         if (rc == EINTR && alarm_caught)
769                                                 break;
770                                         fatal(myrank,
771                                               "write(%s) error: %s\n",
772                                               filename, strerror(rc));
773                                 }
774                         }
775
776                         close(fd);
777                         nops++;
778                         DISPLAY_PROGRESS();
779                 }
780
781                 dmesg("%d: created %d files, last file '%s'.\n",
782                       myrank, nops, filename);
783                 break;
784 #ifdef HAVE_MDC_LOOKUP
785         case LOOKUP:
786                 fd = open(dir, O_RDONLY);
787                 if (fd < 0) {
788                         fatal(myrank, "open(dir == '%s') error: %s\n",
789                               dir, strerror(errno));
790                 }
791
792                 for (; nops < iters && !alarm_caught;) {
793                         char *filename = next_file();
794                         rc = llapi_file_lookup(fd, filename);
795                         if (rc < 0) {
796                                 if (((rc = errno) == EINTR) && alarm_caught)
797                                         break;
798                                 fatal(myrank, "llapi_file_lookup(%s) "
799                                       "error: %s\n", filename, strerror(rc));
800                         }
801
802                         nops++;
803                         DISPLAY_PROGRESS();
804                 }
805                 break;
806 #endif
807         case MKNOD:
808                 for (; begin <= end && !alarm_caught; begin += dirthreads) {
809                         snprintf(filename, sizeof(filename), filefmt, begin);
810                         rc = mknod(filename, S_IFREG | 0644, 0);
811                         if (rc) {
812                                 rc = errno;
813                                 if (rc == EINTR && alarm_caught)
814                                         break;
815                                 fatal(myrank, "mknod(%s) error: %s\n",
816                                       filename, strerror(rc));
817                         }
818
819                         if (with_xattr) {
820                                 rc = setxattr(filename, xattrname, xattrbuf,
821                                               xattrlen, XATTR_CREATE);
822                                 if (rc) {
823                                         rc = errno;
824                                         if (rc == EINTR && alarm_caught)
825                                                 break;
826                                         fatal(myrank,
827                                               "setxattr(%s) error: %s\n",
828                                               filename, strerror(rc));
829                                 }
830                         }
831
832                         nops++;
833                         DISPLAY_PROGRESS();
834                 }
835                 break;
836         case OPEN:
837                 for (; nops < iters && !alarm_caught;) {
838                         file = next_file();
839                         if ((fd = open(file, openflags, 0644)) < 0) {
840                                 if (((rc = errno) == EINTR) && alarm_caught)
841                                         break;
842                                 fatal(myrank, "open(%s) error: %s\n",
843                                       file, strerror(rc));
844                         }
845
846                         close(fd);
847
848                         nops++;
849                         DISPLAY_PROGRESS();
850                 }
851                 break;
852         case STAT:
853                 for (; begin <= end && !alarm_caught; begin += dirthreads) {
854                         sprintf(filename, filefmt, begin);
855                         rc = stat(filename, &statbuf);
856                         if (rc) {
857                                 if (((rc = errno) == EINTR) && alarm_caught)
858                                         break;
859                                 if (((rc = errno) == ENOENT) && ignore)
860                                         continue;
861                                 fatal(myrank, "stat(%s) error: %s\n",
862                                       filename, strerror(rc));
863                         }
864
865                         nops++;
866                         DISPLAY_PROGRESS();
867                 }
868                 break;
869         case UNLINK:
870                 for (; begin <= end && !alarm_caught; begin += dirthreads) {
871                         sprintf(filename, filefmt, begin);
872                         rc = unlink(filename);
873                         if (rc) {
874                                 if (((rc = errno) == EINTR) && alarm_caught)
875                                         break;
876                                 if ((rc = errno) == ENOENT) {
877                                         if (ignore)
878                                                 continue;
879                                         /* no more files to unlink */
880                                         break;
881                                 }
882                                 fatal(myrank, "unlink(%s) error: %s\n",
883                                       filename, strerror(rc));
884                         }
885
886                         nops++;
887                         DISPLAY_PROGRESS();
888                 }
889                 break;
890         case SETXATTR:
891                 for (; begin <= end && !alarm_caught; begin += dirthreads) {
892                         snprintf(filename, sizeof(filename), filefmt, begin);
893                         rc = setxattr(filename, xattrname, xattrbuf, xattrlen,
894                                       XATTR_CREATE);
895                         if (rc) {
896                                 rc = errno;
897                                 if (rc == EINTR && alarm_caught)
898                                         break;
899                                 if (rc == ENOENT && ignore)
900                                         continue;
901                                 fatal(myrank, "setxattr(%s) error: %s\n",
902                                       filename, strerror(rc));
903                         }
904
905                         nops++;
906                         DISPLAY_PROGRESS();
907                 }
908                 break;
909         }
910
911         rc = MPI_Barrier(MPI_COMM_WORLD);
912         if (rc != MPI_SUCCESS)
913                fatal(myrank, "prep MPI_Barrier failed: %d\n", rc);
914         curTime = MPI_Wtime();
915         interval = curTime - startTime;
916         rate = (double) (nops) / interval;
917
918         rc = MPI_Reduce(&nops, &ag_ops, 1, MPI_INT, MPI_SUM, 0,
919                         MPI_COMM_WORLD);
920         if (rc != MPI_SUCCESS) {
921                 fatal(myrank, "Failure in MPI_Reduce of total ops.\n");
922         }
923
924         rc = MPI_Reduce(&interval, &ag_interval, 1, MPI_DOUBLE, MPI_SUM, 0,
925                         MPI_COMM_WORLD);
926         if (rc != MPI_SUCCESS) {
927                 fatal(myrank, "Failure in MPI_Reduce of total interval.\n");
928         }
929
930         rc = MPI_Reduce(&rate, &ag_rate, 1, MPI_DOUBLE, MPI_SUM, 0,
931                         MPI_COMM_WORLD);
932         if (rc != MPI_SUCCESS) {
933                 fatal(myrank, "Failure in MPI_Reduce of aggregated rate.\n");
934         }
935
936         if (myrank == 0) {
937                 curTime = MPI_Wtime();
938                 interval = curTime - startTime;
939                 effective_rate = (double) ag_ops / interval;
940                 avg_rate = (double) ag_ops / ag_interval;
941
942                 printf("Rate: %.2f eff %.2f aggr %.2f avg client %ss/sec "
943                        "(total: %d threads %d %ss %d dirs %d threads/dir %.2f secs)\n",
944                        effective_rate, ag_rate, avg_rate, cmd, nthreads, ag_ops,
945                        cmd, ndirs, dirthreads, interval);
946                 if (mode == UNLINK && !recreate && !ignore && ag_ops != nfiles)
947                         printf("Warning: only unlinked %d files instead of %d"
948                                "\n", ag_ops, nfiles);
949         }
950
951         if (recreate) {
952                 for (begin = beginsave; begin <= end; begin += dirthreads) {
953                         sprintf(filename, filefmt, begin);
954                         if ((fd = open(filename, openflags, 0644)) < 0) {
955                                 rc = errno;
956                                 if (rc == EEXIST)
957                                         break;
958                                 fatal(myrank, "recreate open(%s) error: %s\n",
959                                       filename, strerror(rc));
960                         }
961
962                         close(fd);
963                 }
964         }
965
966         timestamp = time(0);
967         if ((myrank == 0) || debug) {
968                 printf("%d: %s finished at %s",
969                        myrank, hostname, ctime(&timestamp));
970         }
971
972         MPI_Finalize();
973         return(0);
974 }