From: Nathan Scott Date: Fri, 11 Nov 2005 14:25:18 +0000 (+0000) Subject: Provide further debugging options and tweaks for analysing the read/write paths. X-Git-Tag: v2.8.0~70 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8fb2237e65555ff540e8b6108ffccfffefe239ac;p=thirdparty%2Fxfsprogs-dev.git Provide further debugging options and tweaks for analysing the read/write paths. Merge of master-melb:xfs-cmds:24372a by kenmcd. --- diff --git a/io/bmap.c b/io/bmap.c index 7e5edb742..0d9d7568f 100644 --- a/io/bmap.c +++ b/io/bmap.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -277,7 +277,6 @@ bmap_f( #define MINRANGE_WIDTH 16 #define MINAG_WIDTH 2 #define MINTOT_WIDTH 5 -#define max(a,b) (a > b ? a : b) #define NFLG 5 /* count of flags */ #define FLG_NULL 000000 /* Null flag */ #define FLG_PRE 010000 /* Unwritten extent */ diff --git a/io/io.h b/io/io.h index 997452f9d..c827298ed 100644 --- a/io/io.h +++ b/io/io.h @@ -30,6 +30,16 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ +/* + * Read/write patterns (default is always "forward") + */ +#define IO_RANDOM ( 0) +#define IO_FORWARD ( 1) +#define IO_BACKWARD (-1) + +/* + * File descriptor options + */ #define IO_READONLY (1<<0) #define IO_DIRECT (1<<1) #define IO_REALTIME (1<<2) diff --git a/io/pread.c b/io/pread.c index 14dc3a0e3..f3b820efb 100644 --- a/io/pread.c +++ b/io/pread.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2004 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2003-2005 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -52,7 +52,18 @@ pread_help(void) " Reads a segment of the currently open file, optionally dumping it to the\n" " standard output stream (with -v option) for subsequent inspection.\n" " The reads are performed in sequential blocks starting at offset, with the\n" -" blocksize tunable using the -b option (default blocksize is 4096 bytes).\n" +" blocksize tunable using the -b option (default blocksize is 4096 bytes),\n" +" unless a different pattern is requested.\n" +" -B -- read backwards through the range from offset (backwards N bytes)\n" +" -F -- read forwards through the range of bytes from offset (default)\n" +" -v -- be verbose, dump out buffers (used when reading forwards)\n" +" -R -- read at random offsets in the range of bytes\n" +" -Z N -- zeed the random number generator (used when reading randomly)\n" +" (heh, zorry, the -s/-S arguments were already in use in pwrite)\n" +" When in \"random\" mode, the number of read operations will equal the\n" +" number required to do a complete forward/backward scan of the range.\n" +" Note that the offset within the range is chosen at random each time\n" +" (an offset may be read more than once when operating in this mode).\n" "\n")); } @@ -108,21 +119,126 @@ dump_buffer( } } -int -read_buffer( +static int +read_random( + int fd, + off64_t offset, + long long count, + long long *total, + unsigned int seed, + int eof) +{ + off64_t end, off, range; + ssize_t bytes; + int ops = 0; + + srandom(seed); + end = lseek64(fd, 0, SEEK_END); + offset = (eof || offset > end) ? end : offset; + if ((bytes = (offset % buffersize))) + offset -= bytes; + offset = max(0, offset); + if ((bytes = (count % buffersize))) + count += bytes; + count = max(buffersize, count); + range = count - buffersize; + + *total = 0; + while (count > 0) { + off = ((random() % range) / buffersize) * buffersize; + bytes = pread64(fd, buffer, buffersize, off); + if (bytes == 0) + break; + if (bytes < 0) { + perror("pread64"); + return -1; + } + ops++; + *total += bytes; + if (bytes < buffersize) + break; + count -= bytes; + } + return ops; +} + +static int +read_backward( + int fd, + off64_t *offset, + long long *count, + long long *total, + int eof) +{ + off64_t end, off = *offset; + ssize_t bytes = 0, bytes_requested; + long long cnt = *count; + int ops = 0; + + end = lseek64(fd, 0, SEEK_END); + off = eof ? end : min(end, lseek64(fd, off, SEEK_SET)); + if ((end = off - cnt) < 0) { + cnt += end; /* subtraction, end is negative */ + end = 0; + } + *total = 0; + *count = cnt; + *offset = off; + + /* Do initial unaligned read if needed */ + if ((bytes_requested = (off % buffersize))) { + bytes_requested = min(cnt, bytes_requested); + off -= bytes_requested; + bytes = pread(fd, buffer, bytes_requested, off); + if (bytes == 0) + return ops; + if (bytes < 0) { + perror("pread64"); + return -1; + } + ops++; + *total += bytes; + if (bytes < bytes_requested) + return ops; + cnt -= bytes; + } + + /* Iterate backward through the rest of the range */ + while (cnt > end) { + bytes_requested = min(cnt, buffersize); + off -= bytes_requested; + bytes = pread64(fd, buffer, bytes_requested, off); + if (bytes == 0) + break; + if (bytes < 0) { + perror("pread64"); + return -1; + } + ops++; + *total += bytes; + if (bytes < bytes_requested) + break; + cnt -= bytes; + } + return ops; +} + +static int +read_forward( int fd, off64_t offset, long long count, long long *total, int verbose, - int onlyone) + int onlyone, + int eof) { size_t bytes_requested; ssize_t bytes; int ops = 0; *total = 0; - while (count > 0) { + while (count > 0 || eof) { bytes_requested = min(count, buffersize); bytes = pread64(fd, buffer, bytes_requested, offset); if (bytes == 0) @@ -143,40 +259,74 @@ read_buffer( return ops; } +int +read_buffer( + int fd, + off64_t offset, + long long count, + long long *total, + int verbose, + int onlyone) +{ + return read_forward(fd, offset, count, total, verbose, onlyone, 0); +} + static int pread_f( int argc, char **argv) { + size_t bsize; off64_t offset; + unsigned int zeed = 0; long long count, total, tmp; - size_t blocksize, sectsize; + unsigned int fsblocksize, fssectsize; struct timeval t1, t2; char s1[64], s2[64], ts[64]; + char *sp; int Cflag, uflag, vflag; + int eof = 0, direction = IO_FORWARD; int c; Cflag = uflag = vflag = 0; - init_cvtnum(&blocksize, §size); - while ((c = getopt(argc, argv, "b:Cuv")) != EOF) { + init_cvtnum(&fsblocksize, &fssectsize); + bsize = fsblocksize; + + while ((c = getopt(argc, argv, "b:BCFRuvZ:")) != EOF) { switch (c) { case 'b': - tmp = cvtnum(blocksize, sectsize, optarg); + tmp = cvtnum(fsblocksize, fssectsize, optarg); if (tmp < 0) { printf(_("non-numeric bsize -- %s\n"), optarg); return 0; } - blocksize = tmp; + bsize = tmp; break; case 'C': Cflag = 1; break; + case 'F': + direction = IO_FORWARD; + break; + case 'B': + direction = IO_BACKWARD; + break; + case 'R': + direction = IO_RANDOM; + break; case 'u': uflag = 1; break; case 'v': vflag = 1; break; + case 'Z': + zeed = strtoul(optarg, &sp, 0); + if (!sp || sp == optarg) { + printf(_("non-numeric seed -- %s\n"), optarg); + return 0; + } + break; default: return command_usage(&pread_cmd); } @@ -184,23 +334,43 @@ pread_f( if (optind != argc - 2) return command_usage(&pread_cmd); - offset = cvtnum(blocksize, sectsize, argv[optind]); - if (offset < 0) { - printf(_("non-numeric offset argument -- %s\n"), argv[optind]); + offset = cvtnum(fsblocksize, fssectsize, argv[optind]); + if (offset < 0 && (direction & (IO_RANDOM|IO_BACKWARD))) { + eof = -1; /* read from EOF */ + } else if (offset < 0) { + printf(_("non-numeric length argument -- %s\n"), argv[optind]); return 0; } optind++; - count = cvtnum(blocksize, sectsize, argv[optind]); - if (count < 0) { + count = cvtnum(fsblocksize, fssectsize, argv[optind]); + if (count < 0 && (direction & (IO_RANDOM|IO_FORWARD))) { + eof = -1; /* read to EOF */ + } else if (count < 0) { printf(_("non-numeric length argument -- %s\n"), argv[optind]); return 0; } - - if (alloc_buffer(blocksize, uflag, 0xabababab) < 0) + if (alloc_buffer(bsize, uflag, 0xabababab) < 0) return 0; gettimeofday(&t1, NULL); - if ((c = read_buffer(file->fd, offset, count, &total, vflag, 0)) < 0) + switch (direction) { + case IO_RANDOM: + if (!zeed) /* srandom seed */ + zeed = time(NULL); + c = read_random(file->fd, offset, count, &total, zeed, eof); + break; + case IO_FORWARD: + c = read_forward(file->fd, offset, count, &total, vflag, 0, eof); + if (eof) + count = total; + break; + case IO_BACKWARD: + c = read_backward(file->fd, &offset, &count, &total, eof); + break; + default: + ASSERT(0); + } + if (c < 0) return 0; gettimeofday(&t2, NULL); t2 = tsub(t2, t1); diff --git a/io/pwrite.c b/io/pwrite.c index 4c644c032..822690505 100644 --- a/io/pwrite.c +++ b/io/pwrite.c @@ -50,17 +50,118 @@ pwrite_help(void) "\n" " Writes into a segment of the currently open file, using either a buffer\n" " filled with a set pattern (0xcdcdcdcd) or data read from an input file.\n" -" -S -- use an alternate seed number\n" -" -i -- specifies an input file from which to source data to write\n" -" -d -- open the input file for direct IO\n" -" -s -- skip a number of bytes at the start of the input file\n" -" -w -- call fdatasync(2) at the end (included in timing results)\n" -" -W -- call fsync(2) at the end (included in timing results)\n" " The writes are performed in sequential blocks starting at offset, with the\n" -" blocksize tunable using the -b option (default blocksize is 4096 bytes).\n" +" blocksize tunable using the -b option (default blocksize is 4096 bytes),\n" +" unless a different write pattern is requested.\n" +" -S -- use an alternate seed number for filling the write buffer\n" +" -i -- input file, source of data to write (used when writing forward)\n" +" -d -- open the input file for direct IO\n" +" -s -- skip a number of bytes at the start of the input file\n" +" -w -- call fdatasync(2) at the end (included in timing results)\n" +" -W -- call fsync(2) at the end (included in timing results)\n" +" -B -- write backwards through the range from offset (backwards N bytes)\n" +" -F -- write forwards through the range of bytes from offset (default)\n" +" -R -- write at random offsets in the specified range of bytes\n" +" -Z N -- zeed the random number generator (used when writing randomly)\n" +" (heh, zorry, the -s/-S arguments were already in use in pwrite)\n" "\n")); } +static int +write_random( + off64_t offset, + long long count, + unsigned int seed, + long long *total) +{ + off64_t off, range; + ssize_t bytes; + int ops = 0; + + srandom(seed); + if ((bytes = (offset % buffersize))) + offset -= bytes; + offset = max(0, offset); + if ((bytes = (count % buffersize))) + count += bytes; + count = max(buffersize, count); + range = count - buffersize; + + *total = 0; + while (count > 0) { + off = ((random() % range) / buffersize) * buffersize; + bytes = pwrite64(file->fd, buffer, buffersize, off); + if (bytes == 0) + break; + if (bytes < 0) { + perror("pwrite64"); + return -1; + } + ops++; + *total += bytes; + if (bytes < buffersize) + break; + count -= bytes; + } + return ops; +} + +static int +write_backward( + off64_t offset, + long long *count, + long long *total) +{ + off64_t end, off = offset; + ssize_t bytes = 0, bytes_requested; + long long cnt = *count; + int ops = 0; + + if ((end = off - cnt) < 0) { + cnt += end; /* subtraction, end is negative */ + end = 0; + } + *total = 0; + *count = cnt; + + /* Do initial unaligned write if needed */ + if ((bytes_requested = (off % buffersize))) { + bytes_requested = min(cnt, bytes_requested); + off -= bytes_requested; + bytes = pwrite(file->fd, buffer, bytes_requested, off); + if (bytes == 0) + return ops; + if (bytes < 0) { + perror("pwrite64"); + return -1; + } + ops++; + *total += bytes; + if (bytes < bytes_requested) + return ops; + cnt -= bytes; + } + + /* Iterate backward through the rest of the range */ + while (cnt > end) { + bytes_requested = min(cnt, buffersize); + off -= bytes_requested; + bytes = pwrite64(file->fd, buffer, bytes_requested, off); + if (bytes == 0) + break; + if (bytes < 0) { + perror("pwrite64"); + return -1; + } + ops++; + *total += bytes; + if (bytes < bytes_requested) + break; + cnt -= bytes; + } + return ops; +} + static int write_buffer( off64_t offset, @@ -104,31 +205,44 @@ pwrite_f( int argc, char **argv) { - size_t blocksize, sectsize; + size_t bsize; off64_t offset, skip = 0; long long count, total, tmp; - unsigned int seed = 0xcdcdcdcd; + unsigned int zeed = 0, seed = 0xcdcdcdcd; + unsigned int fsblocksize, fssectsize; struct timeval t1, t2; char s1[64], s2[64], ts[64]; char *sp, *infile = NULL; int Cflag, uflag, dflag, wflag, Wflag; + int direction = IO_FORWARD; int c, fd = -1; Cflag = uflag = dflag = wflag = Wflag = 0; - init_cvtnum(&blocksize, §size); - while ((c = getopt(argc, argv, "b:Cdf:i:s:S:uwW")) != EOF) { + init_cvtnum(&fsblocksize, &fssectsize); + bsize = fsblocksize; + + while ((c = getopt(argc, argv, "b:Cdf:i:s:S:uwWZ:")) != EOF) { switch (c) { case 'b': - tmp = cvtnum(blocksize, sectsize, optarg); + tmp = cvtnum(fsblocksize, fssectsize, optarg); if (tmp < 0) { printf(_("non-numeric bsize -- %s\n"), optarg); return 0; } - blocksize = tmp; + bsize = tmp; break; case 'C': Cflag = 1; break; + case 'F': + direction = IO_FORWARD; + break; + case 'B': + direction = IO_BACKWARD; + break; + case 'R': + direction = IO_RANDOM; + break; case 'd': dflag = 1; break; @@ -137,7 +251,7 @@ pwrite_f( infile = optarg; break; case 's': - skip = cvtnum(blocksize, sectsize, optarg); + skip = cvtnum(fsblocksize, fssectsize, optarg); if (skip < 0) { printf(_("non-numeric skip -- %s\n"), optarg); return 0; @@ -159,25 +273,34 @@ pwrite_f( case 'W': Wflag = 1; break; + case 'Z': + zeed = strtoul(optarg, &sp, 0); + if (!sp || sp == optarg) { + printf(_("non-numeric seed -- %s\n"), optarg); + return 0; + } + break; default: return command_usage(&pwrite_cmd); } } - if ( ((skip || dflag) && !infile) || (optind != argc - 2)) + if (((skip || dflag) && !infile) || (optind != argc - 2)) return command_usage(&pwrite_cmd); - offset = cvtnum(blocksize, sectsize, argv[optind]); + if (infile && direction != IO_FORWARD) + return command_usage(&pwrite_cmd); + offset = cvtnum(fsblocksize, fssectsize, argv[optind]); if (offset < 0) { printf(_("non-numeric offset argument -- %s\n"), argv[optind]); return 0; } optind++; - count = cvtnum(blocksize, sectsize, argv[optind]); + count = cvtnum(fsblocksize, fssectsize, argv[optind]); if (count < 0) { printf(_("non-numeric length argument -- %s\n"), argv[optind]); return 0; } - if (alloc_buffer(blocksize, uflag, seed) < 0) + if (alloc_buffer(bsize, uflag, seed) < 0) return 0; c = IO_READONLY | (dflag ? IO_DIRECT : 0); @@ -185,7 +308,21 @@ pwrite_f( return 0; gettimeofday(&t1, NULL); - c = write_buffer(offset, count, blocksize, fd, skip, &total); + switch (direction) { + case IO_RANDOM: + if (!zeed) /* srandom seed */ + zeed = time(NULL); + c = write_random(offset, count, zeed, &total); + break; + case IO_FORWARD: + c = write_buffer(offset, count, bsize, fd, skip, &total); + break; + case IO_BACKWARD: + c = write_backward(offset, &count, &total); + break; + default: + ASSERT(0); + } if (c < 0) { close(fd); return 0;