diskinfo.c revision 313103
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: stable/10/usr.sbin/diskinfo/diskinfo.c 313103 2017-02-02 19:50:28Z asomers $ 30 */ 31 32#include <stdio.h> 33#include <stdint.h> 34#include <stdlib.h> 35#include <strings.h> 36#include <unistd.h> 37#include <errno.h> 38#include <fcntl.h> 39#include <libutil.h> 40#include <paths.h> 41#include <err.h> 42#include <sys/disk.h> 43#include <sys/param.h> 44#include <sys/time.h> 45 46static void 47usage(void) 48{ 49 fprintf(stderr, "usage: diskinfo [-ctv] disk ...\n"); 50 exit (1); 51} 52 53static int opt_c, opt_t, opt_v; 54 55static void speeddisk(int fd, off_t mediasize, u_int sectorsize); 56static void commandtime(int fd, off_t mediasize, u_int sectorsize); 57 58int 59main(int argc, char **argv) 60{ 61 int i, ch, fd, error, exitval = 0; 62 char buf[BUFSIZ], ident[DISK_IDENT_SIZE], physpath[MAXPATHLEN]; 63 off_t mediasize, stripesize, stripeoffset; 64 u_int sectorsize, fwsectors, fwheads; 65 66 while ((ch = getopt(argc, argv, "ctv")) != -1) { 67 switch (ch) { 68 case 'c': 69 opt_c = 1; 70 opt_v = 1; 71 break; 72 case 't': 73 opt_t = 1; 74 opt_v = 1; 75 break; 76 case 'v': 77 opt_v = 1; 78 break; 79 default: 80 usage(); 81 } 82 } 83 argc -= optind; 84 argv += optind; 85 86 if (argc < 1) 87 usage(); 88 89 for (i = 0; i < argc; i++) { 90 fd = open(argv[i], O_RDONLY); 91 if (fd < 0 && errno == ENOENT && *argv[i] != '/') { 92 snprintf(buf, BUFSIZ, "%s%s", _PATH_DEV, argv[i]); 93 fd = open(buf, O_RDONLY); 94 } 95 if (fd < 0) { 96 warn("%s", argv[i]); 97 exit(1); 98 } 99 error = ioctl(fd, DIOCGMEDIASIZE, &mediasize); 100 if (error) { 101 warnx("%s: ioctl(DIOCGMEDIASIZE) failed, probably not a disk.", argv[i]); 102 exitval = 1; 103 goto out; 104 } 105 error = ioctl(fd, DIOCGSECTORSIZE, §orsize); 106 if (error) { 107 warnx("%s: ioctl(DIOCGSECTORSIZE) failed, probably not a disk.", argv[i]); 108 exitval = 1; 109 goto out; 110 } 111 error = ioctl(fd, DIOCGFWSECTORS, &fwsectors); 112 if (error) 113 fwsectors = 0; 114 error = ioctl(fd, DIOCGFWHEADS, &fwheads); 115 if (error) 116 fwheads = 0; 117 error = ioctl(fd, DIOCGSTRIPESIZE, &stripesize); 118 if (error) 119 stripesize = 0; 120 error = ioctl(fd, DIOCGSTRIPEOFFSET, &stripeoffset); 121 if (error) 122 stripeoffset = 0; 123 if (!opt_v) { 124 printf("%s", argv[i]); 125 printf("\t%u", sectorsize); 126 printf("\t%jd", (intmax_t)mediasize); 127 printf("\t%jd", (intmax_t)mediasize/sectorsize); 128 printf("\t%jd", (intmax_t)stripesize); 129 printf("\t%jd", (intmax_t)stripeoffset); 130 if (fwsectors != 0 && fwheads != 0) { 131 printf("\t%jd", (intmax_t)mediasize / 132 (fwsectors * fwheads * sectorsize)); 133 printf("\t%u", fwheads); 134 printf("\t%u", fwsectors); 135 } 136 } else { 137 humanize_number(buf, 5, (int64_t)mediasize, "", 138 HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); 139 printf("%s\n", argv[i]); 140 printf("\t%-12u\t# sectorsize\n", sectorsize); 141 printf("\t%-12jd\t# mediasize in bytes (%s)\n", 142 (intmax_t)mediasize, buf); 143 printf("\t%-12jd\t# mediasize in sectors\n", 144 (intmax_t)mediasize/sectorsize); 145 printf("\t%-12jd\t# stripesize\n", stripesize); 146 printf("\t%-12jd\t# stripeoffset\n", stripeoffset); 147 if (fwsectors != 0 && fwheads != 0) { 148 printf("\t%-12jd\t# Cylinders according to firmware.\n", (intmax_t)mediasize / 149 (fwsectors * fwheads * sectorsize)); 150 printf("\t%-12u\t# Heads according to firmware.\n", fwheads); 151 printf("\t%-12u\t# Sectors according to firmware.\n", fwsectors); 152 } 153 if (ioctl(fd, DIOCGIDENT, ident) == 0) 154 printf("\t%-12s\t# Disk ident.\n", ident); 155 if (ioctl(fd, DIOCGPHYSPATH, physpath) == 0) 156 printf("\t%-12s\t# Physical path\n", physpath); 157 } 158 printf("\n"); 159 if (opt_c) 160 commandtime(fd, mediasize, sectorsize); 161 if (opt_t) 162 speeddisk(fd, mediasize, sectorsize); 163out: 164 close(fd); 165 } 166 exit (exitval); 167} 168 169 170static char sector[65536]; 171static char mega[1024 * 1024]; 172 173static void 174rdsect(int fd, off_t blockno, u_int sectorsize) 175{ 176 int error; 177 178 if (lseek(fd, (off_t)blockno * sectorsize, SEEK_SET) == -1) 179 err(1, "lseek"); 180 error = read(fd, sector, sectorsize); 181 if (error == -1) 182 err(1, "read"); 183 if (error != (int)sectorsize) 184 errx(1, "disk too small for test."); 185} 186 187static void 188rdmega(int fd) 189{ 190 int error; 191 192 error = read(fd, mega, sizeof(mega)); 193 if (error == -1) 194 err(1, "read"); 195 if (error != sizeof(mega)) 196 errx(1, "disk too small for test."); 197} 198 199static struct timeval tv1, tv2; 200 201static void 202T0(void) 203{ 204 205 fflush(stdout); 206 sync(); 207 sleep(1); 208 sync(); 209 sync(); 210 gettimeofday(&tv1, NULL); 211} 212 213static void 214TN(int count) 215{ 216 double dt; 217 218 gettimeofday(&tv2, NULL); 219 dt = (tv2.tv_usec - tv1.tv_usec) / 1e6; 220 dt += (tv2.tv_sec - tv1.tv_sec); 221 printf("%5d iter in %10.6f sec = %8.3f msec\n", 222 count, dt, dt * 1000.0 / count); 223} 224 225static void 226TR(double count) 227{ 228 double dt; 229 230 gettimeofday(&tv2, NULL); 231 dt = (tv2.tv_usec - tv1.tv_usec) / 1e6; 232 dt += (tv2.tv_sec - tv1.tv_sec); 233 printf("%8.0f kbytes in %10.6f sec = %8.0f kbytes/sec\n", 234 count, dt, count / dt); 235} 236 237static void 238speeddisk(int fd, off_t mediasize, u_int sectorsize) 239{ 240 int bulk, i; 241 off_t b0, b1, sectorcount, step; 242 243 sectorcount = mediasize / sectorsize; 244 if (sectorcount <= 0) 245 return; /* Can't test devices with no sectors */ 246 247 step = 1ULL << (flsll(sectorcount / (4 * 200)) - 1); 248 if (step > 16384) 249 step = 16384; 250 bulk = mediasize / (1024 * 1024); 251 if (bulk > 100) 252 bulk = 100; 253 254 printf("Seek times:\n"); 255 printf("\tFull stroke:\t"); 256 b0 = 0; 257 b1 = sectorcount - step; 258 T0(); 259 for (i = 0; i < 125; i++) { 260 rdsect(fd, b0, sectorsize); 261 b0 += step; 262 rdsect(fd, b1, sectorsize); 263 b1 -= step; 264 } 265 TN(250); 266 267 printf("\tHalf stroke:\t"); 268 b0 = sectorcount / 4; 269 b1 = b0 + sectorcount / 2; 270 T0(); 271 for (i = 0; i < 125; i++) { 272 rdsect(fd, b0, sectorsize); 273 b0 += step; 274 rdsect(fd, b1, sectorsize); 275 b1 += step; 276 } 277 TN(250); 278 printf("\tQuarter stroke:\t"); 279 b0 = sectorcount / 4; 280 b1 = b0 + sectorcount / 4; 281 T0(); 282 for (i = 0; i < 250; i++) { 283 rdsect(fd, b0, sectorsize); 284 b0 += step; 285 rdsect(fd, b1, sectorsize); 286 b1 += step; 287 } 288 TN(500); 289 290 printf("\tShort forward:\t"); 291 b0 = sectorcount / 2; 292 T0(); 293 for (i = 0; i < 400; i++) { 294 rdsect(fd, b0, sectorsize); 295 b0 += step; 296 } 297 TN(400); 298 299 printf("\tShort backward:\t"); 300 b0 = sectorcount / 2; 301 T0(); 302 for (i = 0; i < 400; i++) { 303 rdsect(fd, b0, sectorsize); 304 b0 -= step; 305 } 306 TN(400); 307 308 printf("\tSeq outer:\t"); 309 b0 = 0; 310 T0(); 311 for (i = 0; i < 2048; i++) { 312 rdsect(fd, b0, sectorsize); 313 b0++; 314 } 315 TN(2048); 316 317 printf("\tSeq inner:\t"); 318 b0 = sectorcount - 2048; 319 T0(); 320 for (i = 0; i < 2048; i++) { 321 rdsect(fd, b0, sectorsize); 322 b0++; 323 } 324 TN(2048); 325 326 printf("Transfer rates:\n"); 327 printf("\toutside: "); 328 rdsect(fd, 0, sectorsize); 329 T0(); 330 for (i = 0; i < bulk; i++) { 331 rdmega(fd); 332 } 333 TR(bulk * 1024); 334 335 printf("\tmiddle: "); 336 b0 = sectorcount / 2 - bulk * (1024*1024 / sectorsize) / 2 - 1; 337 rdsect(fd, b0, sectorsize); 338 T0(); 339 for (i = 0; i < bulk; i++) { 340 rdmega(fd); 341 } 342 TR(bulk * 1024); 343 344 printf("\tinside: "); 345 b0 = sectorcount - bulk * (1024*1024 / sectorsize) - 1; 346 rdsect(fd, b0, sectorsize); 347 T0(); 348 for (i = 0; i < bulk; i++) { 349 rdmega(fd); 350 } 351 TR(bulk * 1024); 352 353 printf("\n"); 354 return; 355} 356 357static void 358commandtime(int fd, off_t mediasize, u_int sectorsize) 359{ 360 double dtmega, dtsector; 361 int i; 362 363 printf("I/O command overhead:\n"); 364 i = mediasize; 365 rdsect(fd, 0, sectorsize); 366 T0(); 367 for (i = 0; i < 10; i++) 368 rdmega(fd); 369 gettimeofday(&tv2, NULL); 370 dtmega = (tv2.tv_usec - tv1.tv_usec) / 1e6; 371 dtmega += (tv2.tv_sec - tv1.tv_sec); 372 373 printf("\ttime to read 10MB block %10.6f sec\t= %8.3f msec/sector\n", 374 dtmega, dtmega*100/2048); 375 376 rdsect(fd, 0, sectorsize); 377 T0(); 378 for (i = 0; i < 20480; i++) 379 rdsect(fd, 0, sectorsize); 380 gettimeofday(&tv2, NULL); 381 dtsector = (tv2.tv_usec - tv1.tv_usec) / 1e6; 382 dtsector += (tv2.tv_sec - tv1.tv_sec); 383 384 printf("\ttime to read 20480 sectors %10.6f sec\t= %8.3f msec/sector\n", 385 dtsector, dtsector*100/2048); 386 printf("\tcalculated command overhead\t\t\t= %8.3f msec/sector\n", 387 (dtsector - dtmega)*100/2048); 388 389 printf("\n"); 390 return; 391} 392