1 /*- 2 * Copyright (c) 2003 Poul-Henning Kamp 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. The names of the authors may not be used to endorse or promote 14 * products derived from this software without specific prior written 15 * permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $FreeBSD$ 30 */ 31 32 #include <stdio.h> 33 #include <stdint.h> 34 #include <unistd.h> 35 #include <errno.h> 36 #include <fcntl.h> 37 #include <paths.h> 38 #include <err.h> 39 #include <sys/disk.h> 40 41 static void 42 usage(void) 43 { 44 fprintf(stderr, "Usage: diskinfo [-tv]\n"); 45 exit (1); 46 } 47 48 static int opt_t, opt_v; 49 50 static void speeddisk(const char *name, int fd, off_t mediasize, u_int sectorsize); 51 52 int 53 main(int argc, char **argv) 54 { 55 int i, ch, fd, error; 56 char buf[BUFSIZ]; 57 off_t mediasize; 58 u_int sectorsize, fwsectors, fwheads; 59 60 while ((ch = getopt(argc, argv, "tv")) != -1) { 61 switch (ch) { 62 case 't': 63 opt_t = 1; 64 opt_v = 1; 65 break; 66 case 'v': 67 opt_v = 1; 68 break; 69 default: 70 usage(); 71 } 72 } 73 argc -= optind; 74 argv += optind; 75 76 for (i = 0; i < argc; i++) { 77 fd = open(argv[i], O_RDONLY); 78 if (fd < 0 && errno == ENOENT && *argv[i] != '/') { 79 sprintf(buf, "%s%s", _PATH_DEV, argv[i]); 80 fd = open(buf, O_RDONLY); 81 } 82 if (fd < 0) 83 err(1, argv[i]); 84 error = ioctl(fd, DIOCGMEDIASIZE, &mediasize); 85 if (error) 86 err(1, "%s: ioctl(DIOCGMEDIASIZE) failed, probably not a disk.", argv[i]); 87 error = ioctl(fd, DIOCGSECTORSIZE, §orsize); 88 if (error) 89 err(1, "%s: DIOCGSECTORSIZE failed, probably not a disk.", argv[i]); 90 error = ioctl(fd, DIOCGFWSECTORS, &fwsectors); 91 if (error) 92 fwsectors = 0; 93 error = ioctl(fd, DIOCGFWHEADS, &fwheads); 94 if (error) 95 fwheads = 0; 96 if (!opt_v) { 97 printf("%s", argv[i]); 98 printf("\t%u", sectorsize); 99 printf("\t%jd", (intmax_t)mediasize); 100 printf("\t%jd", (intmax_t)mediasize/sectorsize); 101 if (fwsectors != 0 && fwheads != 0) { 102 printf("\t%jd", (intmax_t)mediasize / 103 (fwsectors * fwheads * sectorsize)); 104 printf("\t%u", fwheads); 105 printf("\t%u", fwsectors); 106 } 107 } else { 108 printf("%s\n", argv[i]); 109 printf("\t%-12u\t# sectorsize\n", sectorsize); 110 printf("\t%-12jd\t# mediasize in bytes\n", 111 (intmax_t)mediasize); 112 printf("\t%-12jd\t# mediasize in sectors\n", 113 (intmax_t)mediasize/sectorsize); 114 if (fwsectors != 0 && fwheads != 0) { 115 printf("\t%-12jd\t# Cylinders according to firmware.\n", (intmax_t)mediasize / 116 (fwsectors * fwheads * sectorsize)); 117 printf("\t%-12u\t# Heads according to firmware.\n", fwheads); 118 printf("\t%-12u\t# Sectors according to firmware.\n", fwsectors); 119 } 120 } 121 printf("\n"); 122 if (opt_t) 123 speeddisk(argv[i], fd, mediasize, sectorsize); 124 close(fd); 125 } 126 exit (0); 127 } 128 129 130 static char sector[65536]; 131 static char mega[1024 * 1024]; 132 133 static void 134 rdsect(int fd, u_int blockno, u_int sectorsize) 135 { 136 int error; 137 138 lseek(fd, (off_t)blockno * sectorsize, SEEK_SET); 139 error = read(fd, sector, sectorsize); 140 if (error != sectorsize) 141 err(1, "read error or disk too small for test."); 142 } 143 144 static void 145 rdmega(int fd) 146 { 147 int error; 148 149 error = read(fd, mega, sizeof(mega)); 150 if (error != sizeof(mega)) 151 err(1, "read error or disk too small for test."); 152 } 153 154 static struct timeval tv1, tv2; 155 156 static void 157 T0(void) 158 { 159 160 fflush(stdout); 161 sync(); 162 sleep(1); 163 sync(); 164 sync(); 165 gettimeofday(&tv1, NULL); 166 } 167 168 static void 169 TN(int count) 170 { 171 double dt; 172 173 gettimeofday(&tv2, NULL); 174 dt = (tv2.tv_usec - tv1.tv_usec) / 1e6; 175 dt += (tv2.tv_sec - tv1.tv_sec); 176 printf("%5d iter in %10.6f sec = %8.3f msec\n", 177 count, dt, dt * 1000.0 / count); 178 } 179 180 static void 181 TR(double count) 182 { 183 double dt; 184 185 gettimeofday(&tv2, NULL); 186 dt = (tv2.tv_usec - tv1.tv_usec) / 1e6; 187 dt += (tv2.tv_sec - tv1.tv_sec); 188 printf("%8.0f kbytes in %10.6f sec = %8.0f kbytes/sec\n", 189 count, dt, count / dt); 190 } 191 192 static void 193 speeddisk(const char *name, int fd, off_t mediasize, u_int sectorsize) 194 { 195 int error, i; 196 uint b0, b1, sectorcount; 197 198 off_t size; 199 sectorcount = mediasize / sectorsize; 200 201 printf("Seek times:\n"); 202 printf("\tFull stroke:\t"); 203 b0 = 0; 204 b1 = sectorcount - 1 - 16384; 205 T0(); 206 for (i = 0; i < 125; i++) { 207 rdsect(fd, b0, sectorsize); 208 b0 += 16384; 209 rdsect(fd, b1, sectorsize); 210 b1 -= 16384; 211 } 212 TN(250); 213 214 printf("\tHalf stroke:\t"); 215 b0 = sectorcount / 4; 216 b1 = b0 + sectorcount / 2; 217 T0(); 218 for (i = 0; i < 125; i++) { 219 rdsect(fd, b0, sectorsize); 220 b0 += 16384; 221 rdsect(fd, b1, sectorsize); 222 b1 += 16384; 223 } 224 TN(250); 225 printf("\tQuarter stroke:\t"); 226 b0 = sectorcount / 4; 227 b1 = b0 + sectorcount / 4; 228 T0(); 229 for (i = 0; i < 250; i++) { 230 rdsect(fd, b0, sectorsize); 231 b0 += 16384; 232 rdsect(fd, b1, sectorsize); 233 b1 += 16384; 234 } 235 TN(500); 236 237 printf("\tShort forward:\t"); 238 b0 = sectorcount / 2; 239 T0(); 240 for (i = 0; i < 400; i++) { 241 rdsect(fd, b0, sectorsize); 242 b0 += 16384; 243 } 244 TN(400); 245 246 printf("\tShort backward:\t"); 247 b0 = sectorcount / 2; 248 T0(); 249 for (i = 0; i < 400; i++) { 250 rdsect(fd, b0, sectorsize); 251 b0 -= 16384; 252 } 253 TN(400); 254 255 printf("\tSeq outer:\t"); 256 b0 = 0; 257 T0(); 258 for (i = 0; i < 2048; i++) { 259 rdsect(fd, b0, sectorsize); 260 b0++; 261 } 262 TN(2048); 263 264 printf("\tSeq inner:\t"); 265 b0 = sectorcount - 2048 - 1; 266 T0(); 267 for (i = 0; i < 2048; i++) { 268 rdsect(fd, b0, sectorsize); 269 b0++; 270 } 271 TN(2048); 272 273 printf("Transfer rates:\n"); 274 printf("\toutside: "); 275 rdsect(fd, 0, sectorsize); 276 T0(); 277 for (i = 0; i < 100; i++) { 278 rdmega(fd); 279 } 280 TR(100 * 1024); 281 282 printf("\tmiddle: "); 283 b0 = sectorcount / 2; 284 rdsect(fd, b0, sectorsize); 285 T0(); 286 for (i = 0; i < 100; i++) { 287 rdmega(fd); 288 } 289 TR(100 * 1024); 290 291 printf("\tinside: "); 292 b0 = sectorcount - 100 * (1024*1024 / sectorsize) - 1;; 293 rdsect(fd, b0, sectorsize); 294 T0(); 295 for (i = 0; i < 100; i++) { 296 rdmega(fd); 297 } 298 TR(100 * 1024); 299 300 printf("\n"); 301 302 return; 303 } 304