/* * ATDISK -- PC Tech Journal AT Hard Disk Performance Test * * Version 1.00 * Last modified 05/23/86 * Copyright (c) 1986, Ziff Communications Company * Program by: Paul Pierce, Ted Forgeron, Steven Armbrust * * Uses BIOS INT 13H to measure low-level performance. * Uses DOS INT 21H to measure high-level performance. */ #include "dos.h" /* System clock tick rate in ticks/second */ #define TICK_RATE 18.20648 /* Number of trials for each test */ #define TRIALS 1000 struct diskparam { int sectors; int heads; int cylinders; int drives; } diskparam[10]; char buffer[50 * 512]; /* Number of files for DOS file I/O test */ #define FILES 10 /* Size of each file for DOS file I/O test */ #define FILESIZE 20000 /* Size of each read/write request for DOS file I/O test */ #define FILEBUF 2000 char filename[] = "C:ATDISK.~~0"; unsigned long tick(); unsigned rand(); double drand() { return (double)rand() / 32767; } #define READ_SECTORS 2 #define GET_PARAM 8 #define SEEK 12 main(argc, argv) int argc; char *argv[]; { register i, j, k; unsigned long start; unsigned long total; unsigned trials; int f; trials = TRIALS; /* * Get the disk drive parameters for each hard disk * in the system. */ disk_io(GET_PARAM, 0x80, &diskparam[0], 0, 0, 0, 0); for (i = 1; i < diskparam[0].drives; i++) { disk_io(GET_PARAM, 0x80 + i, &diskparam[i], 0, 0, 0, 0); } /* * Display the disk characteristics. */ printf("\nATDISK -- PC Tech Journal AT Hard Disk "); printf("Performance Test"); printf("\nVersion 1.00, Copyright (c) 1986 Ziff "); printf("Communications Co."); printf("\n\nHARD DISK CHARACTERISTICS\n"); printf("Drive Sectors Heads Cylinders Total "); printf("space\n"); for (i = 0; i < diskparam[0].drives; i++) { total = diskparam[i].sectors * diskparam[i].heads; total *= diskparam[i].cylinders; total *= 512; printf("%3d %5d %5d %5d %10lu\n", i, diskparam[i].sectors, diskparam[i].heads, diskparam[i].cylinders, total); } printf("\nBIOS TEST OF DISK HARDWARE PERFORMANCE\n"); /* * Seek back and forth between tracks 0 and 1. */ for (i = 0; i < diskparam[0].drives; i++) { disk_io(SEEK, 0x80 + i, buffer, 1, 0, 0, 0); start = tick(); for (j = 0; j < trials/2; j++) { disk_io(SEEK, 0x80 + i, buffer, 1, 0, 0, 1); disk_io(SEEK, 0x80 + i, buffer, 1, 0, 0, 0); } total = tick() - start; printf("Drive %d track-track seek time: %4.1f ms", i, (double)total / ((double)trials) * 1000.0 / TICK_RATE); printf("\n"); } /* * Seek to random tracks. */ for (i = 0; i < diskparam[0].drives; i++) { disk_io(SEEK, 0x80 + i, buffer, 1, 0, 0, 0); start = tick(); for (j = 0; j < trials; j++) { disk_io(SEEK, 0x80 + i, buffer, 1, 0, 0, (short)(drand()* (diskparam[i].cylinders - 1))); } total = tick() - start; printf("Drive %d average seek time: %4.1f ms\n", i, (double)total / ((double)trials) * 1000.0 / TICK_RATE); } /* * Measure transfer rate by repeatedly reading sectors */ for (i = 0; i < diskparam[0].drives; i++) { disk_io(READ_SECTORS, 0x80 + i, buffer, 1, 0, 0, 0); start = tick(); for (j = 0; j < trials; j++) { disk_io(READ_SECTORS, 0x80 + i, buffer, diskparam[i].sectors, 0, 0, 0); } total = tick() - start; printf("Drive %d effective transfer rate: ", i); printf("%6.1f Kbytes/second\n", (((double)diskparam[i].sectors)*512.0) * (double)trials / ((double)total) / 1024 * TICK_RATE); } /* * This section indicates overall system disk performance * by using DOS calls to manipulate files. It is only * executed if the -d command line switch is used since * the test writes to disk. */ if (argc == 1) { printf("\nType \"atdisk -d\" to run the DOS "); printf("TEST OF DISK SYSTEM PERFORMANCE.\n"); printf("This test creates, writes, reads and "); printf("deletes ten files named \n"); printf("atdisk.~~0 through atdisk.~~9.\n"); } if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'd'){ printf("\nDOS TEST OF DISK SYSTEM PERFORMANCE\n"); printf("This test creates, writes, reads and "); printf("deletes ten 20,000 byte files.\n"); printf("Best results are achieved with blank, "); printf("freshly-formatted disks.\n"); for (k = 0; k < diskparam[0].drives; k++) { filename[0] = 'C' + k; start = tick(); /* * First create each file, write to it, * and close it. */ for (i = 0; i < FILES; i++) { filename[11] = '0' + i; f = dos_create(filename, 0); for (j = 0; j < FILESIZE/FILEBUF; j++) { dos_write(f, buffer, FILEBUF); } dos_close(f); } /* * Now reopen each file, read it, and * then delete it. */ for (i = 0; i < FILES; i++) { filename[11] = '0' + i; f = dos_open(filename, 0); for (j = 0; j < FILESIZE/FILEBUF; j++) { dos_read(f, buffer, FILEBUF); } dos_close(f); dos_delete(filename); } total = tick() - start; printf("Drive %c:",'C' + k); printf("%6.1f seconds\n", ((double)total) / TICK_RATE); } } } /* * DOS file calls * * Each of these routines sets up the regs structure as * specified in the DOS technical reference and then * calls DOS using the intdos() function. */ /* * DOS call 3C - create file */ int dos_create(file, attribute) char *file; int attribute; { union REGS regs; regs.x.dx =(int)file; regs.h.ah = 0x3C; regs.x.cx = attribute; intdos(®s, ®s); if (regs.x.cflag) { printf("DOS error %d in create\n", regs.x.ax); exit(1); } return regs.x.ax; } /* * DOS call 3D - open file */ int dos_open(file, mode) char *file; int mode; { union REGS regs; regs.x.dx = (int)file; regs.h.ah = 0x3D; regs.h.al = mode; intdos(®s, ®s); if (regs.x.cflag) { printf("DOS error %d in open\n", regs.x.ax); exit(1); } return regs.x.ax; } /* * DOS call 3E - close file */ dos_close(handle) int handle; { union REGS regs; regs.x.bx = handle; regs.h.ah = 0x3E; intdos(®s, ®s); if (regs.x.cflag) { printf("DOS error %d in close\n", regs.x.ax); exit(1); } } /* * DOS call 3F - read file */ int dos_read(handle, buffer, count) int handle; char *buffer; int count; { union REGS regs; regs.x.bx = handle; regs.x.cx = count; regs.x.dx = (int)buffer; regs.h.ah = 0x3F; intdos(®s, ®s); if (regs.x.cflag) { printf("DOS error %d in read\n", regs.x.ax); exit(1); } return regs.x.ax; } /* * DOS call 40 - write file */ int dos_write(handle, buffer, count) int handle; char *buffer; int count; { union REGS regs; regs.x.bx = handle; regs.x.cx = count; regs.x.dx = (int)buffer; regs.h.ah = 0x40; intdos(®s, ®s); if (regs.x.cflag) { printf("DOS error %d in write\n", regs.x.ax); exit(1); } return regs.x.ax; } /* * DOS call 41 - delete file */ dos_delete(file) char *file; { union REGS regs; regs.x.dx = (int)file; regs.h.ah = 0x41; intdos(®s, ®s); if (regs.x.cflag) { printf("DOS error %d in delete\n", regs.x.ax); exit(1); } }