]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
Provide further debugging options and tweaks for analysing the read/write paths.
authorNathan Scott <nathans@sgi.com>
Fri, 11 Nov 2005 14:25:18 +0000 (14:25 +0000)
committerNathan Scott <nathans@sgi.com>
Fri, 11 Nov 2005 14:25:18 +0000 (14:25 +0000)
Merge of master-melb:xfs-cmds:24372a by kenmcd.

io/bmap.c
io/io.h
io/pread.c
io/pwrite.c

index 7e5edb74245494bb990d549bf7f4d7fda06e9d30..0d9d7568fa0d39dbb0f4bbbae6b2511616944a7d 100644 (file)
--- 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 997452f9dd716ab68b923aa5da97eb8711c03c11..c827298edd867a0b13c13d7144431ee6fa41a2b4 100644 (file)
--- a/io/io.h
+++ b/io/io.h
  * 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)
index 14dc3a0e371455a59b77b9ec9256347d8975a108..f3b820efb6824681949b2c303b24f63baa00c9e6 100644 (file)
@@ -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, &sectsize);
-       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);
index 4c644c032e27a14ee6214457418a849f5337951d..82269050518888e2d002f3626ef2bff4c1b9052d 100644 (file)
@@ -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, &sectsize);
-       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;