diff --git a/commands/simple/Makefile b/commands/simple/Makefile index 6d7afcec5..0dc40ff52 100755 --- a/commands/simple/Makefile +++ b/commands/simple/Makefile @@ -149,6 +149,7 @@ ALL = \ pwdauth \ rarpd \ rcp \ + rawspeed \ rdate \ readall \ rev \ @@ -650,6 +651,10 @@ rcp: rcp.c $(CCLD) -o $@ rcp.c @install -S 8kw $@ +rawspeed: rawspeed.c + $(CCLD) -o $@ rawspeed.c + @install -S 512k $@ + rdate: rdate.c $(CCLD) -o $@ rdate.c @install -S 8kw $@ @@ -1026,6 +1031,7 @@ install: \ /usr/lib/pwdauth \ /usr/bin/rarpd \ /usr/bin/rcp \ + /usr/bin/rawspeed \ /usr/bin/rdate \ /usr/bin/readall \ /usr/bin/readfs \ @@ -1472,6 +1478,9 @@ install: \ /usr/bin/rcp: rcp install -cs -o bin $? $@ +/usr/bin/rawspeed: rawspeed + install -cs -o bin $? $@ + /usr/bin/rdate: rdate install -cs -o bin $? $@ diff --git a/commands/simple/rawspeed.c b/commands/simple/rawspeed.c new file mode 100644 index 000000000..b0b9f11bc --- /dev/null +++ b/commands/simple/rawspeed.c @@ -0,0 +1,273 @@ +/* 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; +}