This is a wrapper script for qemu-io and performs repeated I/O
accesses to sheepdog VDI without starting any virtual machines. Its
options are similar to disktest in the Linux Test Projcet test suit.

See `vditest -h' for more information.

Signed-off-by: MORITA Kazutaka <[email protected]>
---
 script/vditest |  318 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 318 insertions(+), 0 deletions(-)
 create mode 100755 script/vditest

diff --git a/script/vditest b/script/vditest
new file mode 100755
index 0000000..89c6ab3
--- /dev/null
+++ b/script/vditest
@@ -0,0 +1,318 @@
+#!/usr/bin/perl
+#
+# Copyright (C) 2010 MORITA Kazutaka <[email protected]>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License version
+# 2 as published by the Free Software Foundation.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+use strict;
+use Getopt::Std;
+use Switch;
+
+my $program = "vditest";
+my %opts = ();
+my ($vdiname, $vdisize);
+
+my $use_aio = 0;
+my ($lblk, $hblk) = (512, 1048576);
+my $cache = 'writethrough';
+my $cycles = 256;
+my ($rrate, $wrate) = (50, 50);
+my $no_act = 0;
+my $offset = 0;
+my $seek_pattern = "linear";
+my $seed = time();
+my ($sblk, $eblk) = (0, 0);
+
+parse();
+print_options();
+
+vdi_open($vdiname, $cache);
+
+vdi_main();
+
+vdi_flush();
+vdi_close();
+
+sub get_aligned_blk {
+    my ($l, $h) = @_;
+
+    return $l + 512 * int(rand($h - $l + 512) / 512);
+}
+
+sub to_bytes {
+    my ($size) = @_;
+
+    switch ($size) {
+       case /K/i { $size *= 1024; }
+       case /M/i { $size *= 1024 ** 2; }
+       case /G/i { $size *= 1024 ** 3; }
+    }
+
+    $_[0] = $size;
+}
+
+sub print_options {
+    my $opt = "options: ";
+
+    $opt .= "-a "  if $use_aio;
+    $opt .= "-B $lblk:$hblk ";
+    $opt .= "-c $cache ";
+    $opt .= "-C $cycles ";
+    $opt .= "-D $rrate:$wrate ";
+    $opt .= "-n "  if $no_act;
+    $opt .= "-o $offset\n";
+    $opt .= "         ";
+    $opt .= "-p $seek_pattern ";
+    $opt .= "-s $seed ";
+    $opt .= "-S $sblk:$eblk ";
+
+    print $opt;
+}
+
+sub print_qemu {
+    my ($cmd) = @_;
+
+    print $cmd;
+
+    print QEMU $cmd  if !$no_act;
+}
+
+sub vdi_open {
+    my ($vdiname, $cache) = @_;
+    my $cmd;
+
+    return  if $no_act;
+
+    switch ($cache) {
+       case 'none' {
+           $cmd = "| qemu-io -n sheepdog:$vdiname";
+       }
+       case 'writeback' {
+           # BDRV_O_CACHE_WB option is not suported by qemu-io
+           $cmd = "| qemu-io sheepdog:$vdiname";
+       }
+       case 'writethrough' {
+           $cmd = "| qemu-io sheepdog:$vdiname";
+       }
+    }
+
+    open QEMU, $cmd or die "cannot run qemu-io\n"  if !$no_act;
+}
+
+sub vdi_close {
+    print_qemu("quit\n");
+
+    close QEMU  if !$no_act;
+}
+
+sub vdi_read {
+    my ($offset, $length, $ptn, $ptn_length) = @_;
+
+    if ($use_aio) {
+       if ($length == $ptn_length) {
+           print_qemu("aio_read -P $ptn $offset $length\n");
+       } else {
+           # partial check is not supported
+           print_qemu("aio_read $offset $length\n");
+       }
+    } else {
+       if ($ptn_length > 0) {
+           print_qemu("read -P $ptn -l $ptn_length $offset $length\n");
+       } else {
+           print_qemu("read $offset $length\n");
+       }
+    }
+}
+
+sub vdi_write {
+    my ($offset, $length, $ptn) = @_;
+
+    if ($use_aio) {
+       print_qemu("aio_write -P $ptn $offset $length\n");
+    } else {
+       print_qemu("write -P $ptn $offset $length\n");
+    }
+}
+
+sub vdi_flush {
+    if ($use_aio) {
+       print_qemu("aio_flush\n");
+    } else {
+       print_qemu("flush\n");
+    }
+}
+
+sub parse {
+    getopts("aB:c:C:D:hno:p:s:S:t:", \%opts) or help(1);
+
+    foreach my $key (keys %opts) {
+       my $val = $opts{$key};
+       switch ($key) {
+           case 'a' {
+               $use_aio = 1;
+           }
+           case 'B' {
+               ($lblk, $hblk) = ($val =~ /(\d+[kmg]?):?(\d*[kmg]?)/i);
+               to_bytes($lblk);
+               to_bytes($hblk);
+               $hblk = $lblk  if $hblk == 0;
+
+               error("$lblk is not sector aligned\n")  if $lblk % 512 != 0;
+               error("$lblk is not valid\n")  if $lblk == 0;
+               error("$hblk is not sector aligned\n")  if $hblk % 512 != 0;
+               error("$hblk is too large\n")  if $lblk > 1048576;
+               error("transfer range is invalid\n")  if $lblk > $hblk;
+           }
+           case 'c' {
+               if ($val !~ /(none|write(back|through))/) {
+                   error("\"$val\" is not valid\n");
+               }
+               $cache = $val;
+           }
+           case 'C' {
+               error("\"$val\" is not valid\n")  if ($val <= 0);
+               $cycles = $val;
+           }
+           case 'D' {
+               ($rrate, $wrate) = ($val =~ /(\d+)\%?:?(\d*)\%?/);
+           }
+           case 'h' {
+               help(0);
+           }
+           case 'n' {
+               $no_act = 1;
+           }
+           case 'o' {
+               error("\"$val\" is not valid\n")  if ($val < 0);
+               $offset = $val;
+           }
+           case 'p' {
+               if ($val =~ /^l/) {
+                   $seek_pattern = "linear";
+               } elsif ($val =~ /^r/) {
+                   $seek_pattern = "random";
+               } else {
+                   error("\"$val\" is not valid\n");
+               }
+           }
+           case 's' {
+               $seed = $val;
+           }
+           case 'S' {
+               ($sblk, $eblk) = ($val =~ /(\d+[kmg]?):?(\d*[kmg]?)/i);
+               to_bytes($sblk);
+               to_bytes($eblk);
+
+               error("$sblk is not sector aligned\n")  if $sblk % 512 != 0;
+               error("$eblk is not sector aligned\n")  if $eblk % 512 != 0;
+           }
+       }
+    }
+
+    error("vdiname must be specified\n")  if @ARGV == 0;
+    error("too many arguments\n")  if @ARGV > 1;
+
+    $vdiname = $ARGV[0];
+    $vdisize = `qemu-io -c length sheepdog:$vdiname`;
+    to_bytes($vdisize);
+
+    error("cannot get vdi size\n")  if $vdisize == 0;
+
+    $eblk = $vdisize  if $eblk == 0;
+
+    error("test block range is invalid\n")  if $sblk >= $eblk;
+    error("transfer size is too large\n")  if $hblk > $eblk - $sblk;
+}
+
+sub vdi_main {
+    my $roffset = $offset;
+    my $woffset = $offset;
+    my %written_data = ();
+
+    srand($seed);
+
+    foreach my $i (1 .. $cycles) {
+       my $length = get_aligned_blk($lblk, $hblk);
+       my $pattern;
+       my $ptn_length = 0;
+
+       print "$i: ";
+
+       if (rand($rrate + $wrate) < $rrate) {
+           # read
+           $length = $eblk - $roffset  if $roffset + $length > $eblk;
+           $pattern = $written_data{$roffset};
+
+           for (my $n = $roffset; $n < $roffset + $length; $n += 512) {
+               last  if $pattern != $written_data{$n} || $pattern == 0;
+               $ptn_length += 512;
+           }
+
+           vdi_read($roffset, $length, $pattern, $ptn_length);
+
+           if ($seek_pattern eq 'linear') {
+               $roffset += $length;
+               $roffset -= $eblk - $sblk  while $roffset >= $eblk;
+           } else {
+               $roffset = get_aligned_blk($sblk, $eblk - 512);
+           }
+       } else {
+           # write
+           $length = $eblk - $woffset  if $woffset + $length > $eblk;
+           $pattern = $i % 251 + 1;
+
+           vdi_write($woffset, $length, $pattern);
+
+           for (my $n = $woffset; $n < $woffset + $length; $n += 512) {
+               $written_data{$n} = $pattern;
+           }
+
+           if ($seek_pattern eq 'linear') {
+               $woffset += $length;
+               $woffset -= $eblk - $sblk  while $woffset >= $eblk;
+           } else {
+               $woffset = get_aligned_blk($sblk, $eblk - 512);
+           }
+       }
+
+       %written_data = ()  if %written_data > 1000000;
+
+       vdi_flush()  if ($use_aio && $i % 4 == 0);
+    }
+}
+
+sub help {
+    my ($status) = @_;
+    print <<END_OF_HELP;
+Usage: $program [OPTION] vdiname
+
+  -a                   use asynchronous I/O for testing.
+  -B lblk[:hblk]       set the block transfer size.
+  -c cache             specify how to use the host cache.
+                       cache is "none", "writeback", or "writethrough".
+  -C cycles            run until cycles disk access cycles are complete.
+  -D r%:w%             duty cycle used while reading and/or writing.
+  -h                   display this help text and exit.
+  -n                   print events that would occur but do not access disk.
+  -o offset            set the start offset.
+  -p seek_pattern      set the pattern of disk seeks.
+                       seek_pattern is "linear" or "random".
+  -s seed              set seed for random number generation.
+  -S sblk[:eblk]       set the start [and stop] test block.
+
+END_OF_HELP
+    exit($status);
+}
+
+sub error {
+    my ($msg) = @_;
+
+    print STDERR $msg;
+
+    exit(1);
+}
-- 
1.5.6.5

-- 
sheepdog mailing list
[email protected]
http://lists.wpkg.org/mailman/listinfo/sheepdog

Reply via email to