From: grev Date: Fri, 3 Apr 2009 17:28:16 +0000 (+0000) Subject: b=18404 X-Git-Tag: v1_9_167~38 X-Git-Url: https://git.whamcloud.com/?a=commitdiff_plain;h=c6487db2289053b4092ee975f4364562bae3526c;p=fs%2Flustre-release.git b=18404 o=Adilger i=grev i=Johann write-append-truncate cleanup --- diff --git a/lustre/tests/write_append_truncate.1 b/lustre/tests/write_append_truncate.1 new file mode 100644 index 0000000..4006f98 --- /dev/null +++ b/lustre/tests/write_append_truncate.1 @@ -0,0 +1,109 @@ +.\" Copyright 2008 Sun Microsystems, Inc. All rights reserved +.\" Use is subject to license terms. +.\" +.\" Author: Andreas Dilger +.TH write_append_truncate 1 "Oct 29, 2008" Lustre "utilities" +.SH NAME +write_append_truncate \- MPI test of concurrent file operation coherency +.SH SYNOPSIS +.B write_append_truncate +.RB [ -a +.IR append_max ] +.RB [ -C ] +.RB [ -n +.IR nloops ] +.RB [ -s +.IR seed ] +.RB [ -t +.IR trunc_max ] +.RB [ -T ] +.RB [ -w +.IR write_max ] +.RB [ -W ] +.I filename +.I ... +.SH DESCRIPTION +The +.B write_append_truncate +program does data coherency testing for parallel filesystem using +.BR mpi (7) +to launch and co-ordinate processes. It runs multiple parallel +processes on one or more nodes, as specified to +.BR mpirun (1), +.BR pdsh (1), +or other MPI job launcher, each operating on the same shared file. +.sp +The master process creates +.I filename +if it does not exist +.I +For each of the +.I num_loops +test iterations one process truncates the file to zero size and writes +a random number of check bytes, +.BR W +between 1 and +.I write_max +to +.IR filename . +.sp +Other processes wait on an MPI barrier until +this is complete. One of the processes is chosen, to do an append +.RB ( write (2) +with +.BR O_APPEND ) of +a random size, +.BR A , +between 1 and +.I append_max +bytes to the end of the file. A second process does a concurrent +.BR truncate (2) +operation on the file to a random size, +.BR W + T , +between 1 and +.I trunc_max +bytes beyond the end of the initial +.B W +bytes data. This truncate will either extend the file size if it is +done before the append, or it will truncate the file if it is done +after the append. +.sp +A second MPI barrier ensures both of the processes have completed +their respective operations, and then the master process reads the entire +file and verifies the contents. +.sp +The beginning of the file is verified to contain the +.B W +check bytes up to the offset it was initially filled to. +.br +If the file size is equal to the truncated size, +.BR W + T , +then the truncate operation was done +.I after +the append and the data beyond the initial write offset +.BR W +to the end of file +.BR W + T +should contain the +.B A +bytes of append check data, and possibly a zero-filled hole at the +end of the file if +.B T +is larger than +.BR A . +.sp +Otherwise, the truncate operation was done +.I before +the append and the data beyond the initial write offset +.B W +to the truncate offset +.BR W + T +should be a zero-filled hole. Beyond the hole to the end of file +there should be +.B A +bytes of append check data. The total file size should be +.BR W " + " T " + " A . +.LP +.SH SEE ALSO +.BR mpirun (1) +.BR pdsh (1) diff --git a/lustre/tests/write_append_truncate.c b/lustre/tests/write_append_truncate.c index 24f9043..bae9ba4 100644 --- a/lustre/tests/write_append_truncate.c +++ b/lustre/tests/write_append_truncate.c @@ -37,13 +37,13 @@ * * Each loop does 3 things: * - truncate file to zero (not via ftruncate though, to test O_APPEND) - * - append a "chunk" of data (should be at file offset 0 after truncate) + * - write a "chunk" of data (should be at file offset 0 after truncate) * - on each of two threads either append or truncate-up the file * * If the truncate happened first, we should have a hole in the file. * If the append happened first, we should have truncated the file down. * - * We pick the CHUNK_SIZE_MAX and APPEND_SIZE_MAX so that we cross a stripe. + * WRITE_SIZE_MAX and APPEND_SIZE_MAX are large enough to cross a stripe. * * compile: mpicc -g -Wall -o write_append_truncate write_append_truncate.c * run: mpirun -np 2 -machlist write_append_truncate @@ -58,62 +58,98 @@ #include #include #include +#include #include #include +#include #include "mpi.h" -#define DEFAULT_ITER 50000 +#define DEFAULT_ITER 10000 -#define CHUNK_SIZE_MAX 123456 -#define CHUNK_CHAR 'C' +#define WRITE_SIZE_MAX 1234567 +#define APPEND_SIZE_MAX 1234567 +#define TRUNC_SIZE_MAX 1234567 -#define APPEND_SIZE_MAX 123456 -#define APPEND_CHAR 'A' - -#define TRUNC_SIZE_MAX (CHUNK_SIZE_MAX+APPEND_SIZE_MAX) +#define STATUS_FMT "WR %c %7d/%#08x, AP %c %7d/%#08x, TR@ %7d/%#08x" #define HOSTNAME_SIZE 50 +char hostname[HOSTNAME_SIZE]; +#define FNAMES_MAX 256 void usage(char *prog) { - printf("usage: %s [nloops]\n", prog); - printf("%s must be run with at least 2 processes\n", prog); + printf("usage: %s [-a append_max] [-C] [-n nloops] [-s seed]\n" + "\t\t[-t trunc_max] [-T] [-v] [-w write_max] ...\n", prog); + printf("\t-a append_max: maximum size of append, default %u bytes\n", + APPEND_SIZE_MAX); + printf("\t-C: 'classic' checks (on file 0)\n"); + printf("\t-n nloops: count of loops to run, default %u\n",DEFAULT_ITER); + printf("\t-s seed: random seed to use, default {current time}\n"); + printf("\t-t trunc_max: maximum size of truncate, default %u bytes\n", + TRUNC_SIZE_MAX); + printf("\t-T: 'classic' truncates (on file 0)\n"); + printf("\t-w write_max: maximum size of write, default %u bytes\n", + WRITE_SIZE_MAX); + printf("\t-W: 'classic' writes (on rank 0, file 0)\n"); + printf("\t-v: run in verbose mode (repeat for more verbosity)\n"); + printf("\tfilename for each mountpoint of same filesystem on a node\n"); + printf("\b%s must be run with at least 2 processes\n", prog); MPI_Finalize(); exit(1); } /* Print process rank, loop count, message, and exit (i.e. a fatal error) */ -void rprintf(int rank, int loop, const char *fmt, ...) +void rprintf(int rank, int loop, int error, const char *fmt, ...) +__attribute__ ((format (printf, 4, 5))); + +void rprintf(int rank, int loop, int error, const char *fmt, ...) { va_list ap; - printf("rank %d, loop %d: ", rank, loop); + printf("r=%2u", rank); + if (loop >= 0) + printf(" l=%04u", loop); + if (error != 0) + printf(" %s", hostname); + printf(": "); va_start(ap, fmt); vprintf(fmt, ap); - MPI_Abort(MPI_COMM_WORLD, -1); + if (error != 0) + MPI_Abort(MPI_COMM_WORLD, error); } int main(int argc, char *argv[]) { - int n, nloops = 0, fd; - int rank, size, ret; - int chunk_size, append_size, trunc_offset; - char append_buf[APPEND_SIZE_MAX]; - char chunk_buf[CHUNK_SIZE_MAX]; - char read_buf[TRUNC_SIZE_MAX+APPEND_SIZE_MAX]; - char trunc_buf[TRUNC_SIZE_MAX]; + int n, nloops = DEFAULT_ITER; + int nfnames = 0, ifnames, fd; + int rank = -1, nproc, ret; + unsigned write_max = WRITE_SIZE_MAX; + unsigned append_max = APPEND_SIZE_MAX; + unsigned write_size = 0, append_size = 0, trunc_size = 0; + unsigned trunc_max = 0, trunc_offset = 0; + char *append_buf; + char *write_buf; + char *read_buf = NULL; + char *trunc_buf = NULL; + int seed = time(0); int done; int error; - char hostname[HOSTNAME_SIZE]; - char *fname, *prog; + int verbose = 0; + int classic_check = 0, classic_trunc = 0, classic_write = 0; + char write_char = 'A', append_char = 'a'; + char *fnames[FNAMES_MAX], *end; + char *prog = "write_append_truncate"; + int c; error = MPI_Init(&argc, &argv); if (error != MPI_SUCCESS) - rprintf(-1, -1, "MPI_Init failed: %d\n", error); + printf("%s: MPI_Init failed: %d\n", prog, error); + else if (verbose > 2) + printf("%s: MPI_Init succeeded\n", prog); prog = strrchr(argv[0], '/'); if (prog == NULL) @@ -121,199 +157,399 @@ int main(int argc, char *argv[]) else prog++; - if (argc < 2 || argc > 3) + while ((c = getopt(argc, argv, "a:cCn:s:t:Tvw:W")) != -1) { + switch(c) { + case 'a': + append_max = strtoul(optarg, &end, 0); + if (append_max == 0 || *end) { + fprintf(stderr, "%s: bad append option '%s'\n", + prog, optarg); + usage(prog); + } + break; + case 'C': + classic_check++; + break; + case 'n': + nloops = strtoul(optarg, &end, 0); + if (nloops == 0 || *end) { + fprintf(stderr, "%s: bad nloops option '%s'\n", + prog, optarg); + usage(prog); + } + break; + case 's': + seed = strtoul(optarg, &end, 0); + if (*end) { + fprintf(stderr, "%s: bad seed option '%s'\n", + prog, optarg); + usage(prog); + } + break; + case 't': + trunc_max = strtoul(optarg, &end, 0); + if (*end) { + fprintf(stderr,"%s: bad truncate option '%s'\n", + prog, optarg); + usage(prog); + } + break; + case 'T': + classic_trunc++; + break; + case 'v': + verbose++; + break; + case 'w': + write_max = strtoul(optarg, &end, 0); + if (write_max == 0 || *end) { + fprintf(stderr, "%s: bad write option '%s'\n", + prog, optarg); + usage(prog); + } + break; + case 'W': + classic_write++; + break; + default: + fprintf(stderr, "%s: unknown option '%c'\n", prog, c); + usage(prog); + } + } + + srand(seed); + + if (argc == optind) { + fprintf(stderr, "%s: missing filename argument\n", prog); + usage(prog); + } + + if (argc > optind + FNAMES_MAX) { + fprintf(stderr, "%s: too many extra options\n", prog); usage(prog); + } + + while (optind < argc) + fnames[nfnames++] = argv[optind++]; error = MPI_Comm_rank(MPI_COMM_WORLD, &rank); - if (error != MPI_SUCCESS) - rprintf(-1, -1, "MPI_Comm_rank failed: %d\n", error); + if (verbose > 2 || error != MPI_SUCCESS) + rprintf(rank, -1, error != MPI_SUCCESS, "MPI_Comm_rank: %d\n", + error); - error = MPI_Comm_size(MPI_COMM_WORLD, &size); - if (error != MPI_SUCCESS) - rprintf(rank, -1, "MPI_Comm_size failed: %d\n", error); + error = MPI_Comm_size(MPI_COMM_WORLD, &nproc); + if (verbose > 2 || error != MPI_SUCCESS) + rprintf(rank, -1, error != MPI_SUCCESS, "MPI_Comm_size: %d\n", + error); - if (size < 2) - rprintf(rank, -1, "%s: must run with at least 2 processes\n", + if (nproc < 2) + rprintf(rank, -1, 1, "%s: must run with at least 2 processes\n", prog); - memset(append_buf, APPEND_CHAR, APPEND_SIZE_MAX); - memset(chunk_buf, CHUNK_CHAR, CHUNK_SIZE_MAX); - memset(trunc_buf, 0, TRUNC_SIZE_MAX); + append_buf = malloc(append_max); + if (append_buf == NULL) + rprintf(rank, -1, 1,"%s: error allocating append_buf %u\n", + prog, append_max); - if (gethostname(hostname, HOSTNAME_SIZE) < 0) - rprintf(rank, -1, "gethostname failed: %s\n", strerror(errno)); - - fname = argv[1]; + write_buf = malloc(write_max); + if (write_buf == NULL) + rprintf(rank, -1, 1, "%s: error allocating write_buf %u\n", + prog, write_max); - if (argc == 3) - nloops = strtoul(argv[2], NULL, 0); - if (nloops == 0) - nloops = DEFAULT_ITER; + if (gethostname(hostname, HOSTNAME_SIZE) < 0) + rprintf(rank, -1, 1, "%s: gethostname failed: %s\n", + prog, strerror(errno)); if (rank == 0) { - fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666); - if (fd < 0) - rprintf(0, -1, "create %s failed: %s\n", fname, - strerror(errno)); - printf("using %s\n", fname); + int max_size = write_max + (trunc_max ?: append_max)+append_max; + + fd = open(fnames[0], O_WRONLY|O_CREAT|O_TRUNC, 0666); + rprintf(rank,-1, fd<0, "create %s, max size: %u, seed %u: %s\n", + fnames[0], max_size, seed, strerror(errno)); + close(fd); + + trunc_buf = calloc(1, trunc_max ?: append_max); + if (trunc_buf == NULL) + rprintf(rank,-1,1,"%s: error allocating trunc_buf %u\n", + prog, trunc_max ?: append_max); + + /* initial write + truncate up + append */ + read_buf = malloc(max_size); + if (read_buf == NULL) + rprintf(rank,-1,1,"%s: error allocating read_buf %u\n", + prog, max_size); } + error = MPI_Barrier(MPI_COMM_WORLD); - if (error != MPI_SUCCESS) - rprintf(rank, -1, "prep MPI_Barrier failed: %d\n", error); + if (verbose > 2 || error != MPI_SUCCESS) + rprintf(rank, -1, error != MPI_SUCCESS, + "prep MPI_Barrier: %d\n", error); - fd = open(fname, O_RDWR | O_APPEND); - if (fd < 0) - rprintf(rank, -1, "open %s failed: %s\n",fname,strerror(errno)); + ifnames = rank % nfnames; + fd = open(fnames[ifnames], O_RDWR | O_APPEND); + if (verbose || fd < 0) + rprintf(rank, -1, errno, "open '%s' (%u): %s\n", + fnames[ifnames], ifnames, strerror(errno)); for (n = 0; n < nloops; n++) { + /* Initialized only to quiet stupid GCC warnings */ + unsigned write_rank = 0, append_rank = n, trunc_rank = n + 1; + unsigned mpi_shared_vars[6]; + /* reset the environment */ - chunk_size = (rand()%(CHUNK_SIZE_MAX-1))+1; - append_size = (rand()%(APPEND_SIZE_MAX-1))+1; - trunc_offset = chunk_size + rand()%append_size; + write_char = 'A' + (n % 26); + append_char = 'a' + (n % 26); + if (rank == 0) { - if (n % 1000 == 0) - printf("loop %5d: chunk %6d/%#07x, " - "append %6d/%#07x, trunc @ %6d/%#07x\n", - n, chunk_size, chunk_size, append_size, - append_size, trunc_offset, trunc_offset); - - ret = truncate(fname, (off_t)0); - if (ret < 0) - rprintf(0, n, "truncate @ 0: %s\n", + write_size = (rand() % (write_max - 1)) + 1; + append_size = (rand() % (append_max - 1)) + 1; + trunc_size = (rand() % ((trunc_max?: append_size)-1))+1; + trunc_offset = write_size + trunc_size; + + if (verbose || n % 1000 == 0) + rprintf(rank, n, 0, STATUS_FMT"\n", + write_char, write_size, write_size, + append_char, append_size, append_size, + trunc_offset, trunc_offset); + + write_rank = (classic_write ? 0 : rand()) % nproc; + do { + append_rank = (classic_write ? n : rand()) % + nproc; + /* We can't allow the append rank be the same + * as the classic_trunc trunc_rank, or we will + * spin here forever. */ + } while (append_rank == (n + 1) % nproc); + do { + trunc_rank = (classic_trunc? (n + 1) : rand()) % + nproc; + } while (trunc_rank == append_rank); + + mpi_shared_vars[0] = write_size; + mpi_shared_vars[1] = append_size; + mpi_shared_vars[2] = trunc_size; + mpi_shared_vars[3] = write_rank; + mpi_shared_vars[4] = append_rank; + mpi_shared_vars[5] = trunc_rank; + } + + error = MPI_Bcast(&mpi_shared_vars, 6, + MPI_INT, 0, MPI_COMM_WORLD); + if (verbose > 2 || error != MPI_SUCCESS) + rprintf(rank, n, error != MPI_SUCCESS, + "MPI_Bcast mpi_shared_vars" + "[%u, %u, %u, %u, %u, %u]: %d\n", + mpi_shared_vars[0], mpi_shared_vars[1], + mpi_shared_vars[2], mpi_shared_vars[3], + mpi_shared_vars[4], mpi_shared_vars[5], error); + + if (rank != 0) { + write_size = mpi_shared_vars[0]; + append_size = mpi_shared_vars[1]; + trunc_size = mpi_shared_vars[2]; + write_rank = mpi_shared_vars[3]; + append_rank = mpi_shared_vars[4]; + trunc_rank = mpi_shared_vars[5]; + + trunc_offset = write_size + trunc_size; + } + + if (rank == write_rank || rank == 0) + memset(write_buf, write_char, write_max); + + if (rank == write_rank) { + ifnames = (classic_write ? 0 : rand()) % nfnames; + ret = truncate(fnames[ifnames], 0); + if (verbose > 1 || ret != 0) + rprintf(rank, n, ret, + "initial truncate %s (%u) @ 0: %s\n", + fnames[ifnames], ifnames, strerror(errno)); + done = 0; do { - ret = write(fd, chunk_buf+done,chunk_size-done); - if (ret <= 0) { - rprintf(0, n, "chunk @ %d: %s\n", - done, strerror(errno)); - break; + ret = write(fd, write_buf+done,write_size-done); + if (verbose > 1 || ret <= 0) { + rprintf(rank, n, ret <= 0, + "write %d/%d @ %d: %s\n", + ret + done, write_size, done, + strerror(errno)); + if (ret <= 0) + break; } done += ret; - } while (done != chunk_size); + } while (done != write_size); } + if (rank == append_rank || rank == 0) + memset(append_buf, append_char, append_size); + error = MPI_Barrier(MPI_COMM_WORLD); - if (error != MPI_SUCCESS) - rprintf(rank, n, "start MPI_Barrier: %d\n",error); + if (verbose > 2 || error != MPI_SUCCESS) + rprintf(rank, n, error != MPI_SUCCESS, + "start MPI_Barrier: %d\n", error); /* Do the race */ - if (rank == n % size) { - // + if (rank == append_rank) { done = 0; do { ret = write(fd, append_buf + done, append_size - done); if (ret < 0) { - rprintf(rank, n, - "loop %d: append @ %u: %s\n", - done, strerror(errno)); + rprintf(rank, n, ret < 0, + "append %u/%u: %s\n", + ret + done, append_size, + strerror(errno)); break; + } else if (verbose > 1 || ret != append_size) { + rprintf(rank, n, ret != append_size, + "append %u/%u\n", + ret + done, append_size); } done += ret; } while (done != append_size); - } else if (rank == (n + 1) % size) { - ret = truncate(fname, (off_t)trunc_offset); - if (ret != 0) - rprintf(rank, n, "truncate @ %u: %s\n", - trunc_offset, strerror(errno) ); + } else if (rank == trunc_rank) { + /* XXX: truncating the same file descriptor as the + * append on a single node causes this test + * to fail currently (2009-02-01). */ + ifnames = (classic_trunc ? rank : rand()) % nfnames; + ret = truncate(fnames[ifnames], trunc_offset); + if (verbose > 1 || ret != 0) + rprintf(rank, n, ret, + "truncate %s (%u) @ %u: %s\n", + fnames[ifnames], ifnames, + trunc_offset, strerror(errno)); } error = MPI_Barrier(MPI_COMM_WORLD); - if (error != MPI_SUCCESS) - rprintf(rank, n, "end MPI_Barrier: %d\n", error); + if (verbose > 2 || error != MPI_SUCCESS) + rprintf(rank, n, error != MPI_SUCCESS, + "end MPI_Barrier: %d\n", error); error = 0; /* Check the result */ if (rank == 0) { - struct stat st; - if (stat(fname, &st) < 0) - rprintf(0, n, "loop %d: stat %s: %s\n", - fname, strerror(errno)); - - if (lseek(fd, (off_t)0, SEEK_SET) != 0) - rprintf(0, n, "lseek fname 0: %s\n", fname, + char *tmp_buf; + struct stat st = { 0 }; + + ifnames = classic_check ? 0 : (rand() % nfnames); + ret = stat(fnames[ifnames], &st); + if (verbose > 1 || ret != 0) + rprintf(rank, n, ret, + "stat %s (%u) size %llu: %s\n", + fnames[ifnames], ifnames, + (long long)st.st_size, strerror(errno)); + + ret = lseek(fd, 0, SEEK_SET); + if (ret != 0) + rprintf(rank, n, ret, "lseek 0: %s\n", strerror(errno)); done = 0; do { ret = read(fd, read_buf+done, st.st_size-done); - if (ret < 0) { - rprintf(0, n, "read @ %u: %s\n", - done, strerror(errno)); + if (verbose > 1 || ret <= 0) { + rprintf(rank, n, ret <= 0, + "read %d/%llu @ %u: %s\n", + ret, (long long)st.st_size-done, + done, ret != 0 ? + strerror(errno) : "short read"); } done += ret; } while (done != st.st_size); - if (memcmp(read_buf, chunk_buf, chunk_size)) { - printf("loop %d: base chunk bad" - " [0-%d]/[0-%#x] != %c\n", n, - chunk_size - 1, chunk_size - 1, - CHUNK_CHAR); + if (memcmp(read_buf, write_buf, write_size)) { + rprintf(rank, n, 0, "WRITE bad " + "[0-%d]/[0-%#x] != %c\n", + write_size - 1, write_size - 1, + write_char); error = 1; } + tmp_buf = read_buf + write_size; + if (st.st_size == trunc_offset) { /* Check case 1: first append then truncate */ - error = memcmp(read_buf+chunk_size, append_buf, - trunc_offset - chunk_size); - if (error) { - printf("loop %d: trunc-after-append bad" - " [%d-%d]/[%#x-%#x] != %c\n", - n, chunk_size, trunc_offset - 1, - chunk_size, trunc_offset - 1, - APPEND_CHAR); + int tmp_size, tmp_offset; + + tmp_size = trunc_size < append_size ? + trunc_size : append_size; + tmp_offset = write_size + tmp_size; + + if (memcmp(tmp_buf, append_buf, tmp_size)) { + rprintf(rank, n, 0,"trunc-after-APPEND " + "bad [%d-%d]/[%#x-%#x] != %c\n", + write_size, tmp_offset - 1, + write_size, tmp_offset - 1, + append_char); + error = 1; + } else if (trunc_size > append_size && + memcmp(tmp_buf+append_size,trunc_buf, + trunc_size - append_size)) { + rprintf(rank, n, 0,"TRUNC-after-append " + "bad [%d-%d]/[%#x-%#x] != 0\n", + tmp_offset, trunc_offset - 1, + tmp_offset, trunc_offset - 1); + error = 1; } } else { + int expected_size = trunc_offset + append_size; /* Check case 2: first truncate then append */ - if (memcmp(read_buf+chunk_size, trunc_buf, - trunc_offset-chunk_size)) { - printf("loop %d: append-after-TRUNC bad" - " [%d-%d]/[%#x-%#x] != 0\n", - n, chunk_size, trunc_offset - 1, - chunk_size, trunc_offset - 1); + if (st.st_size != expected_size) { + rprintf(rank, n, 0,"APPEND-after-trunc " + "bad file size %llu != %u\n", + (long long)st.st_size, + expected_size); error = 1; - } else if (memcmp(read_buf+trunc_offset, + } + + if (memcmp(tmp_buf, trunc_buf, trunc_size)) { + rprintf(rank, n, 0,"append-after-TRUNC " + "bad [%d-%d]/[%#x-%#x] != 0\n", + write_size, trunc_offset - 1, + write_size, trunc_offset - 1); + error = 1; + } else if (memcmp(read_buf + trunc_offset, append_buf, append_size)) { - printf("loop %d: APPEND-after-trunc bad" - " [%d-%d]/[%#x-%#x] != %c\n", - n, trunc_offset, append_size - 1, - trunc_offset, append_size - 1, - APPEND_CHAR); + rprintf(rank, n, 0,"APPEND-after-trunc " + "bad [%d-%d]/[%#x-%#x] != %c\n", + trunc_offset, expected_size - 1, + trunc_offset, expected_size - 1, + append_char); error = 1; } } - } - ret = MPI_Bcast(&error, 1, MPI_INT, 0, MPI_COMM_WORLD); - if (ret != MPI_SUCCESS) - rprintf(rank, n, "MPI_Bcast: %d\n"); - if (error == 1) { - if (rank == 0) { + if (error == 1) { char command[4096]; - printf("loop %5d: chunk %6d/%#07x, " - "append %6d/%#07x, trunc @ %6d/%#07x\n", - n, chunk_size, chunk_size, append_size, - append_size, trunc_offset, trunc_offset); + rprintf(rank, n, 0, STATUS_FMT"\n", + write_char, write_size, write_size, + append_char, append_size, append_size, + trunc_offset, trunc_offset); - sprintf(command, "od -Ax -a %s", fname); + sprintf(command, "od -Ax -a %s", fnames[0]); system(command); + MPI_Abort(MPI_COMM_WORLD, 1); } - rprintf(rank, n, "on machine %s with pid %d\n", - hostname, (int)getpid()); } } - printf("rank %d, loop %d: finished\n", rank, n); + if (rank == 0 || verbose) + printf("r=%2u n=%4u: "STATUS_FMT"\nPASS\n", rank, n - 1, + write_char, write_size, write_size, + append_char, append_size, append_size, + trunc_offset, trunc_offset); + close(fd); if (rank == 0) { - error = unlink(fname); - if (error < 0) - rprintf(0, n, "unlink %s failed: %s\n", - fname, strerror(errno)); + ifnames = rand() % nfnames; + ret = unlink(fnames[ifnames]); + if (ret != 0) + printf("%s: unlink %s failed: %s\n", + prog, fnames[ifnames], strerror(errno)); } MPI_Finalize();