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