1113287Sphk/*- 2113287Sphk * Copyright (c) 2003 Poul-Henning Kamp 3113287Sphk * All rights reserved. 4113287Sphk * 5113287Sphk * Redistribution and use in source and binary forms, with or without 6113287Sphk * modification, are permitted provided that the following conditions 7113287Sphk * are met: 8113287Sphk * 1. Redistributions of source code must retain the above copyright 9113287Sphk * notice, this list of conditions and the following disclaimer. 10113287Sphk * 2. Redistributions in binary form must reproduce the above copyright 11113287Sphk * notice, this list of conditions and the following disclaimer in the 12113287Sphk * documentation and/or other materials provided with the distribution. 13113287Sphk * 3. The names of the authors may not be used to endorse or promote 14113287Sphk * products derived from this software without specific prior written 15113287Sphk * permission. 16113287Sphk * 17113287Sphk * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18113287Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19113287Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20113287Sphk * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21113287Sphk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22113287Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23113287Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24113287Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25113287Sphk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26113287Sphk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27113287Sphk * SUCH DAMAGE. 28113287Sphk * 29113287Sphk * $FreeBSD$ 30113287Sphk */ 31113287Sphk 32113287Sphk#include <stdio.h> 33113287Sphk#include <stdint.h> 34127884Sphk#include <stdlib.h> 35224250Smav#include <strings.h> 36113287Sphk#include <unistd.h> 37113287Sphk#include <errno.h> 38113287Sphk#include <fcntl.h> 39129679Spjd#include <libutil.h> 40113287Sphk#include <paths.h> 41113287Sphk#include <err.h> 42113287Sphk#include <sys/disk.h> 43223089Sgibbs#include <sys/param.h> 44127884Sphk#include <sys/time.h> 45113287Sphk 46113287Sphkstatic void 47113287Sphkusage(void) 48113287Sphk{ 49140058Sru fprintf(stderr, "usage: diskinfo [-ctv] disk ...\n"); 50113287Sphk exit (1); 51113287Sphk} 52113287Sphk 53137456Ssosstatic int opt_c, opt_t, opt_v; 54113287Sphk 55127884Sphkstatic void speeddisk(int fd, off_t mediasize, u_int sectorsize); 56137456Ssosstatic void commandtime(int fd, off_t mediasize, u_int sectorsize); 57113287Sphk 58113287Sphkint 59113287Sphkmain(int argc, char **argv) 60113287Sphk{ 61218432Sdelphij int i, ch, fd, error, exitval = 0; 62223089Sgibbs char buf[BUFSIZ], ident[DISK_IDENT_SIZE], physpath[MAXPATHLEN]; 63200968Smav off_t mediasize, stripesize, stripeoffset; 64113287Sphk u_int sectorsize, fwsectors, fwheads; 65113287Sphk 66137456Ssos while ((ch = getopt(argc, argv, "ctv")) != -1) { 67113287Sphk switch (ch) { 68137456Ssos case 'c': 69137456Ssos opt_c = 1; 70137456Ssos opt_v = 1; 71137456Ssos break; 72113287Sphk case 't': 73113287Sphk opt_t = 1; 74113287Sphk opt_v = 1; 75113287Sphk break; 76113287Sphk case 'v': 77113287Sphk opt_v = 1; 78113287Sphk break; 79113287Sphk default: 80113287Sphk usage(); 81113287Sphk } 82113287Sphk } 83113287Sphk argc -= optind; 84113287Sphk argv += optind; 85113287Sphk 86127610Sru if (argc < 1) 87127610Sru usage(); 88127610Sru 89113287Sphk for (i = 0; i < argc; i++) { 90113287Sphk fd = open(argv[i], O_RDONLY); 91113287Sphk if (fd < 0 && errno == ENOENT && *argv[i] != '/') { 92113287Sphk sprintf(buf, "%s%s", _PATH_DEV, argv[i]); 93113287Sphk fd = open(buf, O_RDONLY); 94113287Sphk } 95218432Sdelphij if (fd < 0) { 96218432Sdelphij warn("%s", argv[i]); 97218432Sdelphij exitval = 1; 98218432Sdelphij goto out; 99218432Sdelphij } 100113287Sphk error = ioctl(fd, DIOCGMEDIASIZE, &mediasize); 101218432Sdelphij if (error) { 102232738Strasz warnx("%s: ioctl(DIOCGMEDIASIZE) failed, probably not a disk.", argv[i]); 103218432Sdelphij exitval = 1; 104218432Sdelphij goto out; 105218432Sdelphij } 106113287Sphk error = ioctl(fd, DIOCGSECTORSIZE, §orsize); 107218432Sdelphij if (error) { 108232738Strasz warnx("%s: ioctl(DIOCGSECTORSIZE) failed, probably not a disk.", argv[i]); 109218432Sdelphij exitval = 1; 110218432Sdelphij goto out; 111218432Sdelphij } 112113287Sphk error = ioctl(fd, DIOCGFWSECTORS, &fwsectors); 113113287Sphk if (error) 114113287Sphk fwsectors = 0; 115113287Sphk error = ioctl(fd, DIOCGFWHEADS, &fwheads); 116113287Sphk if (error) 117113287Sphk fwheads = 0; 118200968Smav error = ioctl(fd, DIOCGSTRIPESIZE, &stripesize); 119200968Smav if (error) 120200968Smav stripesize = 0; 121200968Smav error = ioctl(fd, DIOCGSTRIPEOFFSET, &stripeoffset); 122200968Smav if (error) 123200968Smav stripeoffset = 0; 124113287Sphk if (!opt_v) { 125113287Sphk printf("%s", argv[i]); 126113287Sphk printf("\t%u", sectorsize); 127113287Sphk printf("\t%jd", (intmax_t)mediasize); 128113287Sphk printf("\t%jd", (intmax_t)mediasize/sectorsize); 129200968Smav printf("\t%jd", (intmax_t)stripesize); 130200968Smav printf("\t%jd", (intmax_t)stripeoffset); 131113287Sphk if (fwsectors != 0 && fwheads != 0) { 132113287Sphk printf("\t%jd", (intmax_t)mediasize / 133113287Sphk (fwsectors * fwheads * sectorsize)); 134113287Sphk printf("\t%u", fwheads); 135113287Sphk printf("\t%u", fwsectors); 136113287Sphk } 137113287Sphk } else { 138129712Spjd humanize_number(buf, 5, (int64_t)mediasize, "", 139129679Spjd HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); 140113287Sphk printf("%s\n", argv[i]); 141113287Sphk printf("\t%-12u\t# sectorsize\n", sectorsize); 142129679Spjd printf("\t%-12jd\t# mediasize in bytes (%s)\n", 143129679Spjd (intmax_t)mediasize, buf); 144113287Sphk printf("\t%-12jd\t# mediasize in sectors\n", 145113287Sphk (intmax_t)mediasize/sectorsize); 146200968Smav printf("\t%-12jd\t# stripesize\n", stripesize); 147200968Smav printf("\t%-12jd\t# stripeoffset\n", stripeoffset); 148113287Sphk if (fwsectors != 0 && fwheads != 0) { 149113287Sphk printf("\t%-12jd\t# Cylinders according to firmware.\n", (intmax_t)mediasize / 150113287Sphk (fwsectors * fwheads * sectorsize)); 151113287Sphk printf("\t%-12u\t# Heads according to firmware.\n", fwheads); 152113287Sphk printf("\t%-12u\t# Sectors according to firmware.\n", fwsectors); 153113287Sphk } 154196799Spjd if (ioctl(fd, DIOCGIDENT, ident) == 0) 155169296Spjd printf("\t%-12s\t# Disk ident.\n", ident); 156223089Sgibbs if (ioctl(fd, DIOCGPHYSPATH, physpath) == 0) 157223089Sgibbs printf("\t%-12s\t# Physical path\n", physpath); 158113287Sphk } 159113287Sphk printf("\n"); 160137456Ssos if (opt_c) 161137456Ssos commandtime(fd, mediasize, sectorsize); 162113287Sphk if (opt_t) 163127884Sphk speeddisk(fd, mediasize, sectorsize); 164218432Sdelphijout: 165113287Sphk close(fd); 166113287Sphk } 167218432Sdelphij exit (exitval); 168113287Sphk} 169113287Sphk 170113287Sphk 171113287Sphkstatic char sector[65536]; 172113287Sphkstatic char mega[1024 * 1024]; 173113287Sphk 174113287Sphkstatic void 175224250Smavrdsect(int fd, off_t blockno, u_int sectorsize) 176113287Sphk{ 177113287Sphk int error; 178113287Sphk 179113295Sphk lseek(fd, (off_t)blockno * sectorsize, SEEK_SET); 180113287Sphk error = read(fd, sector, sectorsize); 181232738Strasz if (error == -1) 182232738Strasz err(1, "read"); 183127884Sphk if (error != (int)sectorsize) 184232738Strasz errx(1, "disk too small for test."); 185113287Sphk} 186113287Sphk 187113287Sphkstatic void 188113287Sphkrdmega(int fd) 189113287Sphk{ 190113287Sphk int error; 191113287Sphk 192113287Sphk error = read(fd, mega, sizeof(mega)); 193232738Strasz if (error == -1) 194232738Strasz err(1, "read"); 195113287Sphk if (error != sizeof(mega)) 196232738Strasz errx(1, "disk too small for test."); 197113287Sphk} 198113287Sphk 199113287Sphkstatic struct timeval tv1, tv2; 200113287Sphk 201113287Sphkstatic void 202113287SphkT0(void) 203113287Sphk{ 204113287Sphk 205113287Sphk fflush(stdout); 206113287Sphk sync(); 207113287Sphk sleep(1); 208113287Sphk sync(); 209113287Sphk sync(); 210113287Sphk gettimeofday(&tv1, NULL); 211113287Sphk} 212113287Sphk 213113287Sphkstatic void 214113287SphkTN(int count) 215113287Sphk{ 216113287Sphk double dt; 217113287Sphk 218113287Sphk gettimeofday(&tv2, NULL); 219113287Sphk dt = (tv2.tv_usec - tv1.tv_usec) / 1e6; 220113287Sphk dt += (tv2.tv_sec - tv1.tv_sec); 221113287Sphk printf("%5d iter in %10.6f sec = %8.3f msec\n", 222113287Sphk count, dt, dt * 1000.0 / count); 223113287Sphk} 224113287Sphk 225113287Sphkstatic void 226113287SphkTR(double count) 227113287Sphk{ 228113287Sphk double dt; 229113287Sphk 230113287Sphk gettimeofday(&tv2, NULL); 231113287Sphk dt = (tv2.tv_usec - tv1.tv_usec) / 1e6; 232113287Sphk dt += (tv2.tv_sec - tv1.tv_sec); 233113287Sphk printf("%8.0f kbytes in %10.6f sec = %8.0f kbytes/sec\n", 234113287Sphk count, dt, count / dt); 235113287Sphk} 236113287Sphk 237113287Sphkstatic void 238127884Sphkspeeddisk(int fd, off_t mediasize, u_int sectorsize) 239113287Sphk{ 240224250Smav int bulk, i; 241224250Smav off_t b0, b1, sectorcount, step; 242113287Sphk 243113287Sphk sectorcount = mediasize / sectorsize; 244224250Smav step = 1ULL << (flsll(sectorcount / (4 * 200)) - 1); 245224250Smav if (step > 16384) 246224250Smav step = 16384; 247224250Smav bulk = mediasize / (1024 * 1024); 248224250Smav if (bulk > 100) 249224250Smav bulk = 100; 250113287Sphk 251113287Sphk printf("Seek times:\n"); 252113287Sphk printf("\tFull stroke:\t"); 253113287Sphk b0 = 0; 254224250Smav b1 = sectorcount - step; 255113287Sphk T0(); 256113287Sphk for (i = 0; i < 125; i++) { 257113287Sphk rdsect(fd, b0, sectorsize); 258224250Smav b0 += step; 259113287Sphk rdsect(fd, b1, sectorsize); 260224250Smav b1 -= step; 261113287Sphk } 262113287Sphk TN(250); 263113287Sphk 264113287Sphk printf("\tHalf stroke:\t"); 265113287Sphk b0 = sectorcount / 4; 266113287Sphk b1 = b0 + sectorcount / 2; 267113287Sphk T0(); 268113287Sphk for (i = 0; i < 125; i++) { 269113287Sphk rdsect(fd, b0, sectorsize); 270224250Smav b0 += step; 271113287Sphk rdsect(fd, b1, sectorsize); 272224250Smav b1 += step; 273113287Sphk } 274113287Sphk TN(250); 275113287Sphk printf("\tQuarter stroke:\t"); 276113287Sphk b0 = sectorcount / 4; 277113287Sphk b1 = b0 + sectorcount / 4; 278113287Sphk T0(); 279113287Sphk for (i = 0; i < 250; i++) { 280113287Sphk rdsect(fd, b0, sectorsize); 281224250Smav b0 += step; 282113287Sphk rdsect(fd, b1, sectorsize); 283224250Smav b1 += step; 284113287Sphk } 285113287Sphk TN(500); 286113287Sphk 287113287Sphk printf("\tShort forward:\t"); 288113287Sphk b0 = sectorcount / 2; 289113287Sphk T0(); 290113295Sphk for (i = 0; i < 400; i++) { 291113287Sphk rdsect(fd, b0, sectorsize); 292224250Smav b0 += step; 293113287Sphk } 294113295Sphk TN(400); 295113287Sphk 296113287Sphk printf("\tShort backward:\t"); 297113287Sphk b0 = sectorcount / 2; 298113287Sphk T0(); 299113295Sphk for (i = 0; i < 400; i++) { 300113287Sphk rdsect(fd, b0, sectorsize); 301224250Smav b0 -= step; 302113287Sphk } 303113295Sphk TN(400); 304113287Sphk 305113287Sphk printf("\tSeq outer:\t"); 306113287Sphk b0 = 0; 307113287Sphk T0(); 308113295Sphk for (i = 0; i < 2048; i++) { 309113287Sphk rdsect(fd, b0, sectorsize); 310113287Sphk b0++; 311113287Sphk } 312113295Sphk TN(2048); 313113287Sphk 314113287Sphk printf("\tSeq inner:\t"); 315224250Smav b0 = sectorcount - 2048; 316113287Sphk T0(); 317113295Sphk for (i = 0; i < 2048; i++) { 318113287Sphk rdsect(fd, b0, sectorsize); 319113287Sphk b0++; 320113287Sphk } 321113295Sphk TN(2048); 322113287Sphk 323113287Sphk printf("Transfer rates:\n"); 324113287Sphk printf("\toutside: "); 325113287Sphk rdsect(fd, 0, sectorsize); 326113287Sphk T0(); 327224250Smav for (i = 0; i < bulk; i++) { 328113287Sphk rdmega(fd); 329113287Sphk } 330224250Smav TR(bulk * 1024); 331113287Sphk 332113287Sphk printf("\tmiddle: "); 333224250Smav b0 = sectorcount / 2 - bulk * (1024*1024 / sectorsize) / 2 - 1; 334113287Sphk rdsect(fd, b0, sectorsize); 335113287Sphk T0(); 336224250Smav for (i = 0; i < bulk; i++) { 337113287Sphk rdmega(fd); 338113287Sphk } 339224250Smav TR(bulk * 1024); 340113287Sphk 341113287Sphk printf("\tinside: "); 342241844Seadler b0 = sectorcount - bulk * (1024*1024 / sectorsize) - 1; 343113287Sphk rdsect(fd, b0, sectorsize); 344113287Sphk T0(); 345224250Smav for (i = 0; i < bulk; i++) { 346113287Sphk rdmega(fd); 347113287Sphk } 348224250Smav TR(bulk * 1024); 349113287Sphk 350113287Sphk printf("\n"); 351137456Ssos return; 352137456Ssos} 353113287Sphk 354137456Ssosstatic void 355137456Ssoscommandtime(int fd, off_t mediasize, u_int sectorsize) 356137456Ssos{ 357137456Ssos double dtmega, dtsector; 358137456Ssos int i; 359137456Ssos 360137456Ssos printf("I/O command overhead:\n"); 361137456Ssos i = mediasize; 362137456Ssos rdsect(fd, 0, sectorsize); 363137456Ssos T0(); 364137456Ssos for (i = 0; i < 10; i++) 365137456Ssos rdmega(fd); 366137456Ssos gettimeofday(&tv2, NULL); 367137456Ssos dtmega = (tv2.tv_usec - tv1.tv_usec) / 1e6; 368137456Ssos dtmega += (tv2.tv_sec - tv1.tv_sec); 369137456Ssos 370137456Ssos printf("\ttime to read 10MB block %10.6f sec\t= %8.3f msec/sector\n", 371137456Ssos dtmega, dtmega*100/2048); 372137456Ssos 373137456Ssos rdsect(fd, 0, sectorsize); 374137456Ssos T0(); 375137456Ssos for (i = 0; i < 20480; i++) 376137456Ssos rdsect(fd, 0, sectorsize); 377137456Ssos gettimeofday(&tv2, NULL); 378137456Ssos dtsector = (tv2.tv_usec - tv1.tv_usec) / 1e6; 379137456Ssos dtsector += (tv2.tv_sec - tv1.tv_sec); 380137456Ssos 381137456Ssos printf("\ttime to read 20480 sectors %10.6f sec\t= %8.3f msec/sector\n", 382137456Ssos dtsector, dtsector*100/2048); 383137456Ssos printf("\tcalculated command overhead\t\t\t= %8.3f msec/sector\n", 384137456Ssos (dtsector - dtmega)*100/2048); 385137456Ssos 386137456Ssos printf("\n"); 387113287Sphk return; 388113287Sphk} 389