xref: /minix/minix/commands/rawspeed/rawspeed.c (revision 9f988b79)
1 /*	rawspeed 1.15 - Measure speed of a device.	Author: Kees J. Bot
2  *								26 Apr 1992
3  */
4 #define nil 0
5 #include <sys/types.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <unistd.h>
9 #include <errno.h>
10 #include <signal.h>
11 #include <string.h>
12 #include <time.h>
13 #if !__minix
14 #include <sys/time.h>
15 #endif
16 #include <fcntl.h>
17 #include <limits.h>
18 #include <sys/stat.h>
19 
20 #define SECTOR_SIZE		512
21 #define BLK_MAX_SECTORS		(sizeof(int) == 2 ? 32 : 64)
22 #define CHR_MAX_SECTORS		(sizeof(int) == 2 ? 63 : 512)
23 #define ABS_MAX_SECTORS		(INT_MAX / SECTOR_SIZE)
24 
25 #define USEC	(!__minix || __minix_vmd)
26 
27 /* Any good random number generator around? */
28 #if __minix_vmd || __linux
29 #define	rand	random
30 #define srand	srandom
31 #endif
32 
33 #if __sun && __svr4__
34 #define rand	lrand48
35 #define srand	srand48
36 #endif
37 
38 void report(const char *label)
39 {
40 	fprintf(stderr, "rawspeed: %s: %s\n", label, strerror(errno));
41 }
42 
43 void fatal(const char *label)
44 {
45 	report(label);
46 	exit(1);
47 }
48 
49 void usage(void)
50 {
51 	fprintf(stderr,
52 "Usage: rawspeed [-u unit] [-m max] [-t seconds] [-c] [-r limit] device\n");
53 	fprintf(stderr,
54 "       -u unit = best sector multiple (default 2)\n");
55 	fprintf(stderr,
56 "       -m max = read multiples of unit upto 'max' (default %d raw, %d file)\n",
57 					CHR_MAX_SECTORS, BLK_MAX_SECTORS);
58 	fprintf(stderr,
59 "       -t seconds = time to run test (default 10)\n");
60 	fprintf(stderr,
61 "       -c = cache test: rewind after each read or write of max size\n");
62 	fprintf(stderr,
63 "       -r limit = random seeks upto sector 'limit' before reading or writing\n");
64 	exit(1);
65 }
66 
67 int done= 0;
68 
69 void timeout(int sig)
70 {
71 	done= 1;
72 }
73 
74 int main(int argc, char **argv)
75 {
76 	int i, fd, n= 0, unit= -1, max= -1, cache= 0;
77 	int size, seconds= 10;
78 	long tenthsec;
79 #if USEC
80 	struct timeval start_time, end_time;
81 	struct timezone dummy;
82 #else
83 	time_t start_time;
84 #endif
85 	off_t nbytes= 0, wbytes= 0, randlimit= 0;
86 	char *device, *chunk;
87 	struct stat st;
88 	off_t nseeks= 0;
89 
90 	for (i= 1; i < argc && argv[i][0] == '-' && argv[i][1] != 0; i++) {
91 		char *opt;
92 
93 		if (argv[i][1] == '-' && argv[i][2] == 0) { i++; break; }
94 
95 		for (opt= argv[i]+1; *opt != 0; opt++) {
96 			switch (*opt) {
97 			case 'w':
98 				if (i == argc) usage();
99 				wbytes= atol(argv[++i]) * 1024;
100 				if (wbytes <= 0) usage();
101 				break;
102 			case 'm':
103 				if (i == argc) usage();
104 				max= atoi(argv[++i]);
105 				if (max <= 0 || max > ABS_MAX_SECTORS)
106 					usage();
107 				break;
108 			case 'u':
109 				if (i == argc) usage();
110 				unit= atoi(argv[++i]);
111 				if (unit <= 0 || unit > ABS_MAX_SECTORS)
112 					usage();
113 				break;
114 			case 't':
115 				if (i == argc) usage();
116 				seconds= atoi(argv[++i]);
117 				if (seconds <= 0) usage();
118 				break;
119 			case 'c':
120 				cache= 1;
121 				break;
122 			case 'r':
123 				if (i == argc) usage();
124 				randlimit= atol(argv[++i]);
125 				if (randlimit <= 0) usage();
126 				break;
127 			default:
128 				usage();
129 			}
130 		}
131 	}
132 
133 	if (i != argc - 1) usage();
134 
135 	if (strcmp(argv[i], "-") == 0) {
136 		fd= wbytes == 0 ? 0 : 1;
137 		device= "";
138 	} else {
139 		device= argv[i];
140 		if ((fd= open(device,
141 			wbytes == 0 ? O_RDONLY : O_WRONLY | O_CREAT, 0666)) < 0)
142 				fatal(device);
143 	}
144 	if (max < 0) {
145 		if (fstat(fd, &st) >= 0 && S_ISCHR(st.st_mode))
146 			max= CHR_MAX_SECTORS;
147 		else
148 			max= BLK_MAX_SECTORS;
149 	}
150 
151 	if (unit < 0) unit= max > 1 ? 2 : 1;
152 	unit*= max / unit;
153 	if (unit == 0) usage();
154 	size= unit * SECTOR_SIZE;
155 	randlimit/= unit;
156 
157 	if ((chunk= malloc((size_t) size)) == nil) {
158 		fprintf(stderr, "rawspeed: can't grab %d bytes: %s\n",
159 			size, strerror(errno));
160 		exit(1);
161 	}
162 
163 	/* Touch the pages to get real memory sending other processes to swap.
164 	 */
165 	memset((void *) chunk, 0, (size_t) size);
166 
167 	/* Clean the cache. */
168 	sync();
169 
170 	signal(SIGALRM, timeout);
171 	signal(SIGINT, timeout);
172 #if USEC
173 	gettimeofday(&start_time, &dummy);
174 	if (randlimit != 0) srand((int) (start_time.tv_sec & INT_MAX));
175 #else
176 	start_time= time((time_t *) nil);
177 	if (randlimit != 0) srand((int) (start_time & INT_MAX));
178 #endif
179 	alarm(seconds);
180 
181 	if (wbytes > 0) {
182 		while (!done && (n= write(fd, chunk, size)) > 0
183 						&& (nbytes+= n) < wbytes) {
184 			if (cache && lseek(fd, (off_t) 0, SEEK_SET) == -1)
185 				fatal(device);
186 			if (randlimit != 0) {
187 				if (lseek(fd, (off_t)
188 					(rand() % randlimit * size),
189 							SEEK_SET) == -1)
190 					fatal(device);
191 				nseeks++;
192 			}
193 		}
194 		sync();
195 	} else {
196 		while (!done && (n= read(fd, chunk, size)) > 0) {
197 			nbytes+= n;
198 			if (cache && lseek(fd, (off_t) 0, SEEK_SET) == -1)
199 				fatal(device);
200 			if (randlimit != 0) {
201 				if (lseek(fd, (off_t)
202 					(rand() % randlimit * size),
203 							SEEK_SET) == -1)
204 					fatal(device);
205 				nseeks++;
206 			}
207 		}
208 	}
209 
210 #if USEC
211 	gettimeofday(&end_time, &dummy);
212 	tenthsec= (end_time.tv_sec - start_time.tv_sec) * 10
213 		+ (end_time.tv_usec - start_time.tv_usec) / 100000;
214 #else
215 	tenthsec= (time((time_t *) 0) - start_time) * 10;
216 #endif
217 	if (n < 0 && errno == EINTR) n= 0;
218 	if (n < 0) report(device);
219 
220 	if (nbytes > 0) {
221 		off_t kBpts;
222 
223 		fprintf(stderr, "%lld kB / %ld.%ld s = ",
224 			(nbytes + 512) / 1024,
225 			tenthsec / 10, tenthsec % 10);
226 		if (tenthsec < 5)
227 			fprintf(stderr, "infinite\n");
228 		else {
229 			if (nbytes > LONG_MAX / 100) {
230 				seconds = (tenthsec + 5) / 10;
231 				kBpts= (nbytes + 512L * seconds)
232 							/ (1024L * seconds);
233 				fprintf(stderr, "%lld kB/s\n", kBpts);
234 			} else {
235 				kBpts= (100 * nbytes + 512L * tenthsec)
236 							/ (1024L * tenthsec);
237 				fprintf(stderr, "%lld.%d kB/s\n",
238 					kBpts/10, (int)(kBpts%10));
239 			}
240 		}
241 	}
242 	if (randlimit != 0 && tenthsec >= 5) {
243 		int rpm, disc= 0;
244 		off_t tenthms;
245 
246 		tenthms= (tenthsec * 1000 + nseeks/2) / nseeks;
247 
248 		fprintf(stderr,
249 		"%lld seeks / %ld.%ld s = %lld seeks/s = %lld.%d ms/seek\n",
250 			nseeks, tenthsec / 10, tenthsec % 10,
251 			(nseeks * 10 + tenthsec/2) / tenthsec,
252 			tenthms / 10, (int)(tenthms % 10));
253 
254 		for (rpm= 3600; rpm <= 7200; rpm+= 1800) {
255 			int rotms = (10000L / 2 * 60 + rpm/2) / rpm;
256 
257 			if (tenthms <= rotms) continue;
258 
259 			if (!disc) {
260 				fprintf(stderr,
261 					"discarding av. rotational delay:\n  ");
262 				disc= 1;
263 			} else {
264 				fprintf(stderr, ", ");
265 			}
266 			fprintf(stderr, "%lld.%d ms (%d rpm)",
267 				(tenthms - rotms) / 10,
268 				(int)((tenthms - rotms) % 10),
269 				rpm);
270 		}
271 		if (disc) fputc('\n', stdout);
272 	}
273 	return n < 0 ? 1 : 0;
274 }
275