/* rawspeed 1.15 - Measure speed of a device. Author: Kees J. Bot * 26 Apr 1992 */ #define nil 0 #include #include #include #include #include #include #include #include #if !__minix #include #endif #include #include #include #define SECTOR_SIZE 512 #define BLK_MAX_SECTORS (sizeof(int) == 2 ? 32 : 64) #define CHR_MAX_SECTORS (sizeof(int) == 2 ? 63 : 512) #define ABS_MAX_SECTORS (INT_MAX / SECTOR_SIZE) #define USEC (!__minix || __minix_vmd) /* Any good random number generator around? */ #if __minix_vmd || __linux #define rand random #define srand srandom #endif #if __sun && __svr4__ #define rand lrand48 #define srand srand48 #endif void report(const char *label) { fprintf(stderr, "rawspeed: %s: %s\n", label, strerror(errno)); } void fatal(const char *label) { report(label); exit(1); } void usage(void) { fprintf(stderr, "Usage: rawspeed [-u unit] [-m max] [-t seconds] [-c] [-r limit] device\n"); fprintf(stderr, " -u unit = best sector multiple (default 2)\n"); fprintf(stderr, " -m max = read multiples of unit upto 'max' (default %d raw, %d file)\n", CHR_MAX_SECTORS, BLK_MAX_SECTORS); fprintf(stderr, " -t seconds = time to run test (default 10)\n"); fprintf(stderr, " -c = cache test: rewind after each read or write of max size\n"); fprintf(stderr, " -r limit = random seeks upto sector 'limit' before reading or writing\n"); exit(1); } int done= 0; void timeout(int sig) { done= 1; } int main(int argc, char **argv) { int i, fd, n= 0, unit= -1, max= -1, cache= 0; int size, seconds= 10; long tenthsec; #if USEC struct timeval start_time, end_time; struct timezone dummy; #else time_t start_time; #endif off_t nbytes= 0, wbytes= 0, randlimit= 0; char *device, *chunk; struct stat st; off_t nseeks= 0; for (i= 1; i < argc && argv[i][0] == '-' && argv[i][1] != 0; i++) { char *opt; if (argv[i][1] == '-' && argv[i][2] == 0) { i++; break; } for (opt= argv[i]+1; *opt != 0; opt++) { switch (*opt) { case 'w': if (i == argc) usage(); wbytes= atol(argv[++i]) * 1024; if (wbytes <= 0) usage(); break; case 'm': if (i == argc) usage(); max= atoi(argv[++i]); if (max <= 0 || max > ABS_MAX_SECTORS) usage(); break; case 'u': if (i == argc) usage(); unit= atoi(argv[++i]); if (unit <= 0 || unit > ABS_MAX_SECTORS) usage(); break; case 't': if (i == argc) usage(); seconds= atoi(argv[++i]); if (seconds <= 0) usage(); break; case 'c': cache= 1; break; case 'r': if (i == argc) usage(); randlimit= atol(argv[++i]); if (randlimit <= 0) usage(); break; default: usage(); } } } if (i != argc - 1) usage(); if (strcmp(argv[i], "-") == 0) { fd= wbytes == 0 ? 0 : 1; device= ""; } else { device= argv[i]; if ((fd= open(device, wbytes == 0 ? O_RDONLY : O_WRONLY | O_CREAT, 0666)) < 0) fatal(device); } if (max < 0) { if (fstat(fd, &st) >= 0 && S_ISCHR(st.st_mode)) max= CHR_MAX_SECTORS; else max= BLK_MAX_SECTORS; } if (unit < 0) unit= max > 1 ? 2 : 1; unit*= max / unit; if (unit == 0) usage(); size= unit * SECTOR_SIZE; randlimit/= unit; if ((chunk= malloc((size_t) size)) == nil) { fprintf(stderr, "rawspeed: can't grab %d bytes: %s\n", size, strerror(errno)); exit(1); } /* Touch the pages to get real memory sending other processes to swap. */ memset((void *) chunk, 0, (size_t) size); /* Clean the cache. */ sync(); signal(SIGALRM, timeout); signal(SIGINT, timeout); #if USEC gettimeofday(&start_time, &dummy); if (randlimit != 0) srand((int) (start_time.tv_sec & INT_MAX)); #else start_time= time((time_t *) nil); if (randlimit != 0) srand((int) (start_time & INT_MAX)); #endif alarm(seconds); if (wbytes > 0) { while (!done && (n= write(fd, chunk, size)) > 0 && (nbytes+= n) < wbytes) { if (cache && lseek(fd, (off_t) 0, SEEK_SET) == -1) fatal(device); if (randlimit != 0) { if (lseek(fd, (off_t) (rand() % randlimit * size), SEEK_SET) == -1) fatal(device); nseeks++; } } sync(); } else { while (!done && (n= read(fd, chunk, size)) > 0) { nbytes+= n; if (cache && lseek(fd, (off_t) 0, SEEK_SET) == -1) fatal(device); if (randlimit != 0) { if (lseek(fd, (off_t) (rand() % randlimit * size), SEEK_SET) == -1) fatal(device); nseeks++; } } } #if USEC gettimeofday(&end_time, &dummy); tenthsec= (end_time.tv_sec - start_time.tv_sec) * 10 + (end_time.tv_usec - start_time.tv_usec) / 100000; #else tenthsec= (time((time_t *) 0) - start_time) * 10; #endif if (n < 0 && errno == EINTR) n= 0; if (n < 0) report(device); if (nbytes > 0) { off_t kBpts; fprintf(stderr, "%ld kB / %d.%d s = ", (nbytes + 512) / 1024, tenthsec / 10, tenthsec % 10); if (tenthsec < 5) fprintf(stderr, "infinite\n"); else { if (nbytes > LONG_MAX / 100) { seconds = (tenthsec + 5) / 10; kBpts= (nbytes + 512L * seconds) / (1024L * seconds); fprintf(stderr, "%ld kB/s\n", kBpts); } else { kBpts= (100 * nbytes + 512L * tenthsec) / (1024L * tenthsec); fprintf(stderr, "%ld.%ld kB/s\n", kBpts/10, kBpts%10); } } } if (randlimit != 0 && tenthsec >= 5) { int rpm, disc= 0; off_t tenthms; tenthms= (tenthsec * 1000 + nseeks/2) / nseeks; fprintf(stderr, "%ld seeks / %d.%d s = %ld seeks/s = %ld.%ld ms/seek\n", nseeks, tenthsec / 10, tenthsec % 10, (nseeks * 10 + tenthsec/2) / tenthsec, tenthms / 10, tenthms % 10); for (rpm= 3600; rpm <= 7200; rpm+= 1800) { int rotms = (10000L / 2 * 60 + rpm/2) / rpm; if (tenthms <= rotms) continue; if (!disc) { fprintf(stderr, "discarding av. rotational delay:\n "); disc= 1; } else { fprintf(stderr, ", "); } fprintf(stderr, "%ld.%ld ms (%d rpm)", (tenthms - rotms) / 10, (tenthms - rotms) % 10, rpm); } if (disc) fputc('\n', stdout); } return n < 0 ? 1 : 0; }