/* ** Disk performance benchmark. If your Amiga configuration is substantially ** different from the ones mentioned here, please run the benchmark and ** report the results to either: ..!philabs!sbcs!rick or posting to ** comp.sys.amiga. Thanks! ** ** To compile benchmark for Unix 4.2/4.3 SUN 3.0/3.2: ** ** cc -o diskperf -O -DUNIX diskperf.c ** ** Amiga version was cross compiled from a SUN, so you'll have to figure out ** how to compile diskperf under your favorite compiler system. A uuencoded ** Amiga binary version of diskperfa is included with the shar file that ** contained this source listing. ** ** To run diskperf, simply type: ** ** diskperf [location], e.g. (on Amiga) diskperf ram: ** ** On the Amiga, you will need at least 256K bytes of "disk" wherever you ** choose to run. Unix systems will need about 3 mBytes free (larger size ** test files to delete buffer caching effect). ** ** Disclaimer: ** ** This benchmark is provided only for the purpose of seeing how fast ** _your_ system runs the program. No claims are made on my part ** as to what conclusions may be drawn from the statistics gathered. ** Just consider this program the "Sieve of Eratosthenes" of disk ** benchmarks - haggle over the numbers with friends, etc, but ** don't base purchasing decisions solely on the numbers produced ** by this program. ** ** Amiga timings gathered thus far: ** ----------------------------------------------------------------------------- Amiga A-1000, ~7mHz 68000, RAM: File create/delete: create 5 files/sec, delete 10 files/sec Directory scan: 5 entries/sec Seek/read test: 51 seek/reads per second r/w speed: buf 512 bytes, rd 201469 byte/sec, wr 154202 byte/sec r/w speed: buf 4096 bytes, rd 655360 byte/sec, wr 374491 byte/sec r/w speed: buf 8192 bytes, rd 873813 byte/sec, wr 374491 byte/sec r/w speed: buf 32768 bytes, rd 873813 byte/sec, wr 436906 byte/sec ----------------------------------------------------------------------------- Amiga A-1000, ~7mHz 68000, DF1: File create/delete: create [0..1] files/sec, delete 1 files/sec Directory scan: 43 entries/sec Seek/read test: 18 seek/reads per second r/w speed: buf 512 bytes, rd 11861 byte/sec, wr 5050 byte/sec r/w speed: buf 4096 bytes, rd 12542 byte/sec, wr 5180 byte/sec r/w speed: buf 8192 bytes, rd 12542 byte/sec, wr 5130 byte/sec r/w speed: buf 32768 bytes, rd 12542 byte/sec, wr 5160 byte/sec ----------------------------------------------------------------------------- Amiga A-1000/CSA Turbo board, ~14 mHz 68020, no 32 bit ram installed, RAM: File create/delete: create 7 files/sec, delete 15 files/sec Directory scan: 8 entries/sec Seek/read test: 84 seek/reads per second r/w speed: buf 512 bytes, rd 187245 byte/sec, wr 145625 byte/sec r/w speed: buf 4096 bytes, rd 655360 byte/sec, wr 327680 byte/sec r/w speed: buf 8192 bytes, rd 873813 byte/sec, wr 374491 byte/sec r/w speed: buf 32768 bytes, rd 873813 byte/sec, wr 436906 byte/sec ----------------------------------------------------------------------------- Amiga A-1000, ~7 mHz 68000, Ameristar NFS -> SUN-3/50, Micropolis 1325 disk: File create/delete: create 3 files/sec, delete 7 files/sec Directory scan: 10 entries/sec Seek/read test: 35 seek/reads per second r/w speed: buf 512 bytes, rd 30481 byte/sec, wr 3481 byte/sec r/w speed: buf 4096 bytes, rd 113975 byte/sec, wr 21664 byte/sec r/w speed: buf 8192 bytes, rd 145635 byte/sec, wr 38550 byte/sec r/w speed: buf 32768 bytes, rd 145365 byte/sec, wr 37449 byte/sec ----------------------------------------------------------------------------- SUN-3/50, Adaptec SCSI<->ST-506, Micropolis 1325 drive (5.25", 5 mBit/sec): File create/delete: create 6 files/sec, delete 11 files/sec Directory scan: 350 entries/sec Seek/read test: 298 seek/reads per second r/w speed: buf 512 bytes, rd 240499 byte/sec, wr 215166 byte/sec r/w speed: buf 4096 bytes, rd 234057 byte/sec, wr 182466 byte/sec r/w speed: buf 8192 bytes, rd 233189 byte/sec, wr 179755 byte/sec r/w speed: buf 32768 bytes, rd 236343 byte/sec, wr 187580 byte/sec ----------------------------------------------------------------------------- ** ** Some sample figures from "large" systems: ** ----------------------------------------------------------------------------- SUN-3/160, Fujitsu SuperEagle, Interphase VSMD-3200 controller: File create/delete: create 15 files/sec, delete 18 files/sec Directory scan: 722 entries/sec Seek/read test: 465 seek/reads per second r/w speed: buf 512 bytes, rd 361162 byte/sec, wr 307200 byte/sec r/w speed: buf 4096 bytes, rd 419430 byte/sec, wr 315519 byte/sec r/w speed: buf 8192 bytes, rd 409067 byte/sec, wr 314887 byte/sec r/w speed: buf 32768 bytes, rd 409600 byte/sec, wr 328021 byte/sec ----------------------------------------------------------------------------- SUN-3/75, NFS filesystem, full 8192 byte transactions: File create/delete: create 9 files/sec, delete 12 files/sec Directory scan: 88 entries/sec Seek/read test: 282 seek/reads per second r/w speed: buf 512 bytes, rd 238674 byte/sec, wr 52012 byte/sec r/w speed: buf 4096 bytes, rd 259334 byte/sec, wr 54956 byte/sec r/w speed: buf 8192 bytes, rd 228116 byte/sec, wr 26483 byte/sec r/w speed: buf 32768 bytes, rd 243477 byte/sec, wr 36174 byte/sec ----------------------------------------------------------------------------- DEC VAX 780, RP07: File create/delete: create 12 files/sec, delete 12 files/sec Directory scan: 509 entries/sec Seek/read test: 245 seek/reads per second r/w speed: buf 512 bytes, rd 168041 byte/sec, wr 141064 byte/sec r/w speed: buf 4096 bytes, rd 210135 byte/sec, wr 239765 byte/sec r/w speed: buf 8192 bytes, rd 206277 byte/sec, wr 239948 byte/sec r/w speed: buf 32768 bytes, rd 199222 byte/sec, wr 232328 byte/sec ----------------------------------------------------------------------------- DEC VAX 750, RA81: File create/delete: create 12 files/sec, delete 15 files/sec Directory scan: 208 entries/sec Seek/read test: 153 seek/reads per second r/w speed: buf 512 bytes, rd 99864 byte/sec, wr 72549 byte/sec r/w speed: buf 4096 bytes, rd 142663 byte/sec, wr 166882 byte/sec r/w speed: buf 8192 bytes, rd 147340 byte/sec, wr 153525 byte/sec r/w speed: buf 32768 bytes, rd 142340 byte/sec, wr 141571 byte/sec ----------------------------------------------------------------------------- */ #ifdef UNIX #include #include #include #include #define SCAN_ITER 10 #define RW_ITER 3 #define RW_SIZE (3*1024*1024) #define SEEK_TEST_FSIZE (1024*1024) #define OPEN_TEST_FILES 200 #define TIMER_RATE 100 /* ** Amiga compatibility library for Unix. These are NOT full or correct ** emulations of the Amiga I/F routines - they are intended only to ** run this benchmark. */ #define MODE_OLDFILE 1005 #define MODE_NEWFILE 1006 #define ERROR_NO_MORE_ENTRIES #define OFFSET_BEGINNING -1 #define OFFSET_CURRENT 0 Open(name, accessMode) char *name; long accessMode; { int flags, file; flags = O_RDWR; if(accessMode == MODE_NEWFILE) flags |= O_TRUNC|O_CREAT; if((file = open(name, flags, 0644)) < 0) file = 0; return(file); } /* ** To be fair, write should be followed by fsync(file) to flush cache. But ** since when are benchmarks fair?? */ #define Write(file, buffer, length) write(file, buffer, length) #define Read(file, buffer, length) read(file, buffer, length) #define Close(file) close(file) #define CreateDir(name) mkdir(name, 0755) #define Seek(file, position, mode) lseek(file, position, \ (mode==OFFSET_BEGINNING ? 0 : (mode==OFFSET_CURRENT?1:2))) #define AllocMem(size, constraints) malloc(size) #define FreeMem(p, size) free(p, size) #define DeleteFile(filename) unlink(filename) timer_init() { return(1); } timer_quit() { } timer(valp) long *valp; { static struct timeval ref; struct timeval current; if(valp == (long *)0){ gettimeofday(&ref, 0); return; } gettimeofday(¤t, 0); *valp = (current.tv_usec - ref.tv_usec)/(1000000/TIMER_RATE); if(*valp < 0){ current.tv_sec--; *valp += TIMER_RATE; } *valp += (current.tv_sec - ref.tv_sec)*TIMER_RATE; } OpenStat(filename) char *filename; { int fd, result; struct stat statb; if((fd = open(filename, 0)) < 0) return(0); result = fstat(fd, &statb); close(fd); return(result == 0); } #else /* ** Iteration/size definitions smaller for Amiga so benchmark doesn't take ** as long and fits on empty floppy. */ #include #include #include #ifdef MANX #include /* For Manx only */ #endif #define SCAN_ITER 5 #define RW_ITER 3 #define RW_SIZE (256*1024) #define SEEK_TEST_FSIZE (256*1024) #define OPEN_TEST_FILES 100 #define TIMER_RATE 10 /* misnomer, should be resolution */ struct MsgPort *timerport, *CreatePort(); struct timerequest *timermsg, *CreateExtIO(); long TimerBase; timer_init() { timerport = CreatePort(0, 0); if(timerport == (struct MsgPort *)0) return(0); timermsg = CreateExtIO(timerport, sizeof(struct timerequest)); if(timermsg == (struct timerequest *)0){ DeletePort(timerport); return(0); } if(OpenDevice(TIMERNAME, UNIT_VBLANK, timermsg, 0) != 0){ DeletePort(timerport); DeleteExtIO(timermsg, sizeof(struct timerequest)); return(0); } TimerBase = (long)timermsg->tr_node.io_Device; /* Hack */ return(1); } timer_quit() { CloseDevice(timermsg); DeleteExtIO(timermsg, sizeof(struct timerequest)); DeletePort(timerport); } timer(valp) long *valp; { static struct timeval ref; long t; timermsg->tr_node.io_Command = TR_GETSYSTIME; DoIO(timermsg); t = timermsg->tr_time.tv_secs; if(valp == (long *)0) ref = timermsg->tr_time; else { SubTime(&timermsg->tr_time, &ref); *valp = timermsg->tr_time.tv_secs*TIMER_RATE + (timermsg->tr_time.tv_micro/(1000000/TIMER_RATE)); } } OpenStat(filename) char *filename; { long lock, result; static struct FileInfoBlock fib; /* must be on &fib mod 4 == 0 */ if((lock = Lock(filename, MODE_OLDFILE)) == 0) return(0); result = Examine(lock, &fib); UnLock(lock); return(result); } #endif /* ** Benchmarks performed: ** ** 1) Raw file read/write rates. Tested for operation sizes of ** 512/4096/8192/65536 bytes. Return read/write figures for each ** tranfer size in bytes/sec. ** ** 2) Directory create/delete rates. Return create/delete entries ** per second. ** ** 3) Directory lookup rate. Create files in directory, and ** then measure time to lookup, open & stat entire directory contents. ** Return entries/second. ** ** 4) Seek speed test - create large file, then seek to various ** positions in file & read one byte. Seek distances intentionally ** chosen large to reduce cacheing effectiveness - want basic ** speed of disk format here. Return seeks/second. */ char *prepend = ""; /* prepend this path to all filenames created */ char scratch[8192]; /* scratch buffer used in various tests */ /* ** Our `C' library for the Amiga is a bit different than Unix's, so this ** routine will look a bit obtuse to most of you. Trying to avoid using ** sprintf().. */ maketemp(buf, pref) char *buf; { char *p, *q; int fnum; static int cnt; fnum = cnt++; q = buf; if(pref) for(p = prepend; *p; ) *q++ = *p++; for(p = "diskperf"; *p; ) *q++ = *p++; *q++ = 'A' + ((fnum>>8)&0xf); *q++ = 'A' + ((fnum>>4)&0xf); *q++ = 'A' + (fnum&0xf); *q++ = 0; } long sptest[] = {512, 4096, 8192, 32768, 0}; void rw_test() { long i, j, k, maxsize, file, RDaccTime, WRaccTime, Dt; struct timeval t0, t1; char *p, filename[64]; maxsize = -1; for(k = 0; sptest[k] != 0; k++) if(sptest[k] > maxsize) maxsize = sptest[k]; if((p = (char *)AllocMem(maxsize, 0)) == (char *)0){ printf("Could not get %d bytes of memory\n", maxsize); return; } for(k = 0; sptest[k] != 0; k++){ RDaccTime = WRaccTime = 0; for(j = 0; j < RW_ITER; j++){ maketemp(filename, 1); if((file = (long) Open(filename, MODE_NEWFILE)) == 0){ printf("Could not create %s\n", filename); return; } timer(0); for(i = RW_SIZE/sptest[k]; i > 0; i--) Write(file, p, sptest[k]); timer(&Dt); WRaccTime += Dt; Close(file); if((file = (long) Open(filename, MODE_OLDFILE)) == 0){ printf("Could not open %s\n", filename); return; } timer(0); for(i = RW_SIZE/sptest[k]; i > 0; i--) Read(file, p, sptest[k]); timer(&Dt); RDaccTime += Dt; Close(file); DeleteFile(filename); } printf("r/w speed:\t\tbuf %d bytes, rd %d byte/sec, wr %d byte/sec\n", sptest[k], (TIMER_RATE*RW_SIZE)/(RDaccTime/RW_ITER), (TIMER_RATE*RW_SIZE)/(WRaccTime/RW_ITER)); } FreeMem(p, maxsize); } seek_test() { char fname[64]; long i, fd, Dt, cnt, pos, dist; maketemp(fname, 1); if((fd = (long) Open(fname, MODE_NEWFILE)) == 0){ printf("Could not create %s\n", fname); return; } for(i = SEEK_TEST_FSIZE/sizeof(scratch); i > 0; i--) if(Write(fd, scratch, sizeof(scratch)) != sizeof(scratch)) break; if(i == 0){ cnt = 0; timer(0); for(dist = 256; dist <= 65536; dist <<= 2) for(pos = 0; pos < SEEK_TEST_FSIZE; pos += dist){ cnt++; Seek(fd, pos, OFFSET_BEGINNING); Read(fd, scratch, 1); } timer(&Dt); printf("Seek/read test:\t\t%d seek/reads per second\n", (TIMER_RATE*cnt)/Dt); } Close(fd); DeleteFile(fname); } char tempname[OPEN_TEST_FILES][16]; open_scan_test() { char dirname[64]; long lock, oldlock, cDt, dDt, sDt, i, j, fd, numRead; struct FileInfoBlock *fib; maketemp(dirname, 1); lock = CreateDir(dirname); #ifdef UNIX chdir(dirname); #else oldlock = CurrentDir(lock); #endif for(i = 0; i < OPEN_TEST_FILES; i++) maketemp(tempname[i], 0); /* ** Time Open of files. */ timer(0); for(i = 0; i < OPEN_TEST_FILES; i++){ if((fd = Open(tempname[i], MODE_NEWFILE)) == 0){ printf("Could not open %s/%s\n", dirname, tempname); break; } Close(fd); } timer(&cDt); /* ** Time open scan of directory. */ timer(0); numRead = 1; for(i = 0; i < SCAN_ITER; i++) for(j = 0; j < OPEN_TEST_FILES; j++) if(OpenStat(tempname[i]) != 0) numRead++; timer(&sDt); /* ** Time Close of files. */ timer(0); for(i = 0; i < OPEN_TEST_FILES; i++) DeleteFile(tempname[i]); timer(&dDt); printf("File create/delete:\tcreate %d files/sec, delete %d files/sec\n", (TIMER_RATE*OPEN_TEST_FILES)/cDt, (TIMER_RATE*OPEN_TEST_FILES)/dDt); printf("Directory scan:\t\t%d entries/sec\n", (TIMER_RATE*numRead)/sDt); #ifdef UNIX chdir(".."); rmdir(dirname); #else CurrentDir(oldlock); DeleteFile(dirname); #endif } main(argc, argv) int argc; char **argv; { if(!timer_init()){ printf("Could not init timer\n"); return(0); /* Exit in most systems, but not ours! */ } if(argc > 1) prepend = argv[1]; open_scan_test(); seek_test(); rw_test(); }