xref: /minix3/minix/commands/rawspeed/rawspeed.c (revision d0055759dd8892194db7fce6acc5085d5c9aeaee)
1433d6423SLionel Sambuc /*	rawspeed 1.15 - Measure speed of a device.	Author: Kees J. Bot
2433d6423SLionel Sambuc  *								26 Apr 1992
3433d6423SLionel Sambuc  */
4433d6423SLionel Sambuc #define nil 0
5433d6423SLionel Sambuc #include <sys/types.h>
6433d6423SLionel Sambuc #include <stdio.h>
7433d6423SLionel Sambuc #include <stdlib.h>
8433d6423SLionel Sambuc #include <unistd.h>
9433d6423SLionel Sambuc #include <errno.h>
10433d6423SLionel Sambuc #include <signal.h>
11433d6423SLionel Sambuc #include <string.h>
12433d6423SLionel Sambuc #include <time.h>
13433d6423SLionel Sambuc #if !__minix
14433d6423SLionel Sambuc #include <sys/time.h>
15433d6423SLionel Sambuc #endif
16433d6423SLionel Sambuc #include <fcntl.h>
17433d6423SLionel Sambuc #include <limits.h>
18433d6423SLionel Sambuc #include <sys/stat.h>
19433d6423SLionel Sambuc 
20433d6423SLionel Sambuc #define SECTOR_SIZE		512
21433d6423SLionel Sambuc #define BLK_MAX_SECTORS		(sizeof(int) == 2 ? 32 : 64)
22433d6423SLionel Sambuc #define CHR_MAX_SECTORS		(sizeof(int) == 2 ? 63 : 512)
23433d6423SLionel Sambuc #define ABS_MAX_SECTORS		(INT_MAX / SECTOR_SIZE)
24433d6423SLionel Sambuc 
25433d6423SLionel Sambuc #define USEC	(!__minix || __minix_vmd)
26433d6423SLionel Sambuc 
27433d6423SLionel Sambuc /* Any good random number generator around? */
28433d6423SLionel Sambuc #if __minix_vmd || __linux
29433d6423SLionel Sambuc #define	rand	random
30433d6423SLionel Sambuc #define srand	srandom
31433d6423SLionel Sambuc #endif
32433d6423SLionel Sambuc 
33433d6423SLionel Sambuc #if __sun && __svr4__
34433d6423SLionel Sambuc #define rand	lrand48
35433d6423SLionel Sambuc #define srand	srand48
36433d6423SLionel Sambuc #endif
37433d6423SLionel Sambuc 
report(const char * label)38433d6423SLionel Sambuc void report(const char *label)
39433d6423SLionel Sambuc {
40433d6423SLionel Sambuc 	fprintf(stderr, "rawspeed: %s: %s\n", label, strerror(errno));
41433d6423SLionel Sambuc }
42433d6423SLionel Sambuc 
fatal(const char * label)43433d6423SLionel Sambuc void fatal(const char *label)
44433d6423SLionel Sambuc {
45433d6423SLionel Sambuc 	report(label);
46433d6423SLionel Sambuc 	exit(1);
47433d6423SLionel Sambuc }
48433d6423SLionel Sambuc 
usage(void)49433d6423SLionel Sambuc void usage(void)
50433d6423SLionel Sambuc {
51433d6423SLionel Sambuc 	fprintf(stderr,
52433d6423SLionel Sambuc "Usage: rawspeed [-u unit] [-m max] [-t seconds] [-c] [-r limit] device\n");
53433d6423SLionel Sambuc 	fprintf(stderr,
54433d6423SLionel Sambuc "       -u unit = best sector multiple (default 2)\n");
55433d6423SLionel Sambuc 	fprintf(stderr,
56433d6423SLionel Sambuc "       -m max = read multiples of unit upto 'max' (default %d raw, %d file)\n",
57433d6423SLionel Sambuc 					CHR_MAX_SECTORS, BLK_MAX_SECTORS);
58433d6423SLionel Sambuc 	fprintf(stderr,
59433d6423SLionel Sambuc "       -t seconds = time to run test (default 10)\n");
60433d6423SLionel Sambuc 	fprintf(stderr,
61433d6423SLionel Sambuc "       -c = cache test: rewind after each read or write of max size\n");
62433d6423SLionel Sambuc 	fprintf(stderr,
63433d6423SLionel Sambuc "       -r limit = random seeks upto sector 'limit' before reading or writing\n");
64433d6423SLionel Sambuc 	exit(1);
65433d6423SLionel Sambuc }
66433d6423SLionel Sambuc 
67433d6423SLionel Sambuc int done= 0;
68433d6423SLionel Sambuc 
timeout(int sig)69433d6423SLionel Sambuc void timeout(int sig)
70433d6423SLionel Sambuc {
71433d6423SLionel Sambuc 	done= 1;
72433d6423SLionel Sambuc }
73433d6423SLionel Sambuc 
main(int argc,char ** argv)74433d6423SLionel Sambuc int main(int argc, char **argv)
75433d6423SLionel Sambuc {
76433d6423SLionel Sambuc 	int i, fd, n= 0, unit= -1, max= -1, cache= 0;
77433d6423SLionel Sambuc 	int size, seconds= 10;
78433d6423SLionel Sambuc 	long tenthsec;
79433d6423SLionel Sambuc #if USEC
80433d6423SLionel Sambuc 	struct timeval start_time, end_time;
81433d6423SLionel Sambuc 	struct timezone dummy;
82433d6423SLionel Sambuc #else
83433d6423SLionel Sambuc 	time_t start_time;
84433d6423SLionel Sambuc #endif
85433d6423SLionel Sambuc 	off_t nbytes= 0, wbytes= 0, randlimit= 0;
86433d6423SLionel Sambuc 	char *device, *chunk;
87433d6423SLionel Sambuc 	struct stat st;
88433d6423SLionel Sambuc 	off_t nseeks= 0;
89433d6423SLionel Sambuc 
90433d6423SLionel Sambuc 	for (i= 1; i < argc && argv[i][0] == '-' && argv[i][1] != 0; i++) {
91433d6423SLionel Sambuc 		char *opt;
92433d6423SLionel Sambuc 
93433d6423SLionel Sambuc 		if (argv[i][1] == '-' && argv[i][2] == 0) { i++; break; }
94433d6423SLionel Sambuc 
95433d6423SLionel Sambuc 		for (opt= argv[i]+1; *opt != 0; opt++) {
96433d6423SLionel Sambuc 			switch (*opt) {
97433d6423SLionel Sambuc 			case 'w':
98433d6423SLionel Sambuc 				if (i == argc) usage();
99433d6423SLionel Sambuc 				wbytes= atol(argv[++i]) * 1024;
100433d6423SLionel Sambuc 				if (wbytes <= 0) usage();
101433d6423SLionel Sambuc 				break;
102433d6423SLionel Sambuc 			case 'm':
103433d6423SLionel Sambuc 				if (i == argc) usage();
104433d6423SLionel Sambuc 				max= atoi(argv[++i]);
105433d6423SLionel Sambuc 				if (max <= 0 || max > ABS_MAX_SECTORS)
106433d6423SLionel Sambuc 					usage();
107433d6423SLionel Sambuc 				break;
108433d6423SLionel Sambuc 			case 'u':
109433d6423SLionel Sambuc 				if (i == argc) usage();
110433d6423SLionel Sambuc 				unit= atoi(argv[++i]);
111433d6423SLionel Sambuc 				if (unit <= 0 || unit > ABS_MAX_SECTORS)
112433d6423SLionel Sambuc 					usage();
113433d6423SLionel Sambuc 				break;
114433d6423SLionel Sambuc 			case 't':
115433d6423SLionel Sambuc 				if (i == argc) usage();
116433d6423SLionel Sambuc 				seconds= atoi(argv[++i]);
117433d6423SLionel Sambuc 				if (seconds <= 0) usage();
118433d6423SLionel Sambuc 				break;
119433d6423SLionel Sambuc 			case 'c':
120433d6423SLionel Sambuc 				cache= 1;
121433d6423SLionel Sambuc 				break;
122433d6423SLionel Sambuc 			case 'r':
123433d6423SLionel Sambuc 				if (i == argc) usage();
124433d6423SLionel Sambuc 				randlimit= atol(argv[++i]);
125433d6423SLionel Sambuc 				if (randlimit <= 0) usage();
126433d6423SLionel Sambuc 				break;
127433d6423SLionel Sambuc 			default:
128433d6423SLionel Sambuc 				usage();
129433d6423SLionel Sambuc 			}
130433d6423SLionel Sambuc 		}
131433d6423SLionel Sambuc 	}
132433d6423SLionel Sambuc 
133433d6423SLionel Sambuc 	if (i != argc - 1) usage();
134433d6423SLionel Sambuc 
135433d6423SLionel Sambuc 	if (strcmp(argv[i], "-") == 0) {
136433d6423SLionel Sambuc 		fd= wbytes == 0 ? 0 : 1;
137433d6423SLionel Sambuc 		device= "";
138433d6423SLionel Sambuc 	} else {
139433d6423SLionel Sambuc 		device= argv[i];
140433d6423SLionel Sambuc 		if ((fd= open(device,
141433d6423SLionel Sambuc 			wbytes == 0 ? O_RDONLY : O_WRONLY | O_CREAT, 0666)) < 0)
142433d6423SLionel Sambuc 				fatal(device);
143433d6423SLionel Sambuc 	}
144433d6423SLionel Sambuc 	if (max < 0) {
145433d6423SLionel Sambuc 		if (fstat(fd, &st) >= 0 && S_ISCHR(st.st_mode))
146433d6423SLionel Sambuc 			max= CHR_MAX_SECTORS;
147433d6423SLionel Sambuc 		else
148433d6423SLionel Sambuc 			max= BLK_MAX_SECTORS;
149433d6423SLionel Sambuc 	}
150433d6423SLionel Sambuc 
151433d6423SLionel Sambuc 	if (unit < 0) unit= max > 1 ? 2 : 1;
152433d6423SLionel Sambuc 	unit*= max / unit;
153433d6423SLionel Sambuc 	if (unit == 0) usage();
154433d6423SLionel Sambuc 	size= unit * SECTOR_SIZE;
155433d6423SLionel Sambuc 	randlimit/= unit;
156433d6423SLionel Sambuc 
157433d6423SLionel Sambuc 	if ((chunk= malloc((size_t) size)) == nil) {
158433d6423SLionel Sambuc 		fprintf(stderr, "rawspeed: can't grab %d bytes: %s\n",
159433d6423SLionel Sambuc 			size, strerror(errno));
160433d6423SLionel Sambuc 		exit(1);
161433d6423SLionel Sambuc 	}
162433d6423SLionel Sambuc 
163433d6423SLionel Sambuc 	/* Touch the pages to get real memory sending other processes to swap.
164433d6423SLionel Sambuc 	 */
165433d6423SLionel Sambuc 	memset((void *) chunk, 0, (size_t) size);
166433d6423SLionel Sambuc 
167433d6423SLionel Sambuc 	/* Clean the cache. */
168433d6423SLionel Sambuc 	sync();
169433d6423SLionel Sambuc 
170433d6423SLionel Sambuc 	signal(SIGALRM, timeout);
171433d6423SLionel Sambuc 	signal(SIGINT, timeout);
172433d6423SLionel Sambuc #if USEC
173433d6423SLionel Sambuc 	gettimeofday(&start_time, &dummy);
174433d6423SLionel Sambuc 	if (randlimit != 0) srand((int) (start_time.tv_sec & INT_MAX));
175433d6423SLionel Sambuc #else
176433d6423SLionel Sambuc 	start_time= time((time_t *) nil);
177433d6423SLionel Sambuc 	if (randlimit != 0) srand((int) (start_time & INT_MAX));
178433d6423SLionel Sambuc #endif
179433d6423SLionel Sambuc 	alarm(seconds);
180433d6423SLionel Sambuc 
181433d6423SLionel Sambuc 	if (wbytes > 0) {
182433d6423SLionel Sambuc 		while (!done && (n= write(fd, chunk, size)) > 0
183433d6423SLionel Sambuc 						&& (nbytes+= n) < wbytes) {
184433d6423SLionel Sambuc 			if (cache && lseek(fd, (off_t) 0, SEEK_SET) == -1)
185433d6423SLionel Sambuc 				fatal(device);
186433d6423SLionel Sambuc 			if (randlimit != 0) {
187433d6423SLionel Sambuc 				if (lseek(fd, (off_t)
188433d6423SLionel Sambuc 					(rand() % randlimit * size),
189433d6423SLionel Sambuc 							SEEK_SET) == -1)
190433d6423SLionel Sambuc 					fatal(device);
191433d6423SLionel Sambuc 				nseeks++;
192433d6423SLionel Sambuc 			}
193433d6423SLionel Sambuc 		}
194433d6423SLionel Sambuc 		sync();
195433d6423SLionel Sambuc 	} else {
196433d6423SLionel Sambuc 		while (!done && (n= read(fd, chunk, size)) > 0) {
197433d6423SLionel Sambuc 			nbytes+= n;
198433d6423SLionel Sambuc 			if (cache && lseek(fd, (off_t) 0, SEEK_SET) == -1)
199433d6423SLionel Sambuc 				fatal(device);
200433d6423SLionel Sambuc 			if (randlimit != 0) {
201433d6423SLionel Sambuc 				if (lseek(fd, (off_t)
202433d6423SLionel Sambuc 					(rand() % randlimit * size),
203433d6423SLionel Sambuc 							SEEK_SET) == -1)
204433d6423SLionel Sambuc 					fatal(device);
205433d6423SLionel Sambuc 				nseeks++;
206433d6423SLionel Sambuc 			}
207433d6423SLionel Sambuc 		}
208433d6423SLionel Sambuc 	}
209433d6423SLionel Sambuc 
210433d6423SLionel Sambuc #if USEC
211433d6423SLionel Sambuc 	gettimeofday(&end_time, &dummy);
212433d6423SLionel Sambuc 	tenthsec= (end_time.tv_sec - start_time.tv_sec) * 10
213433d6423SLionel Sambuc 		+ (end_time.tv_usec - start_time.tv_usec) / 100000;
214433d6423SLionel Sambuc #else
215433d6423SLionel Sambuc 	tenthsec= (time((time_t *) 0) - start_time) * 10;
216433d6423SLionel Sambuc #endif
217433d6423SLionel Sambuc 	if (n < 0 && errno == EINTR) n= 0;
218433d6423SLionel Sambuc 	if (n < 0) report(device);
219433d6423SLionel Sambuc 
220433d6423SLionel Sambuc 	if (nbytes > 0) {
221433d6423SLionel Sambuc 		off_t kBpts;
222433d6423SLionel Sambuc 
223*d0055759SDavid van Moolenbroek 		fprintf(stderr, "%lld kB / %ld.%ld s = ",
224433d6423SLionel Sambuc 			(nbytes + 512) / 1024,
225433d6423SLionel Sambuc 			tenthsec / 10, tenthsec % 10);
226433d6423SLionel Sambuc 		if (tenthsec < 5)
227433d6423SLionel Sambuc 			fprintf(stderr, "infinite\n");
228433d6423SLionel Sambuc 		else {
229433d6423SLionel Sambuc 			if (nbytes > LONG_MAX / 100) {
230433d6423SLionel Sambuc 				seconds = (tenthsec + 5) / 10;
231433d6423SLionel Sambuc 				kBpts= (nbytes + 512L * seconds)
232433d6423SLionel Sambuc 							/ (1024L * seconds);
233*d0055759SDavid van Moolenbroek 				fprintf(stderr, "%lld kB/s\n", kBpts);
234433d6423SLionel Sambuc 			} else {
235433d6423SLionel Sambuc 				kBpts= (100 * nbytes + 512L * tenthsec)
236433d6423SLionel Sambuc 							/ (1024L * tenthsec);
237*d0055759SDavid van Moolenbroek 				fprintf(stderr, "%lld.%d kB/s\n",
238*d0055759SDavid van Moolenbroek 					kBpts/10, (int)(kBpts%10));
239433d6423SLionel Sambuc 			}
240433d6423SLionel Sambuc 		}
241433d6423SLionel Sambuc 	}
242433d6423SLionel Sambuc 	if (randlimit != 0 && tenthsec >= 5) {
243433d6423SLionel Sambuc 		int rpm, disc= 0;
244433d6423SLionel Sambuc 		off_t tenthms;
245433d6423SLionel Sambuc 
246433d6423SLionel Sambuc 		tenthms= (tenthsec * 1000 + nseeks/2) / nseeks;
247433d6423SLionel Sambuc 
248433d6423SLionel Sambuc 		fprintf(stderr,
249*d0055759SDavid van Moolenbroek 		"%lld seeks / %ld.%ld s = %lld seeks/s = %lld.%d ms/seek\n",
250433d6423SLionel Sambuc 			nseeks, tenthsec / 10, tenthsec % 10,
251433d6423SLionel Sambuc 			(nseeks * 10 + tenthsec/2) / tenthsec,
252*d0055759SDavid van Moolenbroek 			tenthms / 10, (int)(tenthms % 10));
253433d6423SLionel Sambuc 
254433d6423SLionel Sambuc 		for (rpm= 3600; rpm <= 7200; rpm+= 1800) {
255433d6423SLionel Sambuc 			int rotms = (10000L / 2 * 60 + rpm/2) / rpm;
256433d6423SLionel Sambuc 
257433d6423SLionel Sambuc 			if (tenthms <= rotms) continue;
258433d6423SLionel Sambuc 
259433d6423SLionel Sambuc 			if (!disc) {
260433d6423SLionel Sambuc 				fprintf(stderr,
261433d6423SLionel Sambuc 					"discarding av. rotational delay:\n  ");
262433d6423SLionel Sambuc 				disc= 1;
263433d6423SLionel Sambuc 			} else {
264433d6423SLionel Sambuc 				fprintf(stderr, ", ");
265433d6423SLionel Sambuc 			}
266*d0055759SDavid van Moolenbroek 			fprintf(stderr, "%lld.%d ms (%d rpm)",
267*d0055759SDavid van Moolenbroek 				(tenthms - rotms) / 10,
268*d0055759SDavid van Moolenbroek 				(int)((tenthms - rotms) % 10),
269433d6423SLionel Sambuc 				rpm);
270433d6423SLionel Sambuc 		}
271433d6423SLionel Sambuc 		if (disc) fputc('\n', stdout);
272433d6423SLionel Sambuc 	}
273433d6423SLionel Sambuc 	return n < 0 ? 1 : 0;
274433d6423SLionel Sambuc }
275