/* DRVSPEED.C Copyright (c) April 1996 by Raimo Koski - See GNU GPL for limitations. Postal Address: Uudenmaantie 23 K 3 20720 Finland e-mail raimo.koski@mikropc.fi Compiles with BC++ 3.1 */ #include #include #include #include #include #include #include #include #include #define CF 1 //#define DEBUG 1 void speedtest(int drive); void cd_speedtest(int drive); void usage(void); void readsec(unsigned int drive, unsigned int cyl, unsigned int head, unsigned int sec); unsigned int bios_cyl, bios_head, bios_sec; /* Cylinders, Heads, Sectors */ unsigned int cyl, head, sec = 0; int stdout_tty; int promillage = 20; char *str; unsigned char main (void) { int i, drive, tmp; unsigned int num_cd_drives, first_cd_ltr; union REGS registers; /* Used for Interrupt for BIOS data */ clrscr (); stdout_tty = isatty(fileno(stdout)); for (i=0;i < _argc; i++) if ((strcmpi(_argv[i], "/H") == 0) || (strcmpi(_argv[i], "-H") == 0) || (strcmpi(_argv[i], "H" ) == 0) || (strcmpi(_argv[i], "/?") == 0) || (strcmpi(_argv[i], "-?") == 0) || (strcmpi(_argv[i], "?" ) == 0)) usage(); for (i=0;i < _argc; i++) // Search for value parameter, if found, it is promilles of total // disk space to read for each value displayed. Values over 500 are taken // to mean that we read the whole disk, half from begining, half from // center. str = _argv[i]; /* if (tmp = atoi(_argv[i]) != 0) promillage = tmp;*/ if (tmp = atoi(str)) promillage = tmp; if (promillage > 500) promillage = 500; drive = 0; do { registers.h.ah = 0x8; /* Get drive info */ registers.h.dl = 0x80 + drive; /* Drive is 80H for Disk 0, 81H for Disk 1 */ int86 (0x13, ®isters, ®isters); if (! registers.x.cflag) /* All OK if carry not set */ { bios_head = registers.h.dh + 1; /* Heads are from 0 */ bios_sec = registers.h.cl & 0x3F; /* sec is bits 5 - 0 */ bios_cyl = ((registers.h.cl & 0xC0) << 2) + registers.h.ch + 2; /* +1 because starts from 0 and +1 for FDISK leaving one out */ speedtest(drive++); } } // Loop while BIOS returns valid parameters for drive while(!registers.x.cflag); // Do it for CD-ROM drives registers.x.ax = 0x1500; registers.x.bx = 0x0000; int86 (0x2f, ®isters, ®isters); num_cd_drives = registers.x.bx; first_cd_ltr = registers.x.cx; drive = 0; while (num_cd_drives > 0) { cd_speedtest(first_cd_ltr + drive++); num_cd_drives--; } return(0); } void speedtest(int drive) { int c_size, i; long t_cyl, t_sec, t2_sec, j, bios_time1, bios_time2, bios_time3, bios_time4, bios_time4_1, bios_time5, temp ; struct diskinfo_t dinfo; int result; int limit = 128; int count = 0; float DTR1, DTR2, DTR3, DTRT1, DTRT2, DTRT3, time1, time2, time3; char akey; char far *dbuf; dbuf = (char far *) farmalloc(65536); if (bios_cyl > 0) { DTRT1 = 0; DTRT2 = 0; DTRT3 = 0; fprintf (stderr, "Test disk %i (CHS %i/%i/%i) BIOS Data Transfer Rate (Y/2/N)?\n (2 skips sometimes problematic 128 sectors/record test)\n", drive, bios_cyl, bios_head, bios_sec); akey = toupper(getch()); if ((akey == 'Y') || (akey == '2')) { if (akey == '2') limit = 64; t_cyl = ((long)bios_cyl * promillage) >> 10; if (t_cyl < 1) t_cyl = 1; t_sec = t_cyl * (long)bios_head * (long)bios_sec; t2_sec = (long)((bios_cyl-1)) * (long)bios_head * (long)bios_sec; c_size = bios_head * bios_sec; if (!stdout_tty) { fprintf (stdout, "\nTesting disk %i (CHS %i/%i/%i) BIOS Data Transfer Rate\n", drive, bios_cyl, bios_head, bios_sec); } fprintf(stdout, "Reading %9.1fKB blocks (about %i promilles of disk space)\n\n", (float) (t_sec /2), promillage); fprintf(stdout, "Sectors/ Start of disk End of disk Average cache+bus+BIOS speed\n"); fprintf(stdout, "record KB/s KB/s KB/s KB/s\n"); if (!stdout_tty) { fprintf(stderr, "Reading %9.1fKB blocks (about %i promilles of disk space)\n\n", (float) (t_sec /2), promillage); fprintf(stderr, "Sectors/ Start of disk End of disk Average cache+bus+BIOS speed\n"); fprintf(stderr, "record KB/s KB/s KB/s KB/s\n"); } for (i = limit; i != 1; i = i / 2) { dinfo.drive = drive + 0x80; dinfo.nsectors = i; dinfo.buffer = dbuf; bios_time1 = biostime(0, 0L); // Read from the start of disk for (j=1; j <= t_sec; j = j + i) { dinfo.track = j / c_size; temp = j % c_size; dinfo.head = temp / bios_sec; dinfo.sector = temp % bios_sec + 1; if (_bios_disk(_DISK_READ, &dinfo) & 0xff00 != 0) printf("Error reading disk, Sector %i, Head %i Cyl %i\n", dinfo.sector, dinfo.head, dinfo.track ); } bios_time2 = biostime(0, 0L); // Read from the end of disk for (j=t2_sec - t_sec; j <= t2_sec; j = j + i) { dinfo.track = j / c_size; temp = j % c_size; dinfo.head = temp / bios_sec; dinfo.sector = temp % bios_sec + 1; if (_bios_disk(_DISK_READ, &dinfo) & 0xff00 != 0) printf("Error reading disk, Sector %i, Head %i Cyl %i\n", dinfo.sector, dinfo.head, dinfo.track ); } bios_time3 = biostime(0, 0L); // Do an empty loop for (j=1; j <= t_sec; j = j + i) { dinfo.track = j / c_size; temp = j % c_size; dinfo.head = temp / bios_sec; dinfo.sector = temp % bios_sec + 1; if (0 & 0xff00 != 0); // printf("Error reading disk, Sector %i, Head %i Cyl %i\n", dinfo.sector, dinfo.head, dinfo.track ); } bios_time4 = biostime(0, 0L) - bios_time3; // Do one read to fill the buffer dinfo.track = 0; dinfo.head = 0; dinfo.sector = 1; if (_bios_disk(_DISK_READ, &dinfo) & 0xff00 != 0) printf("Error reading disk, Sector %i, Head %i Cyl %i\n", dinfo.sector, dinfo.head, dinfo.track ); bios_time4_1 = biostime(0, 0L); // Read the same place repeatedly for (j=1; j <= t_sec; j = j + i) { if (_bios_disk(_DISK_READ, &dinfo) & 0xff00 != 0) printf("Error reading disk, Sector %i, Head %i Cyl %i\n", dinfo.sector, dinfo.head, dinfo.track ); } bios_time5 = biostime(0, 0L) - bios_time4_1; time1 = (float) ((bios_time2 - bios_time1 - bios_time4 )); time2 = (float) ((bios_time3 - bios_time2 - bios_time4 )); time3 = (float) ((bios_time5 - bios_time4)); // -1 means unacceptable value. 18.2 clockticks * 0.5KB = 9.1 DTR1 = (time1 == 0) ? -1 : (float)t_sec * 9.1 / time1; DTR2 = (time2 == 0) ? -1 : (float)t_sec * 9.1 / time2; DTR3 = (time3 == 0) ? -1 : (float)t_sec * 9.1 / time3; fprintf (stdout, " %3i %8.1f %8.1f %8.1f %8.1f\n", i, DTR1, DTR2, (DTR1 + DTR2) /2, DTR3); if (!stdout_tty) fprintf (stderr, " %3i %8.1f %8.1f %8.1f %8.1f\n", i, DTR1, DTR2, (DTR1 + DTR2) /2, DTR3); // Skip negative values and 128 sectors per read (to get comparable results) if ((DTR1 > 0) && (DTR2 > 0) && (DTR3 > 0) && (i != 128)) { DTRT1 = DTRT1 + DTR1; DTRT2 = DTRT2 + DTR2; DTRT3 = DTRT3 + DTR3; count++; } } fprintf(stdout, "Average %8.1f %8.1f %8.1f %8.1f\n", DTRT1 / count, DTRT2 / count, (DTRT1 + DTRT2) /count /2, DTRT3/count); fprintf(stdout, "\nThis drive has an average reading speed of %8.1fKB/s\n", (DTRT1 + DTRT2) / count / 2); fprintf(stdout, " ===========\n\n"); if (!stdout_tty) { fprintf(stderr, "Average %8.1f %8.1f %8.1f %8.1f\n", DTRT1 / count, DTRT2 / count, (DTRT1 + DTRT2) /count /2, DTRT3/count); fprintf(stderr, "\nThis drive has an average reading speed of %8.1fKB/s\n", (DTRT1 + DTRT2) / count / 2); fprintf(stderr, " ===========\n\n"); } } } } void cd_speedtest(int drive) { int c_size, i, t_sec, j; long t_cyl, bios_time1, bios_time2, bios_time3, bios_time4, bios_time4_1, bios_time5, temp; int result; int limit = 16; int count = 0; float DTR1, DTRT1, time1; char akey; char far *dbuf; struct REGPACK regs; /* Used for Interrupt for BIOS data */ dbuf = (char far *) farmalloc(65536); if (1) { DTRT1 = 0; fprintf (stderr, "Test CD-ROM %c: MSCDEX Data Transfer Rate (Y/N)?\n", drive + 'A'); akey = toupper(getch()); if (akey == 'Y') { // Assume total capacity is 128MB t_sec = 64 * promillage; // read one sector first to position head and check that disk is inserted // and drive is valid. do { regs.r_ax = 0x1508; // Absolute disk read regs.r_es = FP_SEG(dbuf); regs.r_bx = FP_OFF(dbuf); regs.r_cx = drive; regs.r_si = 0; // starting sector number MSB regs.r_di = 0; // starting sector number LSB regs.r_dx = 1; // number of sectors to read intr (0x2f, ®s); if (CF & regs.r_flags) /* All OK if carry not set */ { if ((regs.r_ax & 0x00ff) == 15) { fprintf(stderr, "Invalid drive. Skipping this one\n"); return(255); } if ((regs.r_ax & 0x00ff) == 21) { fprintf(stderr, "Drive not ready. Insert disk and press a key or press S to skip this one\n"); akey = toupper(getch()); if (akey == 'S') return(255); } } } while (CF & regs.r_flags); if (!stdout_tty) { fprintf (stdout, "\nTesting disk %c: MSCDEX Data Transfer Rate\n", drive + 'A'); } fprintf(stdout, "Reading %dKB blocks\n\n", t_sec << 2); fprintf(stdout, "Sectors/ Start of disk\n"); fprintf(stdout, "record KB/s\n"); if (!stdout_tty) { fprintf(stderr, "Reading %dKB blocks\n\n", t_sec << 2); fprintf(stderr, "Sectors/ Start of disk\n"); fprintf(stderr, "record KB/s\n"); } for (i = limit; i >= 1; i = i / 2) { bios_time1 = biostime(0, 0L); // Read from the start of disk for (j=1; j <= t_sec; j = j + i) { regs.r_ax = 0x1508; // Absolute disk read regs.r_es = FP_SEG(dbuf); regs.r_bx = FP_OFF(dbuf); regs.r_cx = drive; regs.r_si = 0; // starting sector number MSB regs.r_di = j; // starting sector number LSB regs.r_dx = i; // number of sectors to read intr (0x2f, ®s); if (! regs.r_flags) /* All OK if carry not set */ { if ((regs.r_ax & 0x00ff) == 15) fprintf(stderr, "Invalid drive\n"); if ((regs.r_ax & 0x00ff) == 21) fprintf(stderr, "Drive not ready\n"); } } bios_time2 = biostime(0, 0L); // Do an empty loop for (j=1; j <= t_sec; j = j + i) { regs.r_ax = 0x1508; // Absolute disk read regs.r_es = FP_SEG(dbuf); regs.r_bx = FP_OFF(dbuf); regs.r_cx = drive; regs.r_si = 0; // starting sector number MSB regs.r_di = j; // starting sector number LSB regs.r_dx = i; // number of sectors to read // intr (0x2f, ®s); if (0) /* All OK if carry not set */ { if ((regs.r_ax & 0x00ff) == 15) fprintf(stderr, "Invalid drive\n"); if ((regs.r_ax & 0x00ff) == 21) fprintf(stderr, "Drive not ready\n"); } } bios_time4 = biostime(0, 0L); time1 = (float) ((bios_time2 - bios_time1 - (bios_time4 - bios_time2) )); // -1 means unacceptable value. 2KB blocks * 18.2 clockticks = 36.4 DTR1 = (time1 == 0) ? -1 : (float)t_sec * 36.4 / time1; fprintf (stdout, " %3i %8.1f\n", i, DTR1); if (!stdout_tty) fprintf (stderr, " %3i %8.1f\n", i, DTR1); // Skip negative values and 128 sectors per read (to get comparable results) if (DTR1 > 0) { DTRT1 = DTRT1 + DTR1; count++; } } fprintf(stdout, "Average %8.1f\n", DTRT1 / count); fprintf(stdout, "\nThis drive has an average reading speed of %8.1fKB/s\n", (DTRT1) / count); fprintf(stdout, " ===========\n\n"); if (!stdout_tty) { fprintf(stderr, "Average %8.1f\n", DTRT1 / count); fprintf(stderr, "\nThis drive has an average reading speed of %8.1fKB/s\n", (DTRT1) / count); fprintf(stderr, " ===========\n\n"); } } } } void usage(void) { fprintf (stderr, "DRVSPEED [H | ?] | [xxxx]\n\n"); fprintf (stderr, "Version 1.1. Tests all BIOS and MSCDEX accessible drives for speed\n\n"); fprintf (stderr, "-H or -? prints this help.\n"); fprintf (stderr, "xxxx value sets how many promilles of total disk space is read for each value.\n"); fprintf (stderr, "Default is 20, which means that the test reads 12%% of total disk space.\n"); fprintf (stderr, "Increase the value if you want more reliable results and have enough patience.\n"); fprintf (stderr, "Note that drive calibration occurs automatically now and then. If you test\n"); fprintf (stderr, "with a small value the calibration might have great effect or it might not\n"); fprintf (stderr, "occur at all during measurement of some values.\n"); fprintf (stderr, "The effect of calibration is not tried to be avoided by this test, so the best\n"); fprintf (stderr, "way to deal with it is trying to get an average amount of calibrations during\n"); fprintf (stderr, "each measurement.\n"); fprintf (stderr, "For CD-ROMs total capacity is assumed to be 128MB.\n\n"); fprintf (stderr, "Example: Read 5%% of total space for each value or total of 60%\n\n"); fprintf (stderr, "DRVSPEED 50\n"); exit(0); }