iogen.c revision 2c28215423293e443469a07ae7011135d058b671
1/* 2 * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. 3 * 4 * This program is free software; you can redistribute it and/or modify it 5 * under the terms of version 2 of the GNU General Public License as 6 * published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it would be useful, but 9 * WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 * 12 * Further, this software is distributed without any warranty that it is 13 * free of the rightful claim of any third person regarding infringement 14 * or the like. Any license provided herein, whether implied or 15 * otherwise, applies only to this software file. Patent licenses, if 16 * any, provided herein do not apply to combinations of this program with 17 * other software, or any other product whatsoever. 18 * 19 * You should have received a copy of the GNU General Public License along 20 * with this program; if not, write the Free Software Foundation, Inc., 59 21 * Temple Place - Suite 330, Boston MA 02111-1307, USA. 22 * 23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, 24 * Mountain View, CA 94043, or: 25 * 26 * http://www.sgi.com 27 * 28 * For further information regarding this notice, see: 29 * 30 * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ 31 */ 32/* 33 * iogen - a tool for generating file/sds io for a doio process 34 */ 35 36#include <stdio.h> 37#include <stdlib.h> 38#include <unistd.h> 39#include <signal.h> 40#include <fcntl.h> 41#include <errno.h> 42#include <string.h> 43#include <signal.h> 44#include <time.h> 45#include <sys/param.h> 46#include <sys/types.h> 47#include <sys/time.h> 48#include <sys/stat.h> 49#include <sys/sysmacros.h> 50#ifdef CRAY 51#include <sys/file.h> 52#include <sys/iosw.h> 53#include <sys/listio.h> 54#endif 55#ifdef sgi 56#include <sys/statvfs.h> 57#include <sys/fs/xfs_itable.h> 58#endif 59 60#ifdef CRAY 61#include "libkern.h" 62#endif 63#include "doio.h" 64#include "str_to_bytes.h" 65#include "string_to_tokens.h" 66#include "open_flags.h" 67#include "random_range.h" 68 69#ifndef PATH_MAX 70#define PATH_MAX 512 /* ??? */ 71#endif 72 73#ifndef BSIZE 74#ifdef linux 75#define BSIZE DEV_BSIZE 76#else 77#define BSIZE 512 78#endif 79#endif 80 81#define RAW_IO(_flags_) ((_flags_) & (O_RAW | O_SSD)) 82 83#ifndef __linux__ 84extern char *sys_errlist[]; 85#endif 86#define SYSERR strerror(errno) 87 88/* 89 * Structure for retaining test file information 90 */ 91 92struct file_info { 93 char f_path[MAX_FNAME_LENGTH+1]; /* file name (full path) */ 94 int f_length; /* length in bytes */ 95 int f_iou; /* file iounit */ 96 int f_riou; /* file raw iounit (for O_RAW/O_SSD) */ 97 int f_dalign; /* direct I/O alignment */ 98 int f_nextoff; /* offset of end of last io operation */ 99 int f_type; /* file type S_IFREG, etc... */ 100 int f_lastoffset; /* offset of last io operation */ 101 int f_lastlength; /* length of last io operation */ 102}; 103 104/* 105 * Simple structure for associating strings with values - useful for converting 106 * cmdline args to internal values, as well as printing internal values in 107 * a human readable form. 108 */ 109 110struct strmap { 111 char *m_string; 112 int m_value; 113 int m_flags; 114}; 115 116/* 117 * Declare cmdline option flags/variables initialized in parse_cmdline() 118 */ 119 120#define OPTS "a:dhf:i:L:m:op:qr:s:t:T:O:N:" 121 122int a_opt = 0; /* async io comp. types supplied */ 123int o_opt = 0; /* form overlapping requests */ 124int f_opt = 0; /* test flags */ 125int i_opt = 0; /* iterations - 0 implies infinite */ 126int L_opt = 0; /* listio min-max nstrides & nents */ 127int m_opt = 0; /* offset mode */ 128int O_opt = 0; /* file creation Open flags */ 129int p_opt = 0; /* output pipe - default is stdout */ 130int r_opt = 0; /* specify raw io multiple instead of */ 131 /* getting it from the mounted on device. */ 132 /* Only applies to regular files. */ 133int s_opt = 0; /* syscalls */ 134int t_opt = 0; /* min transfer size (bytes) */ 135int T_opt = 0; /* max transfer size (bytes) */ 136int q_opt = 0; /* quiet operation on startup */ 137char TagName[40]; /* name of this iogen (see Monster) */ 138struct strmap *Offset_Mode; /* M_SEQUENTIAL, M_RANDOM, etc. */ 139int Iterations; /* # requests to generate (0 --> infinite) */ 140int Time_Mode = 0; /* non-zero if Iterations is in seconds */ 141 /* (ie. -i arg was suffixed with 's') */ 142char *Outpipe; /* Pipe to write output to if p_opt */ 143int Mintrans; /* min io transfer size */ 144int Maxtrans; /* max io transfer size */ 145int Rawmult; /* raw/ssd io multiple (from -r) */ 146int Minstrides; /* min # of listio strides per request */ 147int Maxstrides; /* max # of listio strides per request */ 148int Oflags; /* open(2) flags for creating files */ 149int Ocbits; /* open(2) cbits for creating files */ 150int Ocblks; /* open(2) cblks for creating files */ 151int Orealtime=0; /* flag set for -O REALTIME */ 152int Oextsize=0; /* real-time extent size */ 153int Oreserve=1; /* flag for -O [no]reserve */ 154int Oallocate=0; /* flag for -O allocate */ 155int Owrite=1; /* flag for -O nowrite */ 156 157int Nfiles = 0; /* # files on cmdline */ 158struct file_info *File_List; /* info about each file */ 159int Nflags = 0; /* # flags on cmdline */ 160struct strmap *Flag_List[128]; /* flags selected from cmdline */ 161int Nsyscalls = 0; /* # syscalls on cmdline */ 162struct strmap *Syscall_List[128]; /* syscalls selected on cmdline */ 163int Fileio = 0; /* flag indicating that a file */ 164 /* io syscall has been chosen. */ 165int Naio_Strat_Types = 0; /* # async io completion types */ 166struct strmap *Aio_Strat_List[128]; /* Async io completion types */ 167 168void startup_info(); 169 170/* 171 * Map async io completion modes (-a args) names to values. Macros are 172 * defined in doio.h. 173 */ 174 175struct strmap Aio_Strat_Map[] = { 176#ifndef linux 177 { "poll", A_POLL }, 178 { "signal", A_SIGNAL }, 179#else 180 { "none", 0 }, 181#endif /* !linux */ 182#ifdef CRAY 183#if _UMK || RELEASE_LEVEL >= 8000 184 { "recall", A_RECALL }, 185#endif 186 187#ifdef RECALL_SIZEOF 188 { "recalla", A_RECALLA }, 189#endif 190 { "recalls", A_RECALLS }, 191#endif /* CRAY */ 192 193#ifdef sgi 194 { "suspend", A_SUSPEND }, 195 { "callback", A_CALLBACK }, 196#endif 197 { NULL, -1 } 198}; 199 200/* 201 * Offset_Mode #defines 202 */ 203 204#define M_RANDOM 1 205#define M_SEQUENTIAL 2 206#define M_REVERSE 3 207 208/* 209 * Map offset mode (-m args) names to values 210 */ 211 212struct strmap Omode_Map[] = { 213 { "random", M_RANDOM }, 214 { "sequential", M_SEQUENTIAL }, 215 { "reverse", M_REVERSE }, 216 { NULL, -1 } 217}; 218 219/* 220 * Map syscall names (-s args) to values - macros are defined in doio.h. 221 */ 222#define SY_ASYNC 00001 223#define SY_WRITE 00002 224#define SY_SDS 00010 225#define SY_LISTIO 00020 226#define SY_NENT 00100 /* multi entry vs multi stride >>> */ 227 228struct strmap Syscall_Map[] = { 229 { "read", READ, 0 }, 230 { "write", WRITE, SY_WRITE }, 231#ifdef CRAY 232 { "reada", READA, SY_ASYNC }, 233 { "writea", WRITEA, SY_WRITE|SY_ASYNC }, 234#ifndef _CRAYMPP 235 { "ssread", SSREAD, SY_SDS }, 236 { "sswrite", SSWRITE, SY_WRITE|SY_SDS }, 237#endif 238 { "listio", LISTIO, SY_ASYNC }, 239 240 /* listio as 4 system calls */ 241 { "lread", LREAD, 0 }, 242 { "lreada", LREADA, SY_ASYNC }, 243 { "lwrite", LWRITE, SY_WRITE }, 244 { "lwritea", LWRITEA, SY_WRITE|SY_ASYNC }, 245 246 /* listio with nstrides > 1 */ 247 { "lsread", LSREAD, 0 }, 248 { "lsreada", LSREADA, SY_ASYNC }, 249 { "lswrite", LSWRITE, SY_WRITE }, 250 { "lswritea", LSWRITEA, SY_WRITE|SY_ASYNC }, 251 252 /* listio with nents > 1 */ 253 { "leread", LEREAD, 0|SY_NENT }, 254 { "lereada", LEREADA, SY_ASYNC|SY_NENT }, 255 { "lewrite", LEWRITE, SY_WRITE|SY_NENT }, 256 { "lewritea", LEWRITEA, SY_WRITE|SY_ASYNC|SY_NENT }, 257 258 /* listio with nents > 1 & nstrides > 1 */ 259 260 /* all listio system calls under one name */ 261 { "listio+", LREAD, 0 }, 262 { "listio+", LREADA, SY_ASYNC }, 263 { "listio+", LWRITE, SY_WRITE }, 264 { "listio+", LWRITEA, SY_WRITE|SY_ASYNC }, 265 { "listio+", LSREAD, 0 }, 266 { "listio+", LSREADA, SY_ASYNC }, 267 { "listio+", LSWRITE, SY_WRITE }, 268 { "listio+", LSWRITEA, SY_WRITE|SY_ASYNC }, 269 { "listio+", LEREAD, 0|SY_NENT }, 270 { "listio+", LEREADA, SY_ASYNC|SY_NENT }, 271 { "listio+", LEWRITE, SY_WRITE|SY_NENT }, 272 { "listio+", LEWRITEA, SY_WRITE|SY_ASYNC|SY_NENT }, 273#endif 274 275#ifdef sgi 276 { "pread", PREAD }, 277 { "pwrite", PWRITE, SY_WRITE }, 278 { "aread", AREAD, SY_ASYNC }, 279 { "awrite", AWRITE, SY_WRITE|SY_ASYNC }, 280#if 0 281 /* not written yet */ 282 { "llread", LLREAD, 0 }, 283 { "llaread", LLAREAD, SY_ASYNC }, 284 { "llwrite", LLWRITE, 0 }, 285 { "llawrite", LLAWRITE, SY_ASYNC }, 286#endif 287 { "resvsp", RESVSP, SY_WRITE }, 288 { "unresvsp", UNRESVSP, SY_WRITE }, 289 { "reserve", RESVSP, SY_WRITE }, 290 { "unreserve", UNRESVSP, SY_WRITE }, 291 { "ffsync", DFFSYNC, SY_WRITE }, 292#endif /* SGI */ 293 294#ifndef CRAY 295 { "readv", READV }, 296 { "writev", WRITEV, SY_WRITE }, 297 { "mmread", MMAPR }, 298 { "mmwrite", MMAPW, SY_WRITE }, 299 { "fsync2", FSYNC2, SY_WRITE }, 300 { "fdatasync", FDATASYNC, SY_WRITE }, 301#endif 302 303 { NULL, -1 } 304}; 305 306/* 307 * Map open flags (-f args) to values 308 */ 309#define FLG_RAW 00001 310 311struct strmap Flag_Map[] = { 312 { "buffered", 0, 0 }, 313 { "sync", O_SYNC, 0 }, 314#ifdef CRAY 315 { "raw", O_RAW, FLG_RAW }, 316 { "raw+wf", O_RAW | O_WELLFORMED, FLG_RAW }, 317 { "raw+wf+ldraw", O_RAW | O_WELLFORMED | O_LDRAW, FLG_RAW }, 318 { "raw+wf+ldraw+sync", O_RAW | O_WELLFORMED | O_LDRAW | O_SYNC, FLG_RAW }, 319#ifdef O_SSD 320 { "ssd", O_SSD, FLG_RAW }, 321#endif 322#ifdef O_LDRAW 323 { "ldraw", O_LDRAW, 0 }, 324#endif 325#ifdef O_PARALLEL 326 { "parallel", O_PARALLEL | O_RAW | O_WELLFORMED, 327 FLG_RAW }, 328 { "parallel+sync", O_PARALLEL | O_RAW | O_WELLFORMED | O_SYNC, 329 FLG_RAW }, 330 { "parallel+ldraw", O_PARALLEL | O_RAW | O_WELLFORMED | O_LDRAW, 331 FLG_RAW }, 332 { "parallel+ldraw+sync", 333 O_PARALLEL | O_RAW | O_WELLFORMED | O_LDRAW | O_SYNC, 334 FLG_RAW }, 335#endif 336#endif /* CRAY */ 337 338#ifdef sgi 339 { "direct", O_DIRECT, FLG_RAW }, 340 { "dsync", O_DSYNC }, /* affects writes */ 341 { "rsync", O_RSYNC }, /* affects reads */ 342 { "rsync+dsync", O_RSYNC|O_DSYNC }, 343#endif 344 { NULL, -1 } 345}; 346 347/* 348 * Map file types to strings 349 */ 350 351struct strmap Ftype_Map[] = { 352 { "regular", S_IFREG }, 353 { "blk-spec", S_IFBLK }, 354 { "chr-spec", S_IFCHR }, 355 { NULL, 0 } 356}; 357 358/* 359 * Misc declarations 360 */ 361 362int Sds_Avail; 363 364char Byte_Patterns[26] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 365 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 366 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 367 'Y', 'Z' }; 368 369int form_iorequest(struct io_req *); 370int init_output(); 371int parse_cmdline(int argc, char **argv, char *opts); 372int help(FILE *stream); 373int usage(FILE *stream); 374 375int 376main(argc, argv) 377int argc; 378char **argv; 379{ 380 int rseed, outfd, infinite; 381 time_t start_time; 382 struct io_req req; 383 384 umask(0); 385 386#ifdef CRAY 387 Sds_Avail = sysconf(_SC_CRAY_SDS); 388#else 389 Sds_Avail = 0; 390#endif 391 392 TagName[0] = '\0'; 393 parse_cmdline(argc, argv, OPTS); 394 395 /* 396 * Initialize output descriptor. 397 */ 398 if (! p_opt) { 399 outfd = 1; 400 } else { 401 outfd = init_output(); 402 } 403 404 rseed = getpid(); 405 random_range_seed(rseed); /* initialize random number generator */ 406 407 /* 408 * Print out startup information, unless we're running in quiet mode 409 */ 410 if (!q_opt) 411 startup_info(stderr, rseed); 412 { 413 struct timeval ts; 414 gettimeofday(&ts,NULL); 415 start_time = ts.tv_sec; 416 } 417 /* 418 * While iterations (or forever if Iterations == 0) - compute an 419 * io request, and write the structure to the output descriptor 420 */ 421 422 infinite = !Iterations; 423 struct timeval ts; 424 gettimeofday(&ts,NULL); 425 while (infinite || 426 (! Time_Mode && Iterations--) || 427 (Time_Mode && (ts.tv_sec - start_time <= Iterations))) { 428 gettimeofday(&ts,NULL); 429 memset(&req, 0, sizeof(struct io_req)); 430 if (form_iorequest(&req) == -1) { 431 fprintf(stderr, "iogen%s: form_iorequest() failed\n", TagName); 432 continue; 433 } 434 435 req.r_magic = DOIO_MAGIC; 436 if (write(outfd, (char *)&req, sizeof(req)) == -1) 437 perror("Warning: Could not write"); 438 } 439 440 exit(0); 441 442} /* main */ 443 444void 445startup_info(FILE *stream, int seed) 446{ 447 char *value_to_string(), *type; 448 int i; 449 450 fprintf(stream, "\n"); 451 fprintf(stream, "iogen%s starting up with the following:\n", TagName); 452 fprintf(stream, "\n"); 453 454 fprintf(stream, "Out-pipe: %s\n", 455 p_opt ? Outpipe : "stdout"); 456 457 if (Iterations) { 458 fprintf(stream, "Iterations: %d", Iterations); 459 if (Time_Mode) 460 fprintf(stream, " seconds"); 461 462 fprintf(stream, "\n"); 463 } else { 464 fprintf(stream, "Iterations: Infinite\n"); 465 } 466 467 fprintf(stream, 468 "Seed: %d\n", seed); 469 470 fprintf(stream, 471 "Offset-Mode: %s\n", Offset_Mode->m_string); 472 473 fprintf(stream, "Overlap Flag: %s\n", 474 o_opt ? "on" : "off"); 475 476 fprintf(stream, 477 "Mintrans: %-11d (%d blocks)\n", 478 Mintrans, (Mintrans+BSIZE-1)/BSIZE); 479 480 fprintf(stream, 481 "Maxtrans: %-11d (%d blocks)\n", 482 Maxtrans, (Maxtrans+BSIZE-1)/BSIZE); 483 484 if (! r_opt) 485 fprintf(stream, 486 "O_RAW/O_SSD Multiple: (Determined by device)\n"); 487 else 488 fprintf(stream, 489 "O_RAW/O_SSD Multiple: %-11d (%d blocks)\n", 490 Rawmult, (Rawmult+BSIZE-1)/BSIZE); 491 492 fprintf(stream, "Syscalls: "); 493 for (i = 0; i < Nsyscalls; i++) 494 fprintf(stream, 495 "%s ", Syscall_List[i]->m_string); 496 fprintf(stream, "\n"); 497 498 fprintf(stream, "Aio completion types: "); 499 for (i = 0; i < Naio_Strat_Types; i++) 500 fprintf(stream, 501 "%s ", Aio_Strat_List[i]->m_string); 502 fprintf(stream, "\n"); 503 504 if (Fileio) { 505 fprintf(stream, "Flags: "); 506 for (i = 0; i < Nflags; i++) 507 fprintf(stream, 508 "%s ", Flag_List[i]->m_string); 509 510 fprintf(stream, "\n"); 511 fprintf(stream, "\n"); 512 fprintf(stream, "Test Files: \n"); 513 fprintf(stream, "\n"); 514 fprintf(stream, 515 "Path Length iou raw iou file\n"); 516 fprintf(stream, 517 " (bytes) (bytes) (bytes) type\n"); 518 fprintf(stream, 519 "-----------------------------------------------------------------------------\n"); 520 521 for (i = 0; i < Nfiles; i++) { 522 type = value_to_string(Ftype_Map, File_List[i].f_type); 523 fprintf(stream, "%-40s %12d %7d %7d %s\n", 524 File_List[i].f_path, File_List[i].f_length, 525 File_List[i].f_iou, File_List[i].f_riou, type); 526 } 527 } 528} 529 530/* 531 * Initialize output descriptor. If going to stdout, its easy, 532 * otherwise, attempt to create a FIFO on path Outpipe. Exit with an 533 * error code if this cannot be done. 534 */ 535int 536init_output() 537{ 538 int outfd; 539 struct stat sbuf; 540 541 if (stat(Outpipe, &sbuf) == -1) { 542 if (errno == ENOENT) { 543 if (mkfifo(Outpipe, 0666) == -1) { 544 fprintf(stderr, "iogen%s: Could not mkfifo %s: %s\n", 545 TagName, Outpipe, SYSERR); 546 exit(2); 547 } 548 } else { 549 fprintf(stderr, "iogen%s: Could not stat outpipe %s: %s\n", 550 TagName, Outpipe, SYSERR); 551 exit(2); 552 } 553 } else { 554 if (! S_ISFIFO(sbuf.st_mode)) { 555 fprintf(stderr, 556 "iogen%s: Output file %s exists, but is not a FIFO\n", 557 TagName, Outpipe); 558 exit(2); 559 } 560 } 561 562 if ((outfd = open(Outpipe, O_RDWR)) == -1) { 563 fprintf(stderr, 564 "iogen%s: Couldn't open outpipe %s with flags O_RDWR: %s\n", 565 TagName, Outpipe, SYSERR); 566 exit(2); 567 } 568 569 return(outfd); 570} 571 572/* 573 * Main io generation function. form_iorequest() selects a system call to 574 * do based on cmdline arguments, and proceeds to select parameters for that 575 * system call. 576 * 577 * Returns 0 if req is filled in with a complete doio request, otherwise 578 * returns -1. 579 */ 580 581int 582form_iorequest(req) 583struct io_req *req; 584{ 585 int mult, offset=0, length=0, slength; 586 int minlength, maxlength, laststart, lastend; 587 int minoffset, maxoffset; 588 int maxstride, nstrides; 589 char pattern, *errp; 590 struct strmap *flags, *sc, *aio_strat; 591 struct file_info *fptr; 592#ifdef CRAY 593 int opcode, cmd; 594#endif 595 596 /* 597 * Choose system call, flags, and file 598 */ 599 600 sc = Syscall_List[random_range(0, Nsyscalls-1, 1, NULL)]; 601 req->r_type = sc->m_value; 602 603#ifdef CRAY 604 if (sc->m_value == LISTIO) { 605 opcode = random_range(0, 1, 1, NULL) ? LO_READ : LO_WRITE; 606 cmd = random_range(0, 1, 1, NULL) ? LC_START : LC_WAIT; 607 } 608#endif 609 610 if (sc->m_flags & SY_WRITE) 611 pattern = Byte_Patterns[random_range(0, sizeof(Byte_Patterns) - 1, 1, NULL)]; 612 else 613 pattern = 0; 614 615#if CRAY 616 /* 617 * If sds io, simply choose a length (possibly pattern) and return 618 */ 619 620 if (sc->m_flags & SY_SDS) { 621 req->r_data.ssread.r_nbytes = random_range(Mintrans, Maxtrans, BSIZE, NULL); 622 if (sc->m_flags & SY_WRITE) 623 req->r_data.sswrite.r_pattern = pattern; 624 625 return 0; 626 } 627#endif 628 629 /* 630 * otherwise, we're doing file io. Choose starting offset, length, 631 * open flags, and possibly a pattern (for write/writea). 632 */ 633 634 fptr = &File_List[random_range(0, Nfiles-1, 1, NULL)]; 635 flags = Flag_List[random_range(0, Nflags-1, 1, NULL)]; 636 637 /* 638 * Choose offset/length multiple. IO going to a device, or regular 639 * IO that is O_RAW or O_SSD must be aligned on the file r_iou. Otherwise 640 * it must be aligned on the regular iou (normally 1). 641 */ 642 643 if (fptr->f_type == S_IFREG && (flags->m_flags & FLG_RAW)) 644 mult = fptr->f_riou; 645 else 646 mult = fptr->f_iou; 647 648 /* 649 * Choose offset and length. Both must be a multiple of mult 650 */ 651 652 /* 653 * Choose length first - it must be a multiple of mult 654 */ 655 656 laststart = fptr->f_lastoffset; 657 lastend = fptr->f_lastoffset + fptr->f_lastlength - 1; 658 659 minlength = (Mintrans > mult) ? Mintrans : mult; 660 661 switch (Offset_Mode->m_value) { 662 case M_SEQUENTIAL: 663 if (o_opt && lastend > laststart) 664 offset = random_range(laststart, lastend, 1, NULL); 665 else 666 offset = lastend + 1; 667 if (offset && (offset%mult)) 668 offset += mult - (offset % mult); 669 670 if (minlength > fptr->f_length - offset) 671 offset = 0; 672 673 maxlength = fptr->f_length - offset; 674 if (maxlength > Maxtrans) 675 maxlength = Maxtrans; 676 677 length = random_range(minlength, maxlength, mult, &errp); 678 if (errp != NULL) { 679 fprintf(stderr, "iogen%s: random_range(%d, %d, %d) failed\n", 680 TagName, minlength, maxlength, mult); 681 return -1; 682 } 683 684 break; 685 686 case M_REVERSE: 687 maxlength = laststart; 688 689 if (maxlength > Maxtrans) 690 maxlength = Maxtrans; 691 692 if (minlength > maxlength) { 693 laststart = fptr->f_length; 694 lastend = fptr->f_length; 695 maxlength = Maxtrans; 696 } 697 698 length = random_range(minlength, maxlength, mult, &errp); 699 if (errp != NULL) { 700 fprintf(stderr, "iogen%s: random_range(%d, %d, %d) failed\n", 701 TagName, minlength, maxlength, mult); 702 return -1; 703 } 704 705 offset = laststart - length; 706 707 if (o_opt && lastend > laststart) 708 offset += random_range(1, lastend - laststart, 1, NULL); 709 710 if (offset && (offset%mult)) 711 offset -= offset % mult; 712 713 break; 714 715 case M_RANDOM: 716 length = random_range(Mintrans, Maxtrans, mult, NULL); 717 718 if (o_opt && lastend > laststart) { 719 minoffset = laststart - length + 1; 720 if (minoffset < 0) { 721 minoffset = 0; 722 } 723 724 if (lastend + length > fptr->f_length) { 725 maxoffset = fptr->f_length - length; 726 } else { 727 maxoffset = lastend; 728 } 729 } else { 730 minoffset = 0; 731 maxoffset = fptr->f_length - length; 732 } 733 734 if (minoffset < 0) 735 minoffset = 0; 736 737 offset = random_range(minoffset, maxoffset, mult, &errp); 738 if (errp != NULL) { 739 fprintf(stderr, "iogen%s: random_range(%d, %d, %d) failed\n", 740 TagName, minoffset, maxoffset, mult); 741 return -1; 742 } 743 } 744 745 fptr->f_lastoffset = offset; 746 fptr->f_lastlength = length; 747 748 /* 749 * Choose an async io completion strategy if necessary 750 */ 751 if (sc->m_flags & SY_ASYNC) 752 aio_strat = Aio_Strat_List[random_range(0, Naio_Strat_Types - 1, 753 1, NULL)]; 754 else 755 aio_strat = NULL; 756 757 /* 758 * fill in specific syscall record data 759 */ 760 switch (sc->m_value) { 761 case READ: 762 case READA: 763 strcpy(req->r_data.read.r_file, fptr->f_path); 764 req->r_data.read.r_oflags = O_RDONLY | flags->m_value; 765 req->r_data.read.r_offset = offset; 766 req->r_data.read.r_nbytes = length; 767 req->r_data.read.r_uflags = (flags->m_flags & FLG_RAW) ? F_WORD_ALIGNED : 0; 768 req->r_data.read.r_aio_strat = (aio_strat==NULL) ? 0 : aio_strat->m_value; 769 req->r_data.read.r_nstrides = 1; 770 req->r_data.read.r_nent = 1; 771 break; 772 773 case WRITE: 774 case WRITEA: 775 strcpy(req->r_data.write.r_file, fptr->f_path); 776 req->r_data.write.r_oflags = O_WRONLY | flags->m_value; 777 req->r_data.write.r_offset = offset; 778 req->r_data.write.r_nbytes = length; 779 req->r_data.write.r_pattern = pattern; 780 req->r_data.write.r_uflags = (flags->m_flags & FLG_RAW) ? F_WORD_ALIGNED : 0; 781 req->r_data.write.r_aio_strat = (aio_strat==NULL) ? 0 : aio_strat->m_value; 782 req->r_data.write.r_nstrides = 1; 783 req->r_data.write.r_nent = 1; 784 break; 785 786 case READV: 787 case AREAD: 788 case PREAD: 789 case WRITEV: 790 case AWRITE: 791 case PWRITE: 792 793 case LREAD: 794 case LREADA: 795 case LWRITE: 796 case LWRITEA: 797 798 case RESVSP: 799 case UNRESVSP: 800 case DFFSYNC: 801 case FSYNC2: 802 case FDATASYNC: 803 804 strcpy(req->r_data.io.r_file, fptr->f_path); 805 req->r_data.io.r_oflags = ((sc->m_flags & SY_WRITE) ? O_WRONLY : O_RDONLY) | flags->m_value; 806 req->r_data.io.r_offset = offset; 807 req->r_data.io.r_nbytes = length; 808 req->r_data.io.r_pattern = pattern; 809 req->r_data.io.r_uflags = (flags->m_flags & FLG_RAW) ? F_WORD_ALIGNED : 0; 810 req->r_data.io.r_aio_strat = (aio_strat==NULL) ? 0 : aio_strat->m_value; 811 req->r_data.io.r_nstrides = 1; 812 req->r_data.io.r_nent = 1; 813 break; 814 815 case MMAPR: 816 case MMAPW: 817 strcpy(req->r_data.io.r_file, fptr->f_path); 818 /* a subtle "feature" of mmap: a write-map requires 819 the file open read/write */ 820 req->r_data.io.r_oflags = ((sc->m_flags & SY_WRITE) ? O_RDWR : O_RDONLY) | flags->m_value; 821 req->r_data.io.r_offset = offset; 822 req->r_data.io.r_nbytes = length; 823 req->r_data.io.r_pattern = pattern; 824 req->r_data.io.r_uflags = (flags->m_flags & FLG_RAW) ? F_WORD_ALIGNED : 0; 825 req->r_data.io.r_aio_strat = (aio_strat==NULL) ? 0 : aio_strat->m_value; 826 req->r_data.io.r_nstrides = 1; 827 req->r_data.io.r_nent = 1; 828 break; 829 830 case LSREAD: 831 case LSREADA: 832 case LEREAD: 833 case LEREADA: 834 case LSWRITE: 835 case LSWRITEA: 836 case LEWRITE: 837 case LEWRITEA: 838 /* multi-strided */ 839 strcpy(req->r_data.io.r_file, fptr->f_path); 840 req->r_data.io.r_oflags = ((sc->m_flags & SY_WRITE) ? O_WRONLY : O_RDONLY) | flags->m_value; 841 req->r_data.io.r_offset = offset; 842 req->r_data.io.r_uflags = (flags->m_flags & FLG_RAW) ? F_WORD_ALIGNED : 0; 843 req->r_data.io.r_aio_strat = (aio_strat==NULL) ? 0 : aio_strat->m_value; 844 req->r_data.io.r_pattern = pattern; 845 846 /* multi-strided request... 847 * random number of strides (1...MaxStrides) 848 * length of stride must be > minlength 849 * length of stride must be % mult 850 * 851 * maxstrides = min(length / mult, overall.max#strides) 852 * nstrides = random # 853 * while (length / nstrides < minlength) 854 * nstrides = new random # 855 */ 856 maxstride = length / mult; 857 if (maxstride > Maxstrides) 858 maxstride = Maxstrides; 859 860 if (!Minstrides) 861 Minstrides=1; 862 nstrides = random_range(Minstrides, maxstride, 1, &errp); 863 if (errp != NULL) { 864 fprintf(stderr, "iogen%s: random_range(%d, %d, %d) failed\n", 865 TagName, Minstrides, maxstride, 1); 866 return -1; 867 } 868 869 slength = length / nstrides; 870 if (slength % mult != 0) { 871 if (mult > slength) { 872 slength = mult; 873 } else { 874 slength -= slength % mult; 875 } 876 nstrides = length / slength; 877 if (nstrides > Maxstrides) 878 nstrides = Maxstrides; 879 } 880 881 req->r_data.io.r_nbytes = slength; 882 if (sc->m_flags & SY_NENT) { 883 req->r_data.io.r_nstrides = 1; 884 req->r_data.io.r_nent = nstrides; 885 } else { 886 req->r_data.io.r_nstrides = nstrides; 887 req->r_data.io.r_nent = 1; 888 } 889 break; 890 891 case LISTIO: 892#ifdef CRAY 893 strcpy(req->r_data.listio.r_file, fptr->f_path); 894 req->r_data.listio.r_offset = offset; 895 req->r_data.listio.r_cmd = cmd; 896 req->r_data.listio.r_aio_strat = (aio_strat==NULL) ? 0 : aio_strat->m_value; 897 req->r_data.listio.r_filestride = 0; 898 req->r_data.listio.r_memstride = 0; 899 req->r_data.listio.r_opcode = opcode; 900 req->r_data.listio.r_nstrides = 1; 901 req->r_data.listio.r_nbytes = length; 902 req->r_data.listio.r_uflags = (flags->m_flags & FLG_RAW) ? F_WORD_ALIGNED : 0; 903 904 if (opcode == LO_WRITE) { 905 req->r_data.listio.r_pattern = pattern; 906 req->r_data.listio.r_oflags = O_WRONLY | flags->m_value; 907 } else { 908 req->r_data.listio.r_oflags = O_RDONLY | flags->m_value; 909 } 910#endif 911 break; 912 } 913 914 return 0; 915} 916 917/* 918 * Get information about a file that iogen uses to choose io length and 919 * offset. Information gathered is file length, iounit, and raw iounit. 920 * For regurlar files, iounit is 1, and raw iounit is the iounit of the 921 * device on which the file resides. For block/character special files 922 * the iounit and raw iounit are both the iounit of the device. 923 * 924 * Note: buffered and osync io must be iounit aligned 925 * raw and ossd io must be raw iounit aligned 926 */ 927 928int 929get_file_info(rec) 930struct file_info *rec; 931{ 932 struct stat sbuf; 933#ifdef CRAY 934 struct lk_device_info dinfo; 935#endif 936#ifdef sgi 937 int fd; 938 struct dioattr finfo; 939#endif 940 941 /* 942 * Figure out if the files is regular, block or character special. Any 943 * other type is an error. 944 */ 945 946 if (stat(rec->f_path, &sbuf) == -1) { 947 fprintf(stderr, "iogen%s: get_file_info(): Could not stat() %s: %s\n", 948 TagName, rec->f_path, SYSERR); 949 return -1; 950 } 951 952#if _CRAY2 953 if ((! S_ISREG(sbuf.st_mode)) || strncmp(rec->f_path, "/dev/", 5) == 0) { 954 fprintf(stderr, "iogen%s: device level io not supported on cray2\n", TagName); 955 return -1; 956 } 957#endif 958 959 rec->f_type = sbuf.st_mode & S_IFMT; 960 961 /* 962 * If regular, iou is 1, and we must figure out the device on 963 * which the file resides. riou is the iou (logical sector size) of 964 * this device. 965 */ 966 967 if (S_ISREG(sbuf.st_mode)) { 968 rec->f_iou = 1; 969 rec->f_length = sbuf.st_size; 970 971 /* 972 * If -r used, take Rawmult as the raw/ssd io multiple. Otherwise 973 * attempt to determine it by looking at the device the file 974 * resides on. 975 */ 976 977 if (r_opt) { 978 rec->f_riou = Rawmult; 979 return 0; 980 } 981 982#ifdef CRAY 983 if (lk_rawdev(rec->f_path, dinfo.path, sizeof(dinfo.path), 0) == -1) 984 return -1; 985 986 if (lk_devinfo(&dinfo, 0) == -1) { 987 /* can't get raw I/O unit -- use stat to fudge it */ 988 rec->f_riou = sbuf.st_blksize; 989 } else { 990 rec->f_riou = ctob(dinfo.iou); 991 } 992#endif 993#ifdef linux 994 rec->f_riou = BSIZE; 995#endif 996#ifdef sgi 997 if ((fd = open(rec->f_path, O_RDWR|O_DIRECT, 0)) != -1) { 998 if (fcntl(fd, F_DIOINFO, &finfo) != -1) { 999 rec->f_riou = finfo.d_miniosz; 1000 } else { 1001 fprintf(stderr, 1002 "iogen%s: Error %s (%d) getting direct I/O info of file %s\n", 1003 TagName, strerror(errno), errno, rec->f_path); 1004 } 1005 close(fd); 1006 } else { 1007 rec->f_riou = BBSIZE; 1008 } 1009#endif /* SGI */ 1010 1011 } else { 1012 1013#ifdef CRAY 1014 /* 1015 * Otherwise, file is a device. Use lk_devinfo() to get its logical 1016 * sector size. This is the iou and riou 1017 */ 1018 1019 strcpy(dinfo.path, rec->f_path); 1020 1021 if (lk_devinfo(&dinfo, 0) == -1) { 1022 fprintf(stderr, "iogen%s: %s: %s\n", TagName, Lk_err_func, Lk_err_mesg); 1023 return -1; 1024 } 1025 1026 rec->f_iou = ctob(dinfo.iou); 1027 rec->f_riou = ctob(dinfo.iou); 1028 rec->f_length = ctob(dinfo.length); 1029#else 1030#ifdef sgi 1031 rec->f_riou = BBSIZE; 1032 rec->f_length = BBSIZE; 1033#else 1034 rec->f_riou = BSIZE; 1035 rec->f_length = BSIZE; 1036#endif /* sgi */ 1037#endif /* CRAY */ 1038 } 1039 1040 return 0; 1041} 1042 1043/* 1044 * Create file path as nbytes long. If path exists, the file will either be 1045 * extended or truncated to be nbytes long. Returns final size of file, 1046 * or -1 if there was a failure. 1047 */ 1048 1049int 1050create_file(path, nbytes) 1051char *path; 1052int nbytes; 1053{ 1054 int fd, rval; 1055 char c; 1056 struct stat sbuf; 1057#ifdef sgi 1058 int nb; 1059 struct flock f; 1060 struct fsxattr xattr; 1061 struct dioattr finfo; 1062 char *b, *buf; 1063#endif 1064 1065 errno = 0; 1066 rval = stat(path, &sbuf); 1067 1068 if (rval == -1) { 1069 if (errno == ENOENT) { 1070 sbuf.st_size = 0; 1071 } else { 1072 fprintf(stderr, "iogen%s: Could not stat file %s: %s (%d)\n", 1073 TagName, path, SYSERR, errno); 1074 return -1; 1075 } 1076 } else { 1077 if (! S_ISREG(sbuf.st_mode)) { 1078 fprintf(stderr, 1079 "iogen%s: file %s exists, but is not a regular file - cannot modify length\n", 1080 TagName, path); 1081 return -1; 1082 } 1083 } 1084 1085 if (sbuf.st_size == nbytes) 1086 return nbytes; 1087 1088 Oflags |= O_CREAT | O_WRONLY; 1089 1090 if ((fd = open(path, Oflags, 0666)) == -1) { 1091 fprintf(stderr, "iogen%s: Could not create/open file %s: %s (%d)\n", 1092 TagName, path, SYSERR, errno); 1093 return -1; 1094 } 1095 1096 /* 1097 * Truncate file if it is longer than nbytes, otherwise attempt to 1098 * pre-allocate file blocks. 1099 */ 1100 1101 if (sbuf.st_size > nbytes) { 1102 if (ftruncate(fd, nbytes) == -1) { 1103 fprintf(stderr, 1104 "iogen%s: Could not ftruncate() %s to %d bytes: %s (%d)\n", 1105 TagName, path, nbytes, SYSERR, errno); 1106 close(fd); 1107 return -1; 1108 } 1109 } else { 1110 1111#ifdef sgi 1112 /* 1113 * The file must be designated as Real-Time before any data 1114 * is allocated to it. 1115 * 1116 */ 1117 if (Orealtime != 0) { 1118 memset(&xattr, 0x00, sizeof(xattr)); 1119 xattr.fsx_xflags = XFS_XFLAG_REALTIME; 1120 /*fprintf(stderr, "set: fsx_xflags = 0x%x\n", xattr.fsx_xflags);*/ 1121 if (fcntl(fd, F_FSSETXATTR, &xattr) == -1) { 1122 fprintf(stderr, "iogen%s: Error %s (%d) setting XFS XATTR->Realtime on file %s\n", 1123 TagName, SYSERR, errno, path); 1124 close(fd); 1125 return -1; 1126 } 1127 1128#ifdef DEBUG 1129 if (fcntl(fd, F_FSGETXATTR, &xattr) == -1) { 1130 fprintf(stderr, "iogen%s: Error getting realtime flag %s (%d)\n", 1131 TagName, SYSERR, errno); 1132 close(fd); 1133 return -1; 1134 } else { 1135 fprintf(stderr, "get: fsx_xflags = 0x%x\n", 1136 xattr.fsx_xflags); 1137 } 1138#endif 1139 } 1140 1141 /* 1142 * Reserve space with F_RESVSP 1143 * 1144 * Failure is ignored since F_RESVSP only works on XFS and the 1145 * filesystem could be on EFS or NFS 1146 */ 1147 if (Oreserve) { 1148 f.l_whence = SEEK_SET; 1149 f.l_start = 0; 1150 f.l_len = nbytes; 1151 1152 /*fprintf(stderr, 1153 "create_file: fcntl(%d, F_RESVSP, { %d, %lld, %lld })\n", 1154 fd, f.l_whence, (long long)f.l_start, (long long)f.l_len);*/ 1155 1156 /* non-zeroing reservation */ 1157 if (fcntl(fd, F_RESVSP, &f) == -1) { 1158 fprintf(stderr, 1159 "iogen%s: Could not fcntl(F_RESVSP) %d bytes in file %s: %s (%d)\n", 1160 TagName, nbytes, path, SYSERR, errno); 1161 close(fd); 1162 return -1; 1163 } 1164 } 1165 1166 if (Oallocate) { 1167 /* F_ALLOCSP allocates from the start of the file to l_start */ 1168 f.l_whence = SEEK_SET; 1169 f.l_start = nbytes; 1170 f.l_len = 0; 1171 /*fprintf(stderr, 1172 "create_file: fcntl(%d, F_ALLOCSP, { %d, %lld, %lld })\n", 1173 fd, f.l_whence, (long long)f.l_start, 1174 (long long)f.l_len);*/ 1175 1176 /* zeroing reservation */ 1177 if (fcntl( fd, F_ALLOCSP, &f ) == -1) { 1178 fprintf(stderr, 1179 "iogen%s: Could not fcntl(F_ALLOCSP) %d bytes in file %s: %s (%d)\n", 1180 TagName, nbytes, path, SYSERR, errno); 1181 close(fd); 1182 return -1; 1183 } 1184 } 1185#endif /* sgi */ 1186 1187 /* 1188 * Write a byte at the end of file so that stat() sets the right 1189 * file size. 1190 */ 1191 1192#ifdef sgi 1193 if (Owrite == 2) { 1194 close(fd); 1195 if ((fd = open(path, O_CREAT|O_RDWR|O_DIRECT, 0)) != -1) { 1196 if (fcntl(fd, F_DIOINFO, &finfo) == -1) { 1197 fprintf(stderr, 1198 "iogen%s: Error %s (%d) getting direct I/O info for file %s\n", 1199 TagName, SYSERR, errno, path); 1200 return -1; 1201 } else { 1202 /*fprintf(stderr, "%s: miniosz=%d\n", 1203 path, finfo.d_miniosz);*/ 1204 } 1205 } else { 1206 fprintf(stderr, "iogen%s: Error %s (%d) opening file %s with flags O_CREAT|O_RDWR|O_DIRECT\n", 1207 TagName, SYSERR, errno, path); 1208 return -1; 1209 } 1210 1211 /* 1212 * nb is nbytes adjusted down by an even d_miniosz block 1213 * 1214 * Note: the first adjustment can cause iogen to print a warning 1215 * about not being able to create a file of <nbytes> length, 1216 * since the file will be shorter. 1217 */ 1218 nb = nbytes-finfo.d_miniosz; 1219 nb = nb-nb%finfo.d_miniosz; 1220 1221 /*fprintf(stderr, 1222 "create_file_ow2: lseek(%d, %d {%d %d}, SEEK_SET)\n", 1223 fd, nb, nbytes, finfo.d_miniosz);*/ 1224 1225 if (lseek(fd, nb, SEEK_SET) == -1) { 1226 fprintf(stderr, 1227 "iogen%s: Could not lseek() to EOF of file %s: %s (%d)\n\tactual offset %d file size goal %d miniosz %lld\n", 1228 TagName, path, SYSERR, errno, 1229 nb, nbytes, (long long)finfo.d_miniosz); 1230 close(fd); 1231 return -1; 1232 } 1233 1234 b = buf = (char *)malloc(finfo.d_miniosz+finfo.d_mem); 1235 1236 if (((long)buf % finfo.d_mem != 0)) { 1237 buf += finfo.d_mem - ((long)buf % finfo.d_mem); 1238 } 1239 1240 memset(buf, 0, finfo.d_miniosz); 1241 1242 if ((rval=write(fd, buf, finfo.d_miniosz)) != finfo.d_miniosz) { 1243 fprintf(stderr, 1244 "iogen%s: Could not write %d byte length file %s: %s (%d)\n", 1245 TagName, nb, path, SYSERR, errno); 1246 fprintf(stderr, 1247 "\twrite(%d, 0x%lx, %d) = %d\n", 1248 fd, (long)buf, finfo.d_miniosz, rval); 1249 fprintf(stderr, 1250 "\toffset %d file size goal %d, miniosz=%d\n", 1251 nb, nbytes, finfo.d_miniosz); 1252 close(fd); 1253 return -1; 1254 } 1255 free(b); 1256 } else 1257#endif /* sgi */ 1258 if (Owrite) { 1259 /*fprintf(stderr, 1260 "create_file_Owrite: lseek(%d, %d {%d}, SEEK_SET)\n", 1261 fd, nbytes-1, nbytes);*/ 1262 1263 if (lseek(fd, nbytes-1, SEEK_SET) == -1) { 1264 fprintf(stderr, 1265 "iogen%s: Could not lseek() to EOF in file %s: %s (%d)\n\toffset goal %d\n", 1266 TagName, path, SYSERR, errno, 1267 nbytes-1); 1268 close(fd); 1269 return -1; 1270 } 1271 1272 if ((rval=write(fd, &c, 1)) != 1) { 1273 fprintf(stderr, 1274 "iogen%s: Could not create a %d byte length file %s: %s (%d)\n", 1275 TagName, nbytes, path, SYSERR, errno); 1276 fprintf(stderr, 1277 "\twrite(%d, 0x%lx, %d) = %d\n", 1278 fd, (long)&c, 1, rval); 1279 fprintf(stderr, 1280 "\toffset %d file size goal %d\n", 1281 nbytes-1, nbytes); 1282 close(fd); 1283 return -1; 1284 } 1285 } 1286 } 1287 1288 fstat(fd, &sbuf); 1289 close(fd); 1290 1291 return sbuf.st_size; 1292} 1293 1294/* 1295 * Function to convert a string to its corresponding value in a strmap array. 1296 * If the string is not found in the array, the value corresponding to the 1297 * NULL string (the last element in the array) is returned. 1298 */ 1299 1300int 1301str_to_value(map, str) 1302struct strmap *map; 1303char *str; 1304{ 1305 struct strmap *mp; 1306 1307 for (mp = map; mp->m_string != NULL; mp++) 1308 if (strcmp(mp->m_string, str) == 0) 1309 break; 1310 1311 return mp->m_value; 1312} 1313 1314/* 1315 * Function to convert a string to its corresponding entry in a strmap array. 1316 * If the string is not found in the array, a NULL is returned. 1317 */ 1318 1319struct strmap * 1320str_lookup(map, str) 1321struct strmap *map; 1322char *str; 1323{ 1324 struct strmap *mp; 1325 1326 for (mp = map; mp->m_string != NULL; mp++) 1327 if (strcmp(mp->m_string, str) == 0) 1328 break; 1329 1330 return((mp->m_string == NULL) ? NULL : mp); 1331} 1332 1333/* 1334 * Function to convert a value to its corresponding string in a strmap array. 1335 * If the value is not found in the array, NULL is returned. 1336 */ 1337 1338char * 1339value_to_string(map, val) 1340struct strmap *map; 1341int val; 1342{ 1343 struct strmap *mp; 1344 1345 for (mp = map; mp->m_string != NULL; mp++) 1346 if (mp->m_value == val) 1347 break; 1348 1349 return mp->m_string; 1350} 1351 1352/* 1353 * Interpret cmdline options/arguments. Exit with 1 if something on the 1354 * cmdline isn't kosher. 1355 */ 1356 1357int 1358parse_cmdline(argc, argv, opts) 1359int argc; 1360char **argv; 1361char *opts; 1362{ 1363 int o, len, nb, format_error; 1364 struct strmap *flgs, *sc; 1365 char *file, *cp, ch; 1366 extern int opterr; 1367 extern int optind; 1368 extern char *optarg; 1369 struct strmap *mp; 1370 struct file_info *fptr; 1371 int nopenargs; 1372 char *openargs[5]; /* Flags, cbits, cblks */ 1373 char *errmsg; 1374 int str_to_int(); 1375 opterr = 0; 1376#ifndef linux 1377 char *ranges; 1378 struct strmap *type; 1379#endif 1380 1381 while ((o = getopt(argc, argv, opts)) != EOF) { 1382 switch ((char)o) { 1383 1384 case 'a': 1385#ifdef linux 1386 fprintf(stderr, "iogen%s: Unrecognized option -a on this platform\n", TagName); 1387 exit(2); 1388#else 1389 cp = strtok(optarg, ","); 1390 while (cp != NULL) { 1391 if ((type = str_lookup(Aio_Strat_Map, cp)) == NULL) { 1392 fprintf(stderr, "iogen%s: Unrecognized aio completion strategy: %s\n", TagName, cp); 1393 exit(2); 1394 } 1395 1396 Aio_Strat_List[Naio_Strat_Types++] = type; 1397 cp = strtok(NULL, ","); 1398 } 1399 a_opt++; 1400#endif 1401 break; 1402 1403 case 'f': 1404 cp = strtok(optarg, ","); 1405 while (cp != NULL) { 1406 if ((flgs = str_lookup(Flag_Map, cp)) == NULL) { 1407 fprintf(stderr, "iogen%s: Unrecognized flags: %s\n", TagName, cp); 1408 exit(2); 1409 } 1410 1411 cp = strtok(NULL, ","); 1412 1413#ifdef O_SSD 1414 if (flgs->m_value & O_SSD && ! Sds_Avail) { 1415 fprintf(stderr, "iogen%s: Warning - no sds available, ignoring ssd flag\n", TagName); 1416 continue; 1417 } 1418#endif 1419 1420 Flag_List[Nflags++] = flgs; 1421 } 1422 f_opt++; 1423 break; 1424 1425 case 'h': 1426 help(stdout); 1427 exit(0); 1428 break; 1429 1430 case 'i': 1431 format_error = 0; 1432 1433 switch (sscanf(optarg, "%i%c", &Iterations, &ch)) { 1434 case 1: 1435 Time_Mode = 0; 1436 break; 1437 1438 case 2: 1439 if (ch == 's') 1440 Time_Mode = 1; 1441 else 1442 format_error = 1; 1443 break; 1444 1445 default: 1446 format_error = 1; 1447 } 1448 1449 if (Iterations < 0) 1450 format_error = 1; 1451 1452 if (format_error) { 1453 fprintf(stderr, "iogen%s: Illegal -i arg (%s): Must be of the format: number[s]\n", TagName, optarg); 1454 fprintf(stderr, " where 'number' is >= 0\n"); 1455 exit(1); 1456 } 1457 1458 i_opt++; 1459 break; 1460 1461 case 'L': 1462#ifdef linux 1463 fprintf(stderr, "iogen%s: Unrecognized option -L on this platform\n", TagName); 1464 exit(2); 1465#else 1466 if ( parse_ranges(optarg, 1, 255, 1, NULL, &ranges, 1467 &errmsg ) == -1 ) { 1468 fprintf(stderr, "iogen%s: error parsing listio range '%s': %s\n", 1469 TagName, optarg, errmsg); 1470 exit(1); 1471 } 1472 1473 Minstrides = range_min(ranges, 0); 1474 Maxstrides = range_max(ranges, 0); 1475 1476 free(ranges); 1477 L_opt++; 1478#endif 1479 break; 1480 1481 case 'm': 1482 if ((Offset_Mode = str_lookup(Omode_Map, optarg)) == NULL) { 1483 fprintf(stderr, "iogen%s: Illegal -m arg (%s)\n", TagName, optarg); 1484 exit(1); 1485 } 1486 1487 m_opt++; 1488 break; 1489 1490 case 'N': 1491 sprintf( TagName, "(%.39s)", optarg ); 1492 break; 1493 1494 case 'o': 1495 o_opt++; 1496 break; 1497 1498 case 'O': 1499 1500 nopenargs = string_to_tokens(optarg, openargs, 4, ":/"); 1501 1502#ifdef CRAY 1503 if (nopenargs) 1504 sscanf(openargs[1],"%i", &Ocbits); 1505 if (nopenargs > 1) 1506 sscanf(openargs[2],"%i", &Ocblks); 1507 1508 Oflags = parse_open_flags(openargs[0], &errmsg); 1509 if (Oflags == -1) { 1510 fprintf(stderr, "iogen%s: -O %s error: %s\n", TagName, optarg, errmsg); 1511 exit(1); 1512 } 1513#endif 1514#ifdef linux 1515 Oflags = parse_open_flags(openargs[0], &errmsg); 1516 if (Oflags == -1) { 1517 fprintf(stderr, "iogen%s: -O %s error: %s\n", TagName, optarg, errmsg); 1518 exit(1); 1519 } 1520#endif 1521#ifdef sgi 1522 if (!strcmp(openargs[0], "realtime")) { 1523 /* 1524 * -O realtime:extsize 1525 */ 1526 Orealtime = 1; 1527 if (nopenargs > 1) 1528 sscanf(openargs[1],"%i", &Oextsize); 1529 else 1530 Oextsize=0; 1531 } else if (!strcmp(openargs[0], "allocate") || 1532 !strcmp(openargs[0], "allocsp")) { 1533 /* 1534 * -O allocate 1535 */ 1536 Oreserve=0; 1537 Oallocate=1; 1538 } else if (!strcmp(openargs[0], "reserve")) { 1539 /* 1540 * -O [no]reserve 1541 */ 1542 Oallocate=0; 1543 Oreserve=1; 1544 } else if (!strcmp(openargs[0], "noreserve")) { 1545 /* Oreserve=1 by default; this clears that default */ 1546 Oreserve=0; 1547 } else if (!strcmp(openargs[0], "nowrite")) { 1548 /* Owrite=1 by default; this clears that default */ 1549 Owrite=0; 1550 } else if (!strcmp(openargs[0], "direct")) { 1551 /* this means "use direct i/o to preallocate file" */ 1552 Owrite=2; 1553 } else { 1554 fprintf(stderr, "iogen%s: Error: -O %s error: unrecognized option\n", 1555 TagName, openargs[0]); 1556 exit(1); 1557 } 1558#endif 1559 1560 O_opt++; 1561 break; 1562 1563 case 'p': 1564 Outpipe = optarg; 1565 p_opt++; 1566 break; 1567 1568 case 'r': 1569 if ((Rawmult = str_to_bytes(optarg)) == -1 || 1570 Rawmult < 11 || Rawmult % BSIZE) { 1571 fprintf(stderr, "iogen%s: Illegal -r arg (%s). Must be > 0 and multipe of BSIZE (%d)\n", 1572 TagName, optarg, BSIZE); 1573 exit(1); 1574 } 1575 1576 r_opt++; 1577 break; 1578 1579 case 's': 1580 cp = strtok(optarg, ","); 1581 while (cp != NULL) { 1582 if ((sc = str_lookup(Syscall_Map, cp)) == NULL) { 1583 fprintf(stderr, "iogen%s: Unrecognized syscall: %s\n", TagName, cp); 1584 exit(2); 1585 } 1586 1587 do { 1588 /* >>> sc->m_flags & FLG_SDS */ 1589 if (sc->m_value != SSREAD && sc->m_value != SSWRITE) 1590 Fileio++; 1591 1592 Syscall_List[Nsyscalls++] = sc; 1593 } while ((sc = str_lookup(++sc, cp)) != NULL); 1594 1595 cp = strtok(NULL, ","); 1596 } 1597 s_opt++; 1598 break; 1599 1600 case 't': 1601 if ((Mintrans = str_to_bytes(optarg)) == -1) { 1602 fprintf(stderr, "iogen%s: Illegal -t arg (%s): Must have the form num[bkm]\n", TagName, optarg); 1603 exit(1); 1604 } 1605 t_opt++; 1606 break; 1607 1608 case 'T': 1609 if ((Maxtrans = str_to_bytes(optarg)) == -1) { 1610 fprintf(stderr, "iogen%s: Illegal -T arg (%s): Must have the form num[bkm]\n", TagName, optarg); 1611 exit(1); 1612 } 1613 T_opt++; 1614 break; 1615 1616 case 'q': 1617 q_opt++; 1618 break; 1619 1620 case '?': 1621 usage(stderr); 1622 exit(1); 1623 } 1624 } 1625 1626 /* 1627 * Supply defaults 1628 */ 1629 1630 if (!L_opt) { 1631 Minstrides = 1; 1632 Maxstrides = 255; 1633 } 1634 1635 if (!m_opt) 1636 Offset_Mode = str_lookup(Omode_Map, "sequential"); 1637 1638 if (!i_opt) 1639 Iterations = 0; 1640 1641 if (!t_opt) 1642 Mintrans = 1; 1643 1644 if (!T_opt) 1645 Maxtrans = 256 * BSIZE; 1646 1647 if (!O_opt) 1648 Oflags = Ocbits = Ocblks = 0; 1649 1650 /* 1651 * Supply default async io completion strategy types. 1652 */ 1653 1654 if (!a_opt) { 1655 for (mp = Aio_Strat_Map; mp->m_string != NULL; mp++) { 1656 Aio_Strat_List[Naio_Strat_Types++] = mp; 1657 } 1658 } 1659 1660 /* 1661 * Supply default syscalls. Default is read,write,reada,writea,listio. 1662 */ 1663 1664 if (!s_opt) { 1665 Nsyscalls = 0; 1666 Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "read"); 1667 Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "write"); 1668#ifdef CRAY 1669 Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "reada"); 1670 Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "writea"); 1671 Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "lread"); 1672 Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "lreada"); 1673 Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "lwrite"); 1674 Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "lwritea"); 1675#endif 1676 1677#ifdef sgi 1678 Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "pread"); 1679 Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "pwrite"); 1680 /*Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "aread");*/ 1681 /*Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "awrite");*/ 1682#endif 1683 1684#ifndef CRAY 1685 Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "readv"); 1686 Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "writev"); 1687 Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "mmread"); 1688 Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "mmwrite"); 1689#endif 1690 1691 Fileio = 1; 1692 } 1693 1694 if (Fileio && (argc - optind < 1)) { 1695 fprintf(stderr, "iogen%s: No files specified on the cmdline\n", TagName); 1696 exit(1); 1697 } 1698 1699 /* 1700 * Supply default file io flags - defaut is 'buffered,raw,sync,ldraw'. 1701 */ 1702 1703 if (!f_opt && Fileio) { 1704 Nflags = 0; 1705 Flag_List[Nflags++] = str_lookup(Flag_Map, "buffered"); 1706 Flag_List[Nflags++] = str_lookup(Flag_Map, "sync"); 1707#ifdef CRAY 1708 Flag_List[Nflags++] = str_lookup(Flag_Map, "raw+wf"); 1709 Flag_List[Nflags++] = str_lookup(Flag_Map, "ldraw"); 1710#endif 1711 1712#ifdef sgi 1713 /* Warning: cannot mix direct i/o with others! */ 1714 Flag_List[Nflags++] = str_lookup(Flag_Map, "dsync"); 1715 Flag_List[Nflags++] = str_lookup(Flag_Map, "rsync"); 1716 /* Flag_List[Nflags++] = str_lookup(Flag_Map, "rsync+sync");*/ 1717 /* Flag_List[Nflags++] = str_lookup(Flag_Map, "rsync+dsync");*/ 1718#endif 1719 } 1720 1721 if (Fileio) { 1722 if (optind >= argc) { 1723 fprintf(stderr, "iogen%s: No files listed on the cmdline\n", TagName); 1724 exit(1); 1725 } 1726 1727 /* 1728 * Initialize File_List[] - only necessary if doing file io. First 1729 * space for the File_List array, then fill it in. 1730 */ 1731 1732 File_List = (struct file_info *) 1733 malloc((argc-optind) * sizeof(struct file_info)); 1734 1735 if (File_List == NULL) { 1736 fprintf(stderr, "iogen%s: Could not malloc space for %d file_info structures\n", TagName, argc-optind); 1737 exit(2); 1738 } 1739 1740 memset(File_List, 0, (argc-optind) * sizeof(struct file_info)); 1741 1742 Nfiles = 0; 1743 while (optind < argc) { 1744 len = -1; 1745 1746 /* 1747 * Pick off leading len: if it's there and create/extend/trunc 1748 * the file to the desired length. Otherwise, just make sure 1749 * the file is accessable. 1750 */ 1751 1752 if ((cp = strchr(argv[optind], ':')) != NULL) { 1753 *cp = '\0'; 1754 if ((len = str_to_bytes(argv[optind])) == -1) { 1755 fprintf(stderr, 1756 "iogen%s: illegal file length (%s) for file %s\n", 1757 TagName, argv[optind], cp+1); 1758 exit(2); 1759 } 1760 *cp = ':'; 1761 file = cp+1; 1762 1763 if (strlen(file) > MAX_FNAME_LENGTH) { 1764 fprintf(stderr, "iogen%s: Max fname length is %d chars - ignoring file %s\n", 1765 TagName, MAX_FNAME_LENGTH, file); 1766 optind++; 1767 continue; 1768 } 1769 1770 nb = create_file(file, len); 1771 1772 if (nb < len) { 1773 fprintf(stderr, 1774 "iogen%s warning: Couldn't create file %s of %d bytes\n", 1775 TagName, file, len); 1776 1777 if (nb <= 0) { 1778 optind++; 1779 continue; 1780 } 1781 } 1782 } else { 1783 file = argv[optind]; 1784 if (access(file, R_OK | W_OK) == -1) { 1785 fprintf(stderr, "iogen%s: file %s cannot be accessed for reading and/or writing: %s (%d)\n", 1786 TagName, file, SYSERR, errno); 1787 exit(2); 1788 } 1789 } 1790 1791 /* 1792 * get per-file information 1793 */ 1794 1795 fptr = &File_List[Nfiles]; 1796 1797 if (file[0] == '/') { 1798 strcpy(fptr->f_path, file); 1799 } else { 1800 if (getcwd(fptr->f_path, sizeof(fptr->f_path)-1) == NULL) 1801 perror("Could not get current working directory"); 1802 strcat(fptr->f_path, "/"); 1803 strcat(fptr->f_path, file); 1804 } 1805 1806 if (get_file_info(fptr) == -1) { 1807 fprintf(stderr, "iogen%s warning: Error getting file info for %s\n", TagName, file); 1808 } else { 1809 1810 /* 1811 * If the file length is smaller than our min transfer size, 1812 * ignore it. 1813 */ 1814 1815 if (fptr->f_length < Mintrans) { 1816 fprintf(stderr, "iogen%s warning: Ignoring file %s\n", 1817 TagName, fptr->f_path); 1818 fprintf(stderr, " length (%d) is < min transfer size (%d)\n", 1819 fptr->f_length, Mintrans); 1820 optind++; 1821 continue; 1822 } 1823 1824 /* 1825 * If the file length is smaller than our max transfer size, 1826 * ignore it. 1827 */ 1828 1829 if (fptr->f_length < Maxtrans) { 1830 fprintf(stderr, "iogen%s warning: Ignoring file %s\n", 1831 TagName, fptr->f_path); 1832 fprintf(stderr, " length (%d) is < max transfer size (%d)\n", 1833 fptr->f_length, Maxtrans); 1834 optind++; 1835 continue; 1836 } 1837 1838 if (fptr->f_length > 0) { 1839 switch (Offset_Mode->m_value) { 1840 case M_SEQUENTIAL: 1841 fptr->f_lastoffset = 0; 1842 fptr->f_lastlength = 0; 1843 break; 1844 1845 case M_REVERSE: 1846 fptr->f_lastoffset = fptr->f_length; 1847 fptr->f_lastlength = 0; 1848 break; 1849 1850 case M_RANDOM: 1851 fptr->f_lastoffset = fptr->f_length / 2; 1852 fptr->f_lastlength = 0; 1853 break; 1854 } 1855 1856 Nfiles++; 1857 } 1858 } 1859 1860 optind++; 1861 } 1862 1863 if (Nfiles == 0) { 1864 fprintf(stderr, "iogen%s: Could not create, or gather info for any test files\n", TagName); 1865 exit(2); 1866 } 1867 } 1868 1869 return 0; 1870} 1871 1872int 1873help(stream) 1874FILE *stream; 1875{ 1876 usage(stream); 1877 fprintf(stream, "\n"); 1878#ifndef linux 1879 fprintf(stream, "\t-a aio_type,... Async io completion types to choose. Supported types\n"); 1880#ifdef CRAY 1881#if _UMK || RELEASE_LEVEL >= 8000 1882 fprintf(stream, "\t are: poll, signal, recall, recalla, and recalls.\n"); 1883#else 1884 fprintf(stream, "\t are: poll, signal, recalla, and recalls.\n"); 1885#endif 1886#else 1887 fprintf(stream, "\t are: poll, signal, suspend, and callback.\n"); 1888#endif 1889 fprintf(stream, "\t Default is all of the above.\n"); 1890#else /* !linux */ 1891 fprintf(stream, "\t-a (Not used on Linux).\n"); 1892#endif /* !linux */ 1893 fprintf(stream, "\t-f flag,... Flags to use for file IO. Supported flags are\n"); 1894#ifdef CRAY 1895 fprintf(stream, "\t raw, ssd, buffered, ldraw, sync,\n"); 1896 fprintf(stream, "\t raw+wf, raw+wf+ldraw, raw+wf+ldraw+sync,\n"); 1897 fprintf(stream, "\t and parallel (unicos/mk on MPP only).\n"); 1898 fprintf(stream, "\t Default is 'raw,ldraw,sync,buffered'.\n"); 1899#else 1900#ifdef sgi 1901 fprintf(stream, "\t buffered, direct, sync, dsync, rsync,\n"); 1902 fprintf(stream, "\t rsync+dsync.\n"); 1903 fprintf(stream, "\t Default is 'buffered,sync,dsync,rsync'.\n"); 1904#else 1905 fprintf(stream, "\t buffered, sync.\n"); 1906 fprintf(stream, "\t Default is 'buffered,sync'.\n"); 1907#endif /* sgi */ 1908#endif /* CRAY */ 1909 fprintf(stream, "\t-h This help.\n"); 1910 fprintf(stream, "\t-i iterations[s] # of requests to generate. 0 means causes iogen\n"); 1911 fprintf(stream, "\t to run until it's killed. If iterations is suffixed\n"); 1912 fprintf(stream, "\t with 's', then iterations is the number of seconds\n"); 1913 fprintf(stream, "\t that iogen should run for. Default is '0'.\n"); 1914#ifndef linux 1915 fprintf(stream, "\t-L min:max listio nstrides / nrequests range\n"); 1916#else 1917 fprintf(stream, "\t-L (Not used on Linux).\n"); 1918#endif /* !linux */ 1919 fprintf(stream, "\t-m offset-mode The mode by which iogen chooses the offset for\n"); 1920 fprintf(stream, "\t consectutive transfers within a given file.\n"); 1921 fprintf(stream, "\t Allowed values are 'random', 'sequential',\n"); 1922 fprintf(stream, "\t and 'reverse'.\n"); 1923 fprintf(stream, "\t sequential is the default.\n"); 1924 fprintf(stream, "\t-N tagname Tag name, for Monster.\n"); 1925 fprintf(stream, "\t-o Form overlapping consecutive requests.\n"); 1926 fprintf(stream, "\t-O Open flags for creating files\n"); 1927#ifdef CRAY 1928 fprintf(stream, "\t {O_PLACE,O_BIG,etc}[:CBITS[:CBLKS]]\n"); 1929#endif 1930#ifdef sgi 1931 fprintf(stream, "\t realtime:extsize - put file on real-time volume\n"); 1932 fprintf(stream, "\t allocate - allocate space with F_ALLOCSP\n"); 1933 fprintf(stream, "\t reserve - reserve space with F_RESVSP (default)\n"); 1934 fprintf(stream, "\t noreserve - do not reserve with F_RESVSP\n"); 1935 fprintf(stream, "\t direct - use O_DIRECT I/O to write to the file\n"); 1936#endif 1937#ifdef linux 1938 fprintf(stream, "\t {O_SYNC,etc}\n"); 1939#endif 1940 fprintf(stream, "\t-p Output pipe. Default is stdout.\n"); 1941 fprintf(stream, "\t-q Quiet mode. Normally iogen spits out info\n"); 1942 fprintf(stream, "\t about test files, options, etc. before starting.\n"); 1943 fprintf(stream, "\t-s syscall,... Syscalls to do. Supported syscalls are\n"); 1944#ifdef sgi 1945 fprintf(stream, "\t read, write, pread, pwrite, readv, writev\n"); 1946 fprintf(stream, "\t aread, awrite, resvsp, unresvsp, ffsync,\n"); 1947 fprintf(stream, "\t mmread, mmwrite, fsync2, fdatasync,\n"); 1948 fprintf(stream, "\t Default is 'read,write,pread,pwrite,readv,writev,mmread,mmwrite'.\n"); 1949#endif 1950#ifdef CRAY 1951 fprintf(stream, "\t read, write, reada, writea, listio,\n"); 1952 fprintf(stream, "\t ssread (PVP only), and sswrite (PVP only).\n"); 1953 fprintf(stream, "\t Default is 'read,write,reada,writea,listio'.\n"); 1954#endif 1955#ifdef linux 1956 fprintf(stream, "\t read, write, readv, writev,\n"); 1957 fprintf(stream, "\t mmread, mmwrite, fsync2, fdatasync,\n"); 1958 fprintf(stream, "\t Default is 'read,write,readv,writev,mmread,mmwrite'.\n"); 1959#endif 1960 fprintf(stream, "\t-t mintrans Min transfer length\n"); 1961 fprintf(stream, "\t-T maxtrans Max transfer length\n"); 1962 fprintf(stream, "\n"); 1963 fprintf(stream, "\t[len:]file,... Test files to do IO against (note ssread/sswrite\n"); 1964 fprintf(stream, "\t don't need a test file). The len: syntax\n"); 1965 fprintf(stream, "\t informs iogen to first create/expand/truncate the\n"); 1966 fprintf(stream, "\t to the desired length.\n"); 1967 fprintf(stream, "\n"); 1968 fprintf(stream, "\tNote: The ssd flag causes sds transfers to also be done.\n"); 1969 fprintf(stream, "\t To totally eliminate sds transfers, you must eleminate sds\n"); 1970 fprintf(stream, "\t from the flags (-f) and ssread,ssrite from the syscalls (-s)\n"); 1971 fprintf(stream, "\tThe mintrans, maxtrans, and len: parameters are numbers of the\n"); 1972 fprintf(stream, "\tform [0-9]+[bkm]. The optional trailing b, k, or m multiplies\n"); 1973 fprintf(stream, "\tthe number by blocks, kilobytes, or megabytes. If no trailing\n"); 1974 fprintf(stream, "\tmultiplier is present, the number is interpreted as bytes\n"); 1975 1976 return 0; 1977} 1978 1979/* 1980 * Obvious - usage clause 1981 */ 1982 1983int 1984usage(stream) 1985FILE *stream; 1986{ 1987 fprintf(stream, "usage%s: iogen [-hoq] [-a aio_type,...] [-f flag[,flag...]] [-i iterations] [-p outpipe] [-m offset-mode] [-s syscall[,syscall...]] [-t mintrans] [-T maxtrans] [ -O file-create-flags ] [[len:]file ...]\n", TagName); 1988 return 0; 1989}