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 <stdlib.h> 35 #include <unistd.h> 36 #include <errno.h> 37 #include <fcntl.h> 38 #include <paths.h> 39 #include <err.h> 40 #include <sys/disk.h> 41 #include <sys/time.h> 42 43 static void 44 usage(void) 45 { 46 fprintf(stderr, "usage: diskinfo [-tv] disk ...\n"); 47 exit (1); 48 } 49 50 static int opt_t, opt_v; 51 52 static void speeddisk(int fd, off_t mediasize, u_int sectorsize); 53 54 int 55 main(int argc, char **argv) 56 { 57 int i, ch, fd, error; 58 char buf[BUFSIZ]; 59 off_t mediasize; 60 u_int sectorsize, fwsectors, fwheads; 61 62 while ((ch = getopt(argc, argv, "tv")) != -1) { 63 switch (ch) { 64 case 't': 65 opt_t = 1; 66 opt_v = 1; 67 break; 68 case 'v': 69 opt_v = 1; 70 break; 71 default: 72 usage(); 73 } 74 } 75 argc -= optind; 76 argv += optind; 77 78 if (argc < 1) 79 usage(); 80 81 for (i = 0; i < argc; i++) { 82 fd = open(argv[i], O_RDONLY); 83 if (fd < 0 && errno == ENOENT && *argv[i] != '/') { 84 sprintf(buf, "%s%s", _PATH_DEV, argv[i]); 85 fd = open(buf, O_RDONLY); 86 } 87 if (fd < 0) 88 err(1, argv[i]); 89 error = ioctl(fd, DIOCGMEDIASIZE, &mediasize); 90 if (error) 91 err(1, "%s: ioctl(DIOCGMEDIASIZE) failed, probably not a disk.", argv[i]); 92 error = ioctl(fd, DIOCGSECTORSIZE, §orsize); 93 if (error) 94 err(1, "%s: DIOCGSECTORSIZE failed, probably not a disk.", argv[i]); 95 error = ioctl(fd, DIOCGFWSECTORS, &fwsectors); 96 if (error) 97 fwsectors = 0; 98 error = ioctl(fd, DIOCGFWHEADS, &fwheads); 99 if (error) 100 fwheads = 0; 101 if (!opt_v) { 102 printf("%s", argv[i]); 103 printf("\t%u", sectorsize); 104 printf("\t%jd", (intmax_t)mediasize); 105 printf("\t%jd", (intmax_t)mediasize/sectorsize); 106 if (fwsectors != 0 && fwheads != 0) { 107 printf("\t%jd", (intmax_t)mediasize / 108 (fwsectors * fwheads * sectorsize)); 109 printf("\t%u", fwheads); 110 printf("\t%u", fwsectors); 111 } 112 } else { 113 printf("%s\n", argv[i]); 114 printf("\t%-12u\t# sectorsize\n", sectorsize); 115 printf("\t%-12jd\t# mediasize in bytes\n", 116 (intmax_t)mediasize); 117 printf("\t%-12jd\t# mediasize in sectors\n", 118 (intmax_t)mediasize/sectorsize); 119 if (fwsectors != 0 && fwheads != 0) { 120 printf("\t%-12jd\t# Cylinders according to firmware.\n", (intmax_t)mediasize / 121 (fwsectors * fwheads * sectorsize)); 122 printf("\t%-12u\t# Heads according to firmware.\n", fwheads); 123 printf("\t%-12u\t# Sectors according to firmware.\n", fwsectors); 124 } 125 } 126 printf("\n"); 127 if (opt_t) 128 speeddisk(fd, mediasize, sectorsize); 129 close(fd); 130 } 131 exit (0); 132 } 133 134 135 static char sector[65536]; 136 static char mega[1024 * 1024]; 137 138 static void 139 rdsect(int fd, u_int blockno, u_int sectorsize) 140 { 141 int error; 142 143 lseek(fd, (off_t)blockno * sectorsize, SEEK_SET); 144 error = read(fd, sector, sectorsize); 145 if (error != (int)sectorsize) 146 err(1, "read error or disk too small for test."); 147 } 148 149 static void 150 rdmega(int fd) 151 { 152 int error; 153 154 error = read(fd, mega, sizeof(mega)); 155 if (error != sizeof(mega)) 156 err(1, "read error or disk too small for test."); 157 } 158 159 static struct timeval tv1, tv2; 160 161 static void 162 T0(void) 163 { 164 165 fflush(stdout); 166 sync(); 167 sleep(1); 168 sync(); 169 sync(); 170 gettimeofday(&tv1, NULL); 171 } 172 173 static void 174 TN(int count) 175 { 176 double dt; 177 178 gettimeofday(&tv2, NULL); 179 dt = (tv2.tv_usec - tv1.tv_usec) / 1e6; 180 dt += (tv2.tv_sec - tv1.tv_sec); 181 printf("%5d iter in %10.6f sec = %8.3f msec\n", 182 count, dt, dt * 1000.0 / count); 183 } 184 185 static void 186 TR(double count) 187 { 188 double dt; 189 190 gettimeofday(&tv2, NULL); 191 dt = (tv2.tv_usec - tv1.tv_usec) / 1e6; 192 dt += (tv2.tv_sec - tv1.tv_sec); 193 printf("%8.0f kbytes in %10.6f sec = %8.0f kbytes/sec\n", 194 count, dt, count / dt); 195 } 196 197 static void 198 speeddisk(int fd, off_t mediasize, u_int sectorsize) 199 { 200 int i; 201 uint b0, b1, sectorcount; 202 203 sectorcount = mediasize / sectorsize; 204 205 printf("Seek times:\n"); 206 printf("\tFull stroke:\t"); 207 b0 = 0; 208 b1 = sectorcount - 1 - 16384; 209 T0(); 210 for (i = 0; i < 125; i++) { 211 rdsect(fd, b0, sectorsize); 212 b0 += 16384; 213 rdsect(fd, b1, sectorsize); 214 b1 -= 16384; 215 } 216 TN(250); 217 218 printf("\tHalf stroke:\t"); 219 b0 = sectorcount / 4; 220 b1 = b0 + sectorcount / 2; 221 T0(); 222 for (i = 0; i < 125; i++) { 223 rdsect(fd, b0, sectorsize); 224 b0 += 16384; 225 rdsect(fd, b1, sectorsize); 226 b1 += 16384; 227 } 228 TN(250); 229 printf("\tQuarter stroke:\t"); 230 b0 = sectorcount / 4; 231 b1 = b0 + sectorcount / 4; 232 T0(); 233 for (i = 0; i < 250; i++) { 234 rdsect(fd, b0, sectorsize); 235 b0 += 16384; 236 rdsect(fd, b1, sectorsize); 237 b1 += 16384; 238 } 239 TN(500); 240 241 printf("\tShort forward:\t"); 242 b0 = sectorcount / 2; 243 T0(); 244 for (i = 0; i < 400; i++) { 245 rdsect(fd, b0, sectorsize); 246 b0 += 16384; 247 } 248 TN(400); 249 250 printf("\tShort backward:\t"); 251 b0 = sectorcount / 2; 252 T0(); 253 for (i = 0; i < 400; i++) { 254 rdsect(fd, b0, sectorsize); 255 b0 -= 16384; 256 } 257 TN(400); 258 259 printf("\tSeq outer:\t"); 260 b0 = 0; 261 T0(); 262 for (i = 0; i < 2048; i++) { 263 rdsect(fd, b0, sectorsize); 264 b0++; 265 } 266 TN(2048); 267 268 printf("\tSeq inner:\t"); 269 b0 = sectorcount - 2048 - 1; 270 T0(); 271 for (i = 0; i < 2048; i++) { 272 rdsect(fd, b0, sectorsize); 273 b0++; 274 } 275 TN(2048); 276 277 printf("Transfer rates:\n"); 278 printf("\toutside: "); 279 rdsect(fd, 0, sectorsize); 280 T0(); 281 for (i = 0; i < 100; i++) { 282 rdmega(fd); 283 } 284 TR(100 * 1024); 285 286 printf("\tmiddle: "); 287 b0 = sectorcount / 2; 288 rdsect(fd, b0, sectorsize); 289 T0(); 290 for (i = 0; i < 100; i++) { 291 rdmega(fd); 292 } 293 TR(100 * 1024); 294 295 printf("\tinside: "); 296 b0 = sectorcount - 100 * (1024*1024 / sectorsize) - 1;; 297 rdsect(fd, b0, sectorsize); 298 T0(); 299 for (i = 0; i < 100; i++) { 300 rdmega(fd); 301 } 302 TR(100 * 1024); 303 304 printf("\n"); 305 306 return; 307 } 308