# This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # # Wrapped by Carlton Doe on Wed Jun 2 17:01:22 1999 # # This archive contains: # diskspeed.c iotest.pl params.sample readme # LANG=""; export LANG PATH=/bin:/usr/bin:/usr/sbin:/usr/ccs/bin:$PATH; export PATH echo x - diskspeed.c cat >diskspeed.c <<'@EOF' #include #include #include #include #include #include #define ALIGN(x,y) (((x)+(y)-1)&(-(y))) char *Trunc(); char *disk; long size_of_disk = 0x7fffffff/1024; long blk_size = 60; /* 32K */ long offset=0; long nops=0; int testread=0; int testwrite=0; int randomize=0; int seed=0; #include #define START_CLOCK(t)\ { struct timeval tval; \ gettimeofday(&tval, (void *)0); \ t = tval.tv_sec; } #define ELAPSED_TIME(st, et)\ { struct timeval tval; \ gettimeofday(&tval, (void *)0); \ et = 1000000 * (tval.tv_sec - st) + tval.tv_usec; } int fd; char *buf; long nbytes; char *malloc(); long start_time, end_time; main(argc, argv) int argc; char *argv[]; { if (procopts(argc, argv)) { pusage(); exit(1); } buf = malloc((unsigned)(blk_size+1024)); if (buf == NULL) { perror("Error malloc'ing buffer.\n"); exit(1); } buf = (char *)ALIGN((long)buf, 1024); memset(buf, 0, blk_size); fd = open(disk, O_RDWR); if (fd < 0) { char err[80]; sprintf(err, "Error opening device '%s'\n", disk); perror(err); exit(1); } if (testread) Read(); if (testwrite) Write(); close(fd); done: exit(0) ; } procopts(argc, argv) int argc; char *argv[]; { char *ap; int cnt = 1; if (argc < 2) return -1; while (cnt < argc) { ap = argv[cnt]; if (*ap != '-') { disk = argv[cnt++]; continue; } ap = argv[cnt]+1; switch (*ap) { case 's': sscanf(argv[cnt+1], "%d", &size_of_disk); cnt += 2; break; case 'o': sscanf(argv[cnt+1], "%d", &offset); cnt += 2; break; case 'b': sscanf(argv[cnt+1], "%d", &blk_size); cnt += 2; break; case 'R': if (!strcmp("RW",ap)) testread=testwrite=1; else testread=1; cnt += 1; break; case 'W': if (!strcmp("WR",ap)) testread=testwrite=1; else testwrite=1; cnt += 1; break; case 'r': if (!strcmp("random",ap)) { randomize = 1; sscanf(argv[cnt+1], "%d", &seed); srand(seed); cnt += 2; break; } default: printf("Huh? '%s'\n", ap); return -1; } } offset *= 1024; blk_size *= 1024; size_of_disk *= 1024; if (!(testread || testwrite)) { printf("Specify one of -R,-W or -RW\n\n"); return -1; } return 0; } pusage() { printf("\n"); printf("diskspeed [-R|-W|-RW] path -s disk_size -o offset -b blksize [-random seed]\n"); printf("\t- at least one of -R,-W,-RW must be specified\n"); printf("\t- disk size, offset, blksize are in Kbytes\n"); printf("\t- specifying random is optional\n"); printf("\n"); } Write() { int seekto = offset; nops = 0; nbytes = 0; START_CLOCK(start_time); lseek(fd, seekto, SEEK_SET); while (nbytes < size_of_disk) { int nb; if (randomize) lseek(fd, seekto, SEEK_SET); do { nb = write(fd, buf, blk_size); } while ((nb == -1) && (errno == EINTR)); if (nb != blk_size) { perror("Error writing to disk.\n"); if (randomize) printf("seekto = %d\n", seekto); return -1; } nbytes+= blk_size; nops++; if (randomize) { int nblks = size_of_disk / blk_size; seekto = offset + (rand() % (nblks+1))*blk_size; } } ELAPSED_TIME(start_time, end_time); printf("%s [W]: %d MB in %.3f secs, Rate: %.3f MB/sec, IO: %.3f ios/sec\n", Trunc(disk), nbytes/(1024*1024), ((float)end_time)/1000000.0, (nbytes/(1024*1024))/(((float)end_time)/1000000.0), nops/(((float)end_time)/1000000.0)); } Read() { int seekto = offset; START_CLOCK(start_time); nops = 0; nbytes = 0; lseek(fd, seekto, SEEK_SET); while (nbytes < size_of_disk) { int nb; if (randomize) lseek(fd, seekto, SEEK_SET); do { nb = read(fd, buf, blk_size); } while ((nb == -1) && (errno == EINTR)); if (nb < 0) { perror("Error reading from disk.\n"); if (randomize) printf("seekto = %d\n", seekto); return -1; } nbytes += blk_size; nops++; if (randomize) { int nblks = size_of_disk / blk_size; seekto = offset + (rand() % (nblks+1))*blk_size; } else seekto += blk_size; } ELAPSED_TIME(start_time, end_time); printf("%s [R]: %d MB in %.3f secs, Rate: %.3f MB/sec, IO: %.3f ios/sec\n", Trunc(disk), nbytes/(1024*1024), ((float)end_time)/1000000.0, (nbytes/(1024*1024))/(((float)end_time)/1000000.0), nops/(((float)end_time)/1000000.0)); } char *Trunc(pdisk) char *pdisk; { char* p=pdisk + strlen(pdisk)-1; while (*p != '/' && p != pdisk) p--; return p+1; } @EOF chmod 666 diskspeed.c echo x - iotest.pl sed 's/^@//' >iotest.pl <<'@EOF' #!/usr/local/bin/perl -w @@results = (); @@pids = (); $childpid = 0; $count = -1; $seed = ""; $iotype = "-io"; $paramsfile = ""; $naiovec = 10; sub pusage { print "Usage: iotest -f [paramsfile] [-random seed]\n"; # print " : iotest -aio naiovec -f [paramsfile] [-random seed]\n"; print " : iotest -paramsformat\n"; exit -1; } sub psamplefile { print "#\n"; print "# NOTE: All sizes in kbytes, tests will run in parallel\n"; print "# Place '#' before any line you want to comment out\n"; print "#\n"; print "# partition-name test-type size offset blocksize\n"; print "#\n"; print "/dev/rdsk/c0t0d0s4 R 1024 0 4\n"; print "/dev/rdsk/c0t1d0s4 W 1024 0 4\n"; exit -2; } sub procopts { my $cnt = 0; my $arg = ""; while ($cnt <= $#ARGV) { $arg = $ARGV[$cnt]; if ($arg eq "-paramsformat") { psamplefile; } elsif ($arg eq "-f") { $paramsfile = $ARGV[$cnt+1]; $cnt += 2; } elsif ($arg eq "-random") { $seed = $ARGV[$cnt+1]; $cnt += 2; } elsif ($arg eq "-io") { $iotype = $arg; $cnt += 1; } elsif ($arg eq "-aio") { $iotype = $arg; $naiovec = $ARGV[$cnt+1]; $cnt += 2; } } if ($paramsfile eq "") { pusage; } } # single disk diskspeed test runner sub run_diskspeed { my $disk = $_[0]; my $type = $_[1]; my $size = $_[2]; my $offset = $_[3]; my $blksz = $_[4]; my $count = $_[5]; #print "In run_diskspeed\n"; my $outfile = "/tmp/output.".$count; open(OUTFILE, "> $outfile"); if ($iotype eq "-io") { $cmd = "./diskspeed -R $disk -s $size -o $offset -b $blksz -random $seed"; } elsif ($iotype eq "-aio") { print "not implemented yet\n"; exit -1; # $cmd = "./aiospeed -R $disk -s $size -o $offset -b $blksz -V ".$naiovec; } else { print "Unknown io type \"$iotype\"\n"; exit -2; } if ($seed ne "") { $cmd .= " -random $seed"; } #print "Launching $cmd\n"; open(CMD, "$cmd |") or die("Couldn't open command\n"); while () { chop; print "$_\n"; printf OUTFILE "$_\n"; } close(CMD); close(OUTFILE); } # build results sub buildresults { my $outfile = "/tmp/output.".$_[0]; sleep 1; #print "attempting to open outfile $outfile\n"; open(FH2, $outfile) or die("Couldn't open outfile in buildresults\n"); while () { chop; push(@results, $_); } close(FH2); unlink $outfile; } # compute aggregate result sub aggregate { my $totalbytes = 0; my $totaltime = 0.0; my $totalios = 0.0; for $i (0 .. $#results) { my @fields = split(' ',$results[$i],13); $totalbytes += $fields[2]; if ($fields[5] > $totaltime) { $totaltime = $fields[5]; } $totalios += $fields[5]*$fields[11]; } my $avgkbps = $totalbytes / $totaltime; my $avgios = $totalios / $totaltime; sleep 1; printf "Aggregate: %3d MB in %.3f secs, Rate: %.3f MB/sec, IO: %.3f ios/sec\n", $totalbytes, $totaltime, $avgkbps, $avgios; } sub main { procopts; # read disks and tests open(PARAMS, $paramsfile) or die("Could not open file\n"); while () { chop; if ( /#(.*)/ ) { } elsif ( /[\/a-zA-Z0-9]+/ ) { $count++; ($disk, $type, $size, $offset, $blksize) = split(' ', $_, 5); #print "DISK = $disk\n"; #print "TEST = $type\n"; #print "SIZE = $size\n"; #print "OFFSET = $offset\n"; #print "BLKSZ = $blksize\n\n"; if ($childpid = fork) { push(@pids, $childpid); } elsif (defined $childpid) { run_diskspeed($disk, $type, $size, $offset, $blksize, $count); exit 0; } } } # wait for children to get done my $ret = 0; for ($i=0; $i<$#pids && $ret!=-1; $i++) { $ret = waitpid($pids[$i], 0); } #build results list for $j (0 .. $count) { buildresults($j); } # build aggregate &aggregate; } &main; @EOF chmod 666 iotest.pl echo x - params.sample cat >params.sample <<'@EOF' # # NOTE: all sizes in kbytes, tests will run in parallel # # partition-name test-type size offset blocksize # /dev/rdsk/c3t3d0 R 5120 0 4 /dev/rdsk/c3t4d0 R 5120 0 4 /dev/rdsk/c6t10d0 R 5120 0 4 /dev/rdsk/c6t12d0 R 5120 0 4 @EOF chmod 666 params.sample echo x - readme sed 's/^@//' >readme <<'@EOF' Here is the reader-writer program that can be used to measure io-rates. By adding additional runs of this program, one can find out what is the appropriate number of AIOVPs to add for a system. While this code was originally written by an Informix employee, IT IS NOT SUPPORTED BY INFORMIX IN ANY FORM OR FASHION. 'diskspeed.c' is a program that does read and write tests. Here's its syntax: $ ./diskspeed @. diskspeed [-R|-W|-RW] path -s disk_size -o offset -b blksize [-random seed] - at least one of -R,-W,-RW must be specified - disk size, offset, blksize are in Kbytes - specifying random is optional Use the following to compile 'diskspeed' on any platform: cc -o diskspeed diskspeed.c 'iotest' is the parallel driver written in Perl that can be used to run 'diskspeed' in uses the following file format: $ ./iotest -paramsformat # sample paramsformat file # # NOTE: All sizes in kbytes, tests will run in parallel # Place '#' before any line you want to comment out # # partition-name test-type size offset blocksize # /dev/rdsk/c0t0d0s4 R 1024 0 4 /dev/rdsk/c0t1d0s4 W 1024 0 4 Here's sample output for a test run on an HP machine 'casper': $ .do ./iotest -f params.casper @.c3t3d0 [R]: 5 MB in 9.659 secs, Rate: 0.518 MB/sec, IO: 132.517 ios/sec c6t10d0 [R]: 5 MB in 9.711 secs, Rate: 0.515 MB/sec, IO: 131.812 ios/sec c3t4d0 [R]: 5 MB in 9.729 secs, Rate: 0.514 MB/sec, IO: 131.571 ios/sec c6t12d0 [R]: 5 MB in 10.561 secs, Rate: 0.473 MB/sec, IO: 121.198 ios/sec Aggregate: 20 MB in 10.561 secs, Rate: 1.894 MB/sec, IO: 484.806 ios/sec @EOF chmod 666 readme exit 0