[Sheepdog] [PATCH] vditest: script to test sheepdog virtual disk images
MORITA Kazutaka
morita.kazutaka at lab.ntt.co.jp
Sun Apr 11 11:36:14 CEST 2010
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 <morita.kazutaka at lab.ntt.co.jp>
---
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 <morita.kazutaka at lab.ntt.co.jp>
+#
+# 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
More information about the sheepdog
mailing list