home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume22
/
iozone
/
part01
/
iozone.c
Wrap
C/C++ Source or Header
|
1991-08-21
|
18KB
|
635 lines
/*
iozone.c
'IO Zone' Benchmark Program
Author: Bill Norcott (Bill.Norcott@nuo.mts.dec.com)
4 Dunlap Drive
Nashua, NH 03060
'Copyright 1991, William D. Norcott
License to freely use and distribute this software is hereby granted
by the author, subject to the condition that this copyright notice
remains intact. The author retains the exclusive right to publish
derivative works based on this work, including, but not limited
to, revised versions of this work'
*/
char *help[] = {
" 'IO Zone' Benchmark Program",
" ",
" Author: Bill Norcott (Bill.Norcott@nuo.mts.dec.com)",
" 4 Dunlap Drive",
" Nashua, NH 03060",
" ",
" 'Copyright 1991, William D. Norcott",
" License to freely use and distribute this software is hereby granted ",
" by the author, subject to the condition that this copyright notice ",
" remains intact. The author retains the exclusive right to publish ",
" derivative works based on this work, including, but not limited ",
" to, revised versions of this work'",
" ",
" This test writes a 4 MEGABYTE sequential file in 512 byte chunks, then",
" rewinds it and reads it back. [The size of the file should be",
" big enough to factor out the effect of any disk cache.]",
" ",
" The file is written (filling any cache buffers), and then read. If the",
" cache is >= 4 MB, then most if not all the reads will be satisfied from",
" the cache. However, if it is less than or equal to 2 MB, then NONE of",
" the reads will be satisfied from the cache. This is becase after the ",
" file is written, a 2 MB cache will contain the upper 2 MB of the test",
" file, but we will start reading from the beginning of the file (data",
" which is no longer in the cache)",
" ",
" NOTE: as of V1.04 default file size is now 1 MB not 4 MB",
" ",
" In order for this to be a fair test, the length of the test file must",
" be AT LEAST 2X the amount of disk cache memory for your system. If",
" not, you are really testing the speed at which your CPU can read blocks",
" out of the cache (not a fair test)",
" ",
" IOZONE does NOT test the raw I/O speed of your disk or system. It",
" tests the speed of sequential I/O to actual files. Therefore, this",
" measurement factors in the efficiency of you machines file system,",
" operating system, C compiler, and C runtime library. It produces a ",
" measurement which is the number of bytes per second that your system",
" can read or write to a file. ",
" ",
" For V1.06, IOZONE adds the 'auto test' feature. This is activated",
" by the command: 'iozone auto' . The auto test runs IOZONE repeatedly ",
" using record sizes from 512 to 8192 bytes, and file sizes from 1 to 16",
" megabytes. It creates a table of results.",
" ",
" For V1.06, IOZONE lets you specify the number of file system sizes and ",
" record lengths to test when using auto mode. Define the constants",
" MEGABYTES_ITER_LIMIT and RECLEN_ITER_LIMIT as seen below ",
" ",
" For V1.09 you can show the development help by typing 'iozone help'",
" ",
" For V1.10 IOzone traps SIGINT (user interrupt) and SIGTERM",
" (kill from shell) signals and deletes the temporary file",
" ",
" This program has been ported and tested on the following computer",
" operating systems:",
" ",
" Vendor Operating System Notes on compiling IOzone",
" -------------------------------------------------------------------------",
" Convergent Unisys/AT&T Sys5r3 cc -DCONVERGENT -o iozone iozone.c",
" Digital Equipment ULTRIX V4.1 ",
" Digital Equipment VAX/VMS V5.4 see below ** ",
" Digital Equipment VAX/VMS (POSIX) ",
" Hewlett-Packard HP-UX 7.05",
" IBM AIX Ver. 3 rel. 1 cc -Dunix -o iozone iozone.c",
" Microsoft MS-DOS 3.3 tested Borland, Microsoft C",
" OSF OSF/1",
" SCO UNIX System V/386 3.2.2",
" SCO XENIX 3.2",
" Silicon Graphics UNIX cc -DSGI -o iozone iozone.c",
" Sun Microsystems SUNOS 4.1.1",
" ",
" ** for VMS, define iozone as a foreign command via this DCL command: ",
" ",
" $IOZONE :== $SYS$DISK:[]IOZONE.EXE ",
" ",
" this lets you pass the command line arguments to IOZONE",
" ",
" Acknowledgements to the following persons for their feedback on IOzone: ",
" ",
" Andy Puchrik, Michael D. Lawler, Krishna E. Bera, Sam Drake, John H. Hartman, ",
" Ted Lyszczarz, Bill Metzenthen, Jody Winston, Clarence Dold",
" ",
" --- MODIFICATION HISTORY:",
" ",
" ",
" 3/7/91 William D. Norcott (Bill.Norcott@nuo.mts.dec.com)",
" created",
" ",
" 3/22/91 Bill Norcott tested on OSF/1 ... it works",
" ",
" 3/24/91 Bill Norcott V1.02 -- use calloc in TURBOC to",
" fix bug with their malloc",
" ",
" 3/25/91 Bill Norcott V1.03 -- add ifdef for XENIX",
" ",
" 3/27/91 Bill Norcott V1.04 -- Includes for SCO UNIX",
" ",
" 4/26/91 Bill Norcott V1.05 -- support AIX and SUNos, check",
" length of read() and write()",
" 4/26/91 Bill Norcott V1.06 -- tabulate results of a series ",
" of tests",
" 5/17/91 Bill Norcott V1.07 -- use time() for VMS",
" 5/20/91 Bill Norcott V1.08 -- use %ld for Turbo C and",
" use #ifdef sun to bypass",
" inclusion of limits.h",
" 6/19/91 Bill Norcott V1.09 -- rid #elif to support HP-UX and ",
" Silicon Graphics UNIX, and",
" add #ifdef SGI",
" add #ifdef CONVERGENT",
" for Convergent Technologies",
" also add help option",
" 7/2/91 Bill Norcott V1.10 -- delete file if get SIGINT",
" or SIGTERM",
"" };
/******************************************************************
INCLUDE FILES (system-dependent)
******************************************************************/
#include <signal.h>
#ifdef __MSDOS__ /* Turbo C define this way for PCs... */
#define MSDOS /* Microsoft C defines this */
#endif
/* VMS and MS-DOS both have ANSI C compilers and use rand()/srand() */
#ifdef VMS_POSIX
#undef VMS
#define ANSI_RANDOM 1
#endif
#ifdef MSDOS
#define ANSI_RANDOM 1
#endif
/* Convergent Technologies M680xx based with Unisys/AT&T Sys5r3 */
#ifdef CONVERGENT
#include <fcntl.h>
#define SysVtime
#endif
/* incl definitions of O_* flags for XENIX */
#ifdef M_XENIX
#include <fcntl.h>
#endif
/* SCO Unix System V */
#ifdef M_UNIX
#include <sys/types.h>
#include <sys/fcntl.h>
#endif
#if defined(VMS)
#define ANSI_RANDOM 1
#include <math.h>
#include <unixio.h>
#include <ssdef.h>
#include <file.h>
#include <time.h>
#else
#ifdef MSDOS
/* #elif defined(MSDOS) */
#include <fcntl.h>
#include <time.h>
#endif
/* #elif defined(unix) */
#ifdef unix
#include <sys/file.h>
#ifndef NULL
#define NULL 0
#endif
#endif
/*
define nolimits if your system has no limits.h. Sun's don't but I
take care of this explicitly beginning with V1.08 of IOzone.
*/
#ifdef sun
#define nolimits
#define BSDtime
#endif
/* V1.09 -- Silicon Graphics compile with -DSGI */
#ifdef SGI
#define nolimits
#define BSDtime
#endif
#ifndef nolimits
#include <limits.h>
#endif
#endif
/* for systems with System V-style time, define SysVtime */
#ifdef M_SYSV
#define SysVtime
#endif
#ifdef SysVtime
#include <sys/times.h>
#include <sys/param.h>
#ifndef CLK_TCK
#define CLK_TCK HZ
#endif
#endif
/* for systems with BSD style time, define BSDtime */
#ifdef bsd4_2
#define BSDtime
#endif
#ifdef BSDtime
#include <sys/time.h>
#endif
/******************************************************************
DEFINED CONSTANTS
******************************************************************/
#define MEGABYTES 1 /* number of megabytes in file */
#define RECLEN 512 /* number of bytes in a record */
#define FILESIZE (MEGABYTES*1024*1024) /*size of file in bytes*/
#define NUMRECS FILESIZE/RECLEN /* number of records */
#define MAXBUFFERSIZE 16*1024 /*maximum buffer size*/
#define MINBUFFERSIZE 128
#define TOOFAST 10
#define USAGE "\tUsage:\tiozone [megabytes] [record_length_in_bytes] \
[[path]filename]\n\t\tiozone auto\n\t\tiozone help\n\n"
#define THISVERSION "V1.10"
/* Define only one of the following two. All modern operating systems
have time functions so let TIME be defined */
#if 1
#define TIME 1
#else
#define NOTIME 1
#endif
#define MAXNAMESIZE 1000 /* max # of characters in filename */
#define CONTROL_STRING1 "\t%-8ld%-8ld%-20ld%-20ld\n"
#define CONTROL_STRING2 "\t%-8s%-8s%-20s%-20s\n"
/*
For 'auto mode', these defines determine the number of iterations
to perform for both the file size and the record length.
I.e., if MEGABYTES_ITER_LIMIT = 5 use 1, 2, 4, 8 & 16 megabyte files
if RECLEN_ITER_LIMIT = 5 use 512, 1024, 2048, 4096 & 8192 byte records
*/
#define MEGABYTES_ITER_LIMIT 5
#define RECLEN_ITER_LIMIT 5
/******************************************************************
FUNCTION DECLARATIONS
******************************************************************/
void auto_test(); /* perform automatic test series */
void show_help(); /* show development help*/
static double time_so_far(); /* time since start of program */
void signal_handler(); /* clean up if user interrupts us */
/******************************************************************
GLOBAL VARIABLES
******************************************************************/
int auto_mode;
char filename [MAXNAMESIZE]; /* name of temporary file */
/******************************************************************
MAIN -- entry point
******************************************************************/
main(argc,argv)
int argc;
char *argv[];
{
int fd;
char *default_filename="iozone.tmp"; /*default name of temporary file*/
#ifdef MSDOS
char *buffer;
#else
char buffer [MAXBUFFERSIZE]; /*a temporary data buffer*/
#endif
int i, status;
unsigned long megabytes = MEGABYTES, goodmegs;
unsigned long reclen = RECLEN, goodrecl;
unsigned long filesize = FILESIZE;
unsigned long numrecs = NUMRECS;
unsigned long filebytes;
unsigned long readrate, writerate;
#ifdef TIME
double starttime1, starttime2;
double writetime, readtime;
double totaltime;
#endif
#ifdef MSDOS
buffer = (char *) calloc(1, MAXBUFFERSIZE);
#endif
if (!auto_mode)
{
printf("\n\tIOZONE: Performance Test of Sequential File I/O -- %s\n",
THISVERSION);
printf("\t\tBy Bill Norcott\n\n");
signal(SIGINT, signal_handler); /* handle user interrupt */
signal(SIGTERM, signal_handler); /* handle kill from shell */
}
strcpy(filename,default_filename);
switch (argc) {
case 1: /* no args, take all defaults */
printf(USAGE);
break;
case 2: /* <megabytes|filename> */
i = atoi(argv[1]); if (i) {
megabytes = i;
} else {
/*
'Auto mode' will be enabled if the first command line argument is
the word 'auto'. This will trigger a series of tests
*/
if ( (strcmp(argv[1], "auto") == 0) ||
(strcmp(argv[1], "AUTO") == 0) )
{
auto_mode = 1;
auto_test();
printf("Completed series of tests\n");
exit(0);
} else {
auto_mode = 0;
}
if ( (strcmp(argv[1], "help") == 0) ||
(strcmp(argv[1], "HELP") == 0) )
{
show_help();
exit(0);
}
strcpy(filename,argv[1]);
}
break;
case 3: /* <megabytes> <reclen|filename> */
megabytes = atoi(argv[1]);
if (atoi(argv[2])) {
reclen = atoi(argv[2]);
} else {
strcpy(filename,argv[2]);
}
break;
case 4: /* <megabytes> <reclen> <filename> */
megabytes = atoi(argv[1]);
reclen = atoi(argv[2]);
strcpy(filename,argv[3]);
break;
default:
printf("IOZONE: bad usage\n");
printf(USAGE);
exit(1);
}
if (!auto_mode)
{
printf("\tSend comments to:\tBill.Norcott@nuo.mts.dec.com\n\n");
}
filesize = megabytes*1024*1024;
numrecs = filesize/reclen;
if (reclen > MAXBUFFERSIZE) {
printf("Error: Maximum record length is %d bytes\n", MAXBUFFERSIZE);
exit(1);
}
if (reclen < MINBUFFERSIZE) {
printf("Error: Minimum record length is %d bytes\n", MINBUFFERSIZE);
exit(1);
}
if (!auto_mode)
{
printf("\tIOZONE writes a %ld Megabyte sequential file consisting of\n",
megabytes);
printf("\t%ld records which are each %ld bytes in length.\n",
numrecs, reclen);
printf("\tIt then reads the file. It prints the bytes-per-second\n");
printf("\trate at which the computer can read and write files.\n\n");
printf("\nWriting the %ld Megabyte file, '%s'...", megabytes, filename);
}
if((fd = creat(filename, 0640))<0){
printf("Cannot create temporary file: %s\n", filename);
exit(1);
}
#ifdef TIME
starttime1 = time_so_far();
#endif
for(i=0; i<numrecs; i++){
#ifndef DEBUG_ME
if(write(fd, buffer, (unsigned) reclen) != reclen)
{
printf("Error writing block %d\n", i);
exit(1);
}
#endif
}
#ifdef TIME
writetime = time_so_far() - starttime1;
if (!auto_mode)
{
printf("%f seconds", writetime);
}
#endif
close(fd);
#if defined (VMS)
if((fd = open(filename, O_RDONLY, 0640))<0){
printf("Cannot open temporary file for read\n");
exit(1);
}
#else
#ifdef MSDOS
/* #elif defined(MSDOS) */
if((fd = open(filename, O_RDONLY, 0640))<0){
printf("Cannot open temporary file for read\n");
exit(1);
}
#else
if((fd = open(filename, O_RDONLY))<0){
printf("Cannot open temporary file for read\n");
exit(1);
}
#endif
#endif
/*start timing*/
#if defined(NOTIME)
printf("start timing\n");
#endif
if (!auto_mode)
{
printf("\nReading the file...");
}
starttime2 = time_so_far();
for(i=0; i<numrecs; i++) {
#ifndef DEBUG_ME
if(read(fd, buffer, (unsigned) reclen) != reclen)
{
printf("Error reading block %d\n", i);
exit(1);
}
#endif
}
#ifdef NOTIME
printf("stop timing\n");
#endif
#ifdef TIME
readtime = time_so_far() - starttime2;
if (!auto_mode)
{
printf("%f seconds\n", readtime);
}
#ifdef DEBUG_ME
readtime = 1;
writetime = 1;
#endif
if(readtime!=0)
{
filebytes = numrecs*reclen;
readrate = (unsigned long) ((double) filebytes / readtime);
writerate = (unsigned long) ((double) filebytes / writetime);
if (auto_mode)
{
printf(CONTROL_STRING1,
megabytes,
reclen,
writerate,
readrate);
} else {
printf("\nIOZONE performance measurements:\n");
printf("\t%ld bytes/second for writing the file\n", writerate);
printf("\t%ld bytes/second for reading the file\n", readrate);
totaltime = readtime + writetime;
if (totaltime < TOOFAST)
{
goodmegs = (TOOFAST/totaltime)*2*megabytes;
printf("\nThe test completed too quickly to give a good result\n");
printf("You will get a more precise measure of this machine's\n");
printf("performance by re-running IOZONE using the command:\n");
printf("\n\tiozone %ld ", goodmegs);
printf("\t(i.e., file size = %ld megabytes)\n", goodmegs);
}
}
} else {
goodrecl = reclen/2;
printf("\nI/O error during read. Try again with the command:\n");
printf("\n\tiozone %ld %ld ", megabytes, goodrecl);
printf("\t(i.e. record size = %ld bytes)\n", goodrecl);
}
#endif
close(fd);
#ifndef VMS
unlink(filename); /* delete the file */
/*stop timer*/
#endif
#ifdef MSDOS
free(buffer); /* deallocate the memory */
#endif
#ifdef VMS
return SS$_NORMAL;
#else
return 0;
#endif
}
/******************************************************************
SHOW_HELP -- show development help of this program
******************************************************************/
void show_help()
{
int i;
printf("IOZONE: help mode\n\n");
for(i=0; strlen(help[i]); i++)
{
printf("%s\n", help[i]);
}
}
/******************************************************************
SIGNAL_HANDLER -- clean up if user interrupts the program
******************************************************************/
void signal_handler()
{
int i;
printf("\nIOZONE: interrupted\n\n");
#ifndef VMS
printf("deleting file: %s\n", filename);
unlink(filename); /* delete the file */
#endif
printf("exiting IOzone\n\n");
exit();
}
/******************************************************************
AUTO_TEST -- perform series of tests and tabulate results
******************************************************************/
void auto_test()
{
int megsi, recszi;
char megs[10];
char recsz[10];
int i,j;
int argc = 3;
char *argv[3];
printf("IOZONE: auto-test mode\n\n");
printf(CONTROL_STRING2,
"MB",
"reclen",
"bytes/sec written",
"bytes/sec read");
argv[0] = "IOzone auto-test";
argv[1] = megs;
argv[2] = recsz;
/*
Start with file size of 1 megabyte and repeat the test MEGABYTES_ITER_LIMIT
times. Each time we run, the file size is doubled
*/
for(i=0,megsi=1;i<MEGABYTES_ITER_LIMIT;i++,megsi*=2)
{
sprintf(megs, "%d", megsi);
/*
Start with record size of 512 bytes and repeat the test RECLEN_ITER_LIMIT
times. Each time we run, the record size is doubled
*/
for (j=0,recszi=512;j<RECLEN_ITER_LIMIT;j++,recszi*=2)
{
sprintf(recsz, "%d", recszi);
main(argc, argv);
}
}
}
static double
time_so_far()
{
#if defined(VMS)
/*
* 5/17/91 Bill Norcott V1.07 -- use time() for VMS
The times() function in VMS returns proc & user CPU time in 10-millisecond
ticks. Instead, use time() which lacks the precision but gives clock
time in seconds.
*/
return (double) time(NULL);
#else
#ifdef SysVtime
/* #elif defined(SysVtime) */
int val;
struct tms tms;
if ((val = times(&tms)) == -1)
perror("times");
return ((double) val) / ((double) CLK_TCK);
#endif
#if defined(MSDOS)
return ((double) clock()) / ((double) CLK_TCK);
#endif
#ifndef MSDOS
#ifndef SysVtime
/* #else */
struct timeval tp;
if (gettimeofday(&tp, (struct timezone *) NULL) == -1)
perror("gettimeofday");
return ((double) (tp.tv_sec)) +
(((double) tp.tv_usec) / 1000000.0);
#endif
#endif
#endif
}