1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 %{ 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 %} 29 30 %{ 31 32 #include <stdlib.h> 33 #include <stdio.h> 34 #include <string.h> 35 #include <signal.h> 36 #include <errno.h> 37 #include <sys/types.h> 38 #include <locale.h> 39 #include <sys/utsname.h> 40 #ifdef HAVE_STDINT_H 41 #include <stdint.h> 42 #endif 43 #include <fcntl.h> 44 #include <sys/mman.h> 45 #include <sys/wait.h> 46 #ifdef HAVE_LIBTECLA 47 #include <libtecla.h> 48 #endif 49 #include "parsertypes.h" 50 #include "filebench.h" 51 #include "utils.h" 52 #include "stats.h" 53 #include "vars.h" 54 #include "eventgen.h" 55 #ifdef HAVE_LIBTECLA 56 #include "auto_comp.h" 57 #endif 58 59 int dofile = FS_FALSE; 60 static const char cmdname[] = "filebench"; 61 static const char cmd_options[] = "pa:f:hi:s:m:"; 62 static void usage(int); 63 64 static cmd_t *cmd = NULL; /* Command being processed */ 65 #ifdef HAVE_LIBTECLA 66 static GetLine *gl; /* GetLine resource object */ 67 #endif 68 69 char *execname; 70 char *fscriptname; 71 int noproc = 0; 72 var_t *var_list = NULL; 73 pidlist_t *pidlist = NULL; 74 char *cwd = NULL; 75 FILE *parentscript = NULL; 76 77 static int filecreate_done = 0; 78 79 /* yacc externals */ 80 extern FILE *yyin; 81 extern int yydebug; 82 extern void yyerror(char *s); 83 84 /* utilities */ 85 static void terminate(void); 86 static cmd_t *alloc_cmd(void); 87 static attr_t *alloc_attr(void); 88 static attr_t *get_attr(cmd_t *cmd, int64_t name); 89 static attr_t *get_attr_integer(cmd_t *cmd, int64_t name); 90 static attr_t *get_attr_bool(cmd_t *cmd, int64_t name); 91 static var_t *alloc_var(void); 92 static var_t *get_var(cmd_t *cmd, int64_t name); 93 static list_t *alloc_list(); 94 static probtabent_t *alloc_probtabent(void); 95 96 /* Info Commands */ 97 static void parser_list(cmd_t *); 98 static void parser_flowop_list(cmd_t *); 99 100 /* Define Commands */ 101 static void parser_proc_define(cmd_t *); 102 static void parser_thread_define(cmd_t *, procflow_t *, int instances); 103 static void parser_flowop_define(cmd_t *, threadflow_t *, flowop_t **, int); 104 static void parser_file_define(cmd_t *); 105 static void parser_fileset_define(cmd_t *); 106 static void parser_randvar_define(cmd_t *); 107 static void parser_randvar_set(cmd_t *); 108 109 /* Create Commands */ 110 static void parser_proc_create(cmd_t *); 111 static void parser_thread_create(cmd_t *); 112 static void parser_flowop_create(cmd_t *); 113 static void parser_fileset_create(cmd_t *); 114 115 /* set commands */ 116 static void parser_set_integer(char *, fbint_t); 117 static void parser_set_var(char *, char *); 118 119 /* Shutdown Commands */ 120 static void parser_proc_shutdown(cmd_t *); 121 static void parser_filebench_shutdown(cmd_t *cmd); 122 123 /* Other Commands */ 124 static void parser_foreach_integer(cmd_t *cmd); 125 static void parser_foreach_string(cmd_t *cmd); 126 static void parser_sleep(cmd_t *cmd); 127 static void parser_sleep_variable(cmd_t *cmd); 128 static void parser_log(cmd_t *cmd); 129 static void parser_statscmd(cmd_t *cmd); 130 static void parser_statsdump(cmd_t *cmd); 131 static void parser_statsxmldump(cmd_t *cmd); 132 static void parser_echo(cmd_t *cmd); 133 static void parser_usage(cmd_t *cmd); 134 static void parser_vars(cmd_t *cmd); 135 static void parser_printvars(cmd_t *cmd); 136 static void parser_system(cmd_t *cmd); 137 static void parser_statssnap(cmd_t *cmd); 138 static void parser_directory(cmd_t *cmd); 139 static void parser_eventgen(cmd_t *cmd); 140 static void parser_run(cmd_t *cmd); 141 static void parser_run_variable(cmd_t *cmd); 142 static void parser_help(cmd_t *cmd); 143 static void arg_parse(const char *command); 144 static void parser_abort(int arg); 145 146 %} 147 148 %union { 149 int64_t ival; 150 uchar_t bval; 151 char * sval; 152 fs_u val; 153 avd_t avd; 154 cmd_t *cmd; 155 attr_t *attr; 156 list_t *list; 157 probtabent_t *rndtb; 158 } 159 160 %start commands 161 162 %token FSC_LIST FSC_DEFINE FSC_EXEC FSC_QUIT FSC_DEBUG FSC_CREATE 163 %token FSC_SLEEP FSC_STATS FSC_FOREACH FSC_SET FSC_SHUTDOWN FSC_LOG 164 %token FSC_SYSTEM FSC_FLOWOP FSC_EVENTGEN FSC_ECHO FSC_LOAD FSC_RUN 165 %token FSC_USAGE FSC_HELP FSC_VARS 166 %token FSV_STRING FSV_VAL_INT FSV_VAL_BOOLEAN FSV_VARIABLE FSV_WHITESTRING 167 %token FSV_RANDUNI FSV_RANDTAB FSV_RANDVAR FSV_URAND FSV_RAND48 168 %token FST_INT FST_BOOLEAN 169 %token FSE_FILE FSE_PROC FSE_THREAD FSE_CLEAR FSE_ALL FSE_SNAP FSE_DUMP 170 %token FSE_DIRECTORY FSE_COMMAND FSE_FILESET FSE_XMLDUMP FSE_RAND FSE_MODE 171 %token FSK_SEPLST FSK_OPENLST FSK_CLOSELST FSK_ASSIGN FSK_IN FSK_QUOTE 172 %token FSK_DIRSEPLST 173 %token FSA_SIZE FSA_PREALLOC FSA_PARALLOC FSA_PATH FSA_REUSE 174 %token FSA_PROCESS FSA_MEMSIZE FSA_RATE FSA_CACHED 175 %token FSA_IOSIZE FSA_FILE FSA_WSS FSA_NAME FSA_RANDOM FSA_INSTANCES 176 %token FSA_DSYNC FSA_TARGET FSA_ITERS FSA_NICE FSA_VALUE FSA_BLOCKING 177 %token FSA_HIGHWATER FSA_DIRECTIO FSA_DIRWIDTH FSA_FD FSA_SRCFD FSA_ROTATEFD 178 %token FSA_NAMELENGTH FSA_FILESIZE FSA_ENTRIES FSA_FILESIZEGAMMA FSA_DIRDEPTHRV 179 %token FSA_DIRGAMMA FSA_USEISM FSA_TYPE FSA_RANDTABLE FSA_RANDSRC FSA_RANDROUND 180 %token FSA_RANDSEED FSA_RANDGAMMA FSA_RANDMEAN FSA_RANDMIN 181 %token FSS_TYPE FSS_SEED FSS_GAMMA FSS_MEAN FSS_MIN FSS_SRC FSS_ROUND 182 %token FSA_ALLDONE FSA_FIRSTDONE FSA_TIMEOUT 183 184 %type <ival> FSV_VAL_INT 185 %type <bval> FSV_VAL_BOOLEAN 186 %type <sval> FSV_STRING 187 %type <sval> FSV_WHITESTRING 188 %type <sval> FSV_VARIABLE 189 %type <sval> FSV_RANDVAR 190 %type <sval> FSK_ASSIGN 191 192 %type <ival> FSC_LIST FSC_DEFINE FSC_SET FSC_LOAD FSC_RUN 193 %type <ival> FSE_FILE FSE_PROC FSE_THREAD FSE_CLEAR FSC_HELP 194 195 %type <sval> name 196 %type <ival> entity 197 %type <val> value 198 199 %type <cmd> command inner_commands load_command run_command list_command 200 %type <cmd> proc_define_command files_define_command randvar_define_command 201 %type <cmd> debug_command create_command 202 %type <cmd> sleep_command stats_command set_command shutdown_command 203 %type <cmd> foreach_command log_command system_command flowop_command 204 %type <cmd> eventgen_command quit_command flowop_list thread_list 205 %type <cmd> thread echo_command usage_command help_command vars_command 206 207 %type <attr> files_attr_op files_attr_ops pt_attr_op pt_attr_ops 208 %type <attr> fo_attr_op fo_attr_ops ev_attr_op ev_attr_ops 209 %type <attr> randvar_attr_op randvar_attr_ops randvar_attr_typop 210 %type <attr> randvar_attr_srcop attr_value attr_list_value 211 %type <list> integer_seplist string_seplist string_list var_string_list 212 %type <list> var_string whitevar_string whitevar_string_list 213 %type <ival> attrs_define_file attrs_define_thread attrs_flowop 214 %type <ival> attrs_define_fileset attrs_define_proc attrs_eventgen 215 %type <ival> files_attr_name pt_attr_name fo_attr_name ev_attr_name 216 %type <ival> randvar_attr_name FSA_TYPE randtype_name randvar_attr_param 217 %type <ival> randsrc_name FSA_RANDSRC randvar_attr_tsp 218 %type <ival> FSS_TYPE FSS_SEED FSS_GAMMA FSS_MEAN FSS_MIN FSS_SRC 219 220 %type <rndtb> probtabentry_list probtabentry 221 %type <avd> var_int_val 222 %% 223 224 commands: commands command 225 { 226 list_t *list = NULL; 227 list_t *list_end = NULL; 228 229 if ($2->cmd != NULL) 230 $2->cmd($2); 231 232 free($2); 233 } 234 | commands error 235 { 236 if (dofile) 237 YYABORT; 238 } 239 |; 240 241 inner_commands: command 242 { 243 filebench_log(LOG_DEBUG_IMPL, "inner_command %zx", $1); 244 $$ = $1; 245 } 246 | inner_commands command 247 { 248 cmd_t *list = NULL; 249 cmd_t *list_end = NULL; 250 251 /* Find end of list */ 252 for (list = $1; list != NULL; 253 list = list->cmd_next) 254 list_end = list; 255 256 list_end->cmd_next = $2; 257 258 filebench_log(LOG_DEBUG_IMPL, 259 "inner_commands adding cmd %zx to list %zx", $2, $1); 260 261 $$ = $1; 262 }; 263 264 command: 265 proc_define_command 266 | files_define_command 267 | randvar_define_command 268 | debug_command 269 | eventgen_command 270 | create_command 271 | echo_command 272 | usage_command 273 | vars_command 274 | foreach_command 275 | help_command 276 | list_command 277 | load_command 278 | log_command 279 | run_command 280 | set_command 281 | shutdown_command 282 | sleep_command 283 | stats_command 284 | system_command 285 | quit_command; 286 287 foreach_command: FSC_FOREACH 288 { 289 if (($$ = alloc_cmd()) == NULL) 290 YYERROR; 291 filebench_log(LOG_DEBUG_IMPL, "foreach_command %zx", $$); 292 } 293 | foreach_command FSV_VARIABLE FSK_IN integer_seplist FSK_OPENLST inner_commands FSK_CLOSELST 294 { 295 cmd_t *cmd, *inner_cmd; 296 list_t *list; 297 298 $$ = $1; 299 $$->cmd_list = $6; 300 $$->cmd_tgt1 = $2; 301 $$->cmd_param_list = $4; 302 $$->cmd = parser_foreach_integer; 303 304 for (list = $$->cmd_param_list; list != NULL; 305 list = list->list_next) { 306 for (inner_cmd = $$->cmd_list; 307 inner_cmd != NULL; 308 inner_cmd = inner_cmd->cmd_next) { 309 filebench_log(LOG_DEBUG_IMPL, 310 "packing foreach: %zx %s=%llu, cmd %zx", 311 $$, $$->cmd_tgt1, 312 (u_longlong_t)avd_get_int(list->list_integer), 313 inner_cmd); 314 } 315 } 316 }| foreach_command FSV_VARIABLE FSK_IN string_seplist FSK_OPENLST inner_commands FSK_CLOSELST 317 { 318 cmd_t *cmd, *inner_cmd; 319 list_t *list; 320 321 $$ = $1; 322 $$->cmd_list = $6; 323 $$->cmd_tgt1 = $2; 324 $$->cmd_param_list = $4; 325 $$->cmd = parser_foreach_string; 326 327 for (list = $$->cmd_param_list; list != NULL; 328 list = list->list_next) { 329 for (inner_cmd = $$->cmd_list; 330 inner_cmd != NULL; 331 inner_cmd = inner_cmd->cmd_next) { 332 filebench_log(LOG_DEBUG_IMPL, 333 "packing foreach: %zx %s=%s, cmd %zx", 334 $$, 335 $$->cmd_tgt1, 336 *list->list_string, inner_cmd); 337 } 338 } 339 }; 340 341 integer_seplist: FSV_VAL_INT 342 { 343 if (($$ = alloc_list()) == NULL) 344 YYERROR; 345 346 $$->list_integer = avd_int_alloc($1); 347 } 348 | integer_seplist FSK_SEPLST FSV_VAL_INT 349 { 350 list_t *list = NULL; 351 list_t *list_end = NULL; 352 353 if (($$ = alloc_list()) == NULL) 354 YYERROR; 355 356 $$->list_integer = avd_int_alloc($3); 357 358 /* Find end of list */ 359 for (list = $1; list != NULL; 360 list = list->list_next) 361 list_end = list; 362 list_end->list_next = $$; 363 $$ = $1; 364 }; 365 366 string_seplist: FSK_QUOTE FSV_WHITESTRING FSK_QUOTE 367 { 368 if (($$ = alloc_list()) == NULL) 369 YYERROR; 370 371 $$->list_string = avd_str_alloc($2); 372 } 373 | string_seplist FSK_SEPLST FSK_QUOTE FSV_WHITESTRING FSK_QUOTE 374 { 375 list_t *list = NULL; 376 list_t *list_end = NULL; 377 378 if (($$ = alloc_list()) == NULL) 379 YYERROR; 380 381 $$->list_string = avd_str_alloc($4); 382 383 /* Find end of list */ 384 for (list = $1; list != NULL; 385 list = list->list_next) 386 list_end = list; 387 list_end->list_next = $$; 388 $$ = $1; 389 }; 390 391 eventgen_command: FSC_EVENTGEN 392 { 393 if (($$ = alloc_cmd()) == NULL) 394 YYERROR; 395 $$->cmd = &parser_eventgen; 396 } 397 | eventgen_command ev_attr_ops 398 { 399 $1->cmd_attr_list = $2; 400 }; 401 402 system_command: FSC_SYSTEM whitevar_string_list 403 { 404 if (($$ = alloc_cmd()) == NULL) 405 YYERROR; 406 407 $$->cmd_param_list = $2; 408 $$->cmd = parser_system; 409 }; 410 411 echo_command: FSC_ECHO whitevar_string_list 412 { 413 if (($$ = alloc_cmd()) == NULL) 414 YYERROR; 415 416 $$->cmd_param_list = $2; 417 $$->cmd = parser_echo; 418 }; 419 420 usage_command: FSC_USAGE whitevar_string_list 421 { 422 if (($$ = alloc_cmd()) == NULL) 423 YYERROR; 424 425 $$->cmd_param_list = $2; 426 $$->cmd = parser_usage; 427 }; 428 429 vars_command: FSC_VARS 430 { 431 if (($$ = alloc_cmd()) == NULL) 432 YYERROR; 433 434 $$->cmd = parser_printvars; 435 }; 436 437 string_list: FSV_VARIABLE 438 { 439 if (($$ = alloc_list()) == NULL) 440 YYERROR; 441 $$->list_string = avd_str_alloc($1); 442 } 443 | string_list FSK_SEPLST FSV_VARIABLE 444 { 445 list_t *list = NULL; 446 list_t *list_end = NULL; 447 448 if (($$ = alloc_list()) == NULL) 449 YYERROR; 450 451 $$->list_string = avd_str_alloc($3); 452 453 /* Find end of list */ 454 for (list = $1; list != NULL; 455 list = list->list_next) 456 list_end = list; 457 list_end->list_next = $$; 458 $$ = $1; 459 }; 460 461 var_string: FSV_VARIABLE 462 { 463 if (($$ = alloc_list()) == NULL) 464 YYERROR; 465 466 $$->list_string = avd_str_alloc($1); 467 } 468 | FSV_STRING 469 { 470 if (($$ = alloc_list()) == NULL) 471 YYERROR; 472 473 $$->list_string = avd_str_alloc($1); 474 }; 475 476 var_string_list: var_string 477 { 478 $$ = $1; 479 }| var_string FSV_STRING 480 { 481 list_t *list = NULL; 482 list_t *list_end = NULL; 483 484 /* Add string */ 485 if (($$ = alloc_list()) == NULL) 486 YYERROR; 487 488 $$->list_string = avd_str_alloc($2); 489 490 /* Find end of list */ 491 for (list = $1; list != NULL; 492 list = list->list_next) 493 list_end = list; 494 list_end->list_next = $$; 495 $$ = $1; 496 497 }| var_string FSV_VARIABLE 498 { 499 list_t *list = NULL; 500 list_t *list_end = NULL; 501 502 /* Add variable */ 503 if (($$ = alloc_list()) == NULL) 504 YYERROR; 505 506 $$->list_string = avd_str_alloc($2); 507 508 /* Find end of list */ 509 for (list = $1; list != NULL; 510 list = list->list_next) 511 list_end = list; 512 list_end->list_next = $$; 513 $$ = $1; 514 } |var_string_list FSV_STRING 515 { 516 list_t *list = NULL; 517 list_t *list_end = NULL; 518 519 /* Add string */ 520 if (($$ = alloc_list()) == NULL) 521 YYERROR; 522 523 $$->list_string = avd_str_alloc($2); 524 525 /* Find end of list */ 526 for (list = $1; list != NULL; 527 list = list->list_next) 528 list_end = list; 529 list_end->list_next = $$; 530 $$ = $1; 531 532 }| var_string_list FSV_VARIABLE 533 { 534 list_t *list = NULL; 535 list_t *list_end = NULL; 536 537 /* Add variable */ 538 if (($$ = alloc_list()) == NULL) 539 YYERROR; 540 541 $$->list_string = avd_str_alloc($2); 542 543 /* Find end of list */ 544 for (list = $1; list != NULL; 545 list = list->list_next) 546 list_end = list; 547 list_end->list_next = $$; 548 $$ = $1; 549 }; 550 551 whitevar_string: FSK_QUOTE FSV_VARIABLE 552 { 553 if (($$ = alloc_list()) == NULL) 554 YYERROR; 555 556 $$->list_string = avd_str_alloc($2); 557 } 558 | FSK_QUOTE FSV_WHITESTRING 559 { 560 if (($$ = alloc_list()) == NULL) 561 YYERROR; 562 563 $$->list_string = avd_str_alloc($2); 564 }; 565 566 whitevar_string_list: whitevar_string FSV_WHITESTRING 567 { 568 list_t *list = NULL; 569 list_t *list_end = NULL; 570 571 /* Add string */ 572 if (($$ = alloc_list()) == NULL) 573 YYERROR; 574 575 $$->list_string = avd_str_alloc($2); 576 577 /* Find end of list */ 578 for (list = $1; list != NULL; 579 list = list->list_next) 580 list_end = list; 581 list_end->list_next = $$; 582 $$ = $1; 583 584 }| whitevar_string FSV_VARIABLE 585 { 586 list_t *list = NULL; 587 list_t *list_end = NULL; 588 589 /* Add variable */ 590 if (($$ = alloc_list()) == NULL) 591 YYERROR; 592 593 $$->list_string = avd_str_alloc($2); 594 595 /* Find end of list */ 596 for (list = $1; list != NULL; 597 list = list->list_next) 598 list_end = list; 599 list_end->list_next = $$; 600 $$ = $1; 601 }| whitevar_string FSV_RANDVAR randvar_attr_tsp 602 { 603 list_t *list = NULL; 604 list_t *list_end = NULL; 605 606 /* Add variable */ 607 if (($$ = alloc_list()) == NULL) 608 YYERROR; 609 610 $$->list_string = avd_str_alloc($2); 611 $$->list_integer = avd_int_alloc($3); 612 613 /* Find end of list */ 614 for (list = $1; list != NULL; 615 list = list->list_next) 616 list_end = list; 617 list_end->list_next = $$; 618 $$ = $1; 619 }| whitevar_string_list FSV_WHITESTRING 620 { 621 list_t *list = NULL; 622 list_t *list_end = NULL; 623 624 /* Add string */ 625 if (($$ = alloc_list()) == NULL) 626 YYERROR; 627 628 $$->list_string = avd_str_alloc($2); 629 630 /* Find end of list */ 631 for (list = $1; list != NULL; 632 list = list->list_next) 633 list_end = list; 634 list_end->list_next = $$; 635 $$ = $1; 636 637 }| whitevar_string_list FSV_VARIABLE 638 { 639 list_t *list = NULL; 640 list_t *list_end = NULL; 641 642 /* Add variable */ 643 if (($$ = alloc_list()) == NULL) 644 YYERROR; 645 646 $$->list_string = avd_str_alloc($2); 647 648 /* Find end of list */ 649 for (list = $1; list != NULL; 650 list = list->list_next) 651 list_end = list; 652 list_end->list_next = $$; 653 $$ = $1; 654 }| whitevar_string_list FSV_RANDVAR randvar_attr_tsp 655 { 656 list_t *list = NULL; 657 list_t *list_end = NULL; 658 659 /* Add variable */ 660 if (($$ = alloc_list()) == NULL) 661 YYERROR; 662 663 $$->list_string = avd_str_alloc($2); 664 $$->list_integer = avd_int_alloc($3); 665 666 /* Find end of list */ 667 for (list = $1; list != NULL; 668 list = list->list_next) 669 list_end = list; 670 list_end->list_next = $$; 671 $$ = $1; 672 }| whitevar_string_list FSK_QUOTE 673 { 674 $$ = $1; 675 }| whitevar_string FSK_QUOTE 676 { 677 $$ = $1; 678 }; 679 680 list_command: FSC_LIST 681 { 682 if (($$ = alloc_cmd()) == NULL) 683 YYERROR; 684 $$->cmd = &parser_list; 685 } 686 | list_command FSC_FLOWOP 687 { 688 $1->cmd = &parser_flowop_list; 689 }; 690 691 log_command: FSC_LOG whitevar_string_list 692 { 693 if (($$ = alloc_cmd()) == NULL) 694 YYERROR; 695 $$->cmd = &parser_log; 696 $$->cmd_param_list = $2; 697 }; 698 699 debug_command: FSC_DEBUG FSV_VAL_INT 700 { 701 if (($$ = alloc_cmd()) == NULL) 702 YYERROR; 703 $$->cmd = NULL; 704 filebench_shm->debug_level = $2; 705 if (filebench_shm->debug_level > 9) 706 yydebug = 1; 707 }; 708 709 set_command: FSC_SET FSV_VARIABLE FSK_ASSIGN FSV_VAL_INT 710 { 711 if (($$ = alloc_cmd()) == NULL) 712 YYERROR; 713 var_assign_integer($2, $4); 714 if (parentscript) { 715 $$->cmd_tgt1 = $2; 716 parser_vars($$); 717 } 718 $$->cmd = NULL; 719 } 720 | FSC_SET FSV_VARIABLE FSK_ASSIGN FSV_VAL_BOOLEAN 721 { 722 if (($$ = alloc_cmd()) == NULL) 723 YYERROR; 724 var_assign_boolean($2, $4); 725 if (parentscript) { 726 $$->cmd_tgt1 = $2; 727 parser_vars($$); 728 } 729 $$->cmd = NULL; 730 } 731 | FSC_SET FSV_VARIABLE FSK_ASSIGN FSK_QUOTE FSV_WHITESTRING FSK_QUOTE 732 { 733 if (($$ = alloc_cmd()) == NULL) 734 YYERROR; 735 var_assign_string($2, $5); 736 if (parentscript) { 737 $$->cmd_tgt1 = $2; 738 parser_vars($$); 739 } 740 $$->cmd = NULL; 741 }| FSC_SET FSV_VARIABLE FSK_ASSIGN FSV_STRING 742 { 743 if (($$ = alloc_cmd()) == NULL) 744 YYERROR; 745 var_assign_string($2, $4); 746 if (parentscript) { 747 $$->cmd_tgt1 = $2; 748 parser_vars($$); 749 } 750 $$->cmd = NULL; 751 }| FSC_SET FSV_VARIABLE FSK_ASSIGN FSV_VARIABLE 752 { 753 if (($$ = alloc_cmd()) == NULL) 754 YYERROR; 755 var_assign_var($2, $4); 756 if (parentscript) { 757 $$->cmd_tgt1 = $2; 758 parser_vars($$); 759 } 760 $$->cmd = NULL; 761 } | FSC_SET FSE_MODE FSC_QUIT FSA_TIMEOUT 762 { 763 filebench_shm->shm_rmode = FILEBENCH_MODE_TIMEOUT; 764 if (($$ = alloc_cmd()) == NULL) 765 YYERROR; 766 $$->cmd = NULL; 767 } | FSC_SET FSE_MODE FSC_QUIT FSA_ALLDONE 768 { 769 filebench_shm->shm_rmode = FILEBENCH_MODE_QALLDONE; 770 if (($$ = alloc_cmd()) == NULL) 771 YYERROR; 772 $$->cmd = NULL; 773 } | FSC_SET FSE_MODE FSC_QUIT FSA_FIRSTDONE 774 { 775 filebench_shm->shm_rmode = FILEBENCH_MODE_Q1STDONE; 776 if (($$ = alloc_cmd()) == NULL) 777 YYERROR; 778 $$->cmd = NULL; 779 }| FSC_SET FSV_RANDVAR FSS_TYPE FSK_ASSIGN randvar_attr_typop 780 { 781 if (($$ = alloc_cmd()) == NULL) 782 YYERROR; 783 $$->cmd = &parser_randvar_set; 784 $$->cmd_tgt1 = $2; 785 $$->cmd_qty = FSS_TYPE; 786 $$->cmd_attr_list = $5; 787 788 }| FSC_SET FSV_RANDVAR FSS_SRC FSK_ASSIGN randvar_attr_srcop 789 { 790 if (($$ = alloc_cmd()) == NULL) 791 YYERROR; 792 $$->cmd = &parser_randvar_set; 793 $$->cmd_tgt1 = $2; 794 $$->cmd_qty = FSS_SRC; 795 $$->cmd_attr_list = $5; 796 797 }| FSC_SET FSV_RANDVAR randvar_attr_param FSK_ASSIGN attr_value 798 { 799 if (($$ = alloc_cmd()) == NULL) 800 YYERROR; 801 $$->cmd = &parser_randvar_set; 802 $$->cmd_tgt1 = $2; 803 $$->cmd_qty = $3; 804 $$->cmd_attr_list = $5; 805 806 }; 807 808 stats_command: FSC_STATS FSE_SNAP 809 { 810 if (($$ = alloc_cmd()) == NULL) 811 YYERROR; 812 $$->cmd = (void (*)(struct cmd *))&parser_statssnap; 813 break; 814 815 } 816 | FSC_STATS FSE_CLEAR 817 { 818 if (($$ = alloc_cmd()) == NULL) 819 YYERROR; 820 $$->cmd = (void (*)(struct cmd *))&stats_clear; 821 822 } 823 | FSC_STATS FSE_DIRECTORY var_string_list 824 { 825 if (($$ = alloc_cmd()) == NULL) 826 YYERROR; 827 $$->cmd_param_list = $3; 828 $$->cmd = (void (*)(struct cmd *))&parser_directory; 829 830 } 831 | FSC_STATS FSE_COMMAND whitevar_string_list 832 { 833 if (($$ = alloc_cmd()) == NULL) 834 YYERROR; 835 836 $$->cmd_param_list = $3; 837 $$->cmd = parser_statscmd; 838 839 }| FSC_STATS FSE_DUMP whitevar_string_list 840 { 841 if (($$ = alloc_cmd()) == NULL) 842 YYERROR; 843 844 $$->cmd_param_list = $3; 845 $$->cmd = parser_statsdump; 846 }| FSC_STATS FSE_XMLDUMP whitevar_string_list 847 { 848 if (($$ = alloc_cmd()) == NULL) 849 YYERROR; 850 851 $$->cmd_param_list = $3; 852 $$->cmd = parser_statsxmldump; 853 }; 854 855 quit_command: FSC_QUIT 856 { 857 if (($$ = alloc_cmd()) == NULL) 858 YYERROR; 859 $$->cmd = parser_filebench_shutdown; 860 }; 861 862 flowop_list: flowop_command 863 { 864 $$ = $1; 865 }| flowop_list flowop_command 866 { 867 cmd_t *list = NULL; 868 cmd_t *list_end = NULL; 869 870 /* Find end of list */ 871 for (list = $1; list != NULL; 872 list = list->cmd_next) 873 list_end = list; 874 875 list_end->cmd_next = $2; 876 877 filebench_log(LOG_DEBUG_IMPL, 878 "flowop_list adding cmd %zx to list %zx", $2, $1); 879 880 $$ = $1; 881 }; 882 883 thread: FSE_THREAD pt_attr_ops FSK_OPENLST flowop_list FSK_CLOSELST 884 { 885 /* 886 * Allocate a cmd node per thread, with a 887 * list of flowops attached to the cmd_list 888 */ 889 if (($$ = alloc_cmd()) == NULL) 890 YYERROR; 891 $$->cmd_list = $4; 892 $$->cmd_attr_list = $2; 893 }; 894 895 thread_list: thread 896 { 897 $$ = $1; 898 }| thread_list thread 899 { 900 cmd_t *list = NULL; 901 cmd_t *list_end = NULL; 902 903 /* Find end of list */ 904 for (list = $1; list != NULL; 905 list = list->cmd_next) 906 list_end = list; 907 908 list_end->cmd_next = $2; 909 910 filebench_log(LOG_DEBUG_IMPL, 911 "thread_list adding cmd %zx to list %zx", $2, $1); 912 913 $$ = $1; 914 }; 915 916 proc_define_command: FSC_DEFINE FSE_PROC pt_attr_ops FSK_OPENLST thread_list FSK_CLOSELST 917 { 918 if (($$ = alloc_cmd()) == NULL) 919 YYERROR; 920 $$->cmd = &parser_proc_define; 921 $$->cmd_list = $5; 922 $$->cmd_attr_list = $3; 923 924 } 925 | proc_define_command pt_attr_ops 926 { 927 $1->cmd_attr_list = $2; 928 }; 929 930 files_define_command: FSC_DEFINE FSE_FILE 931 { 932 if (($$ = alloc_cmd()) == NULL) 933 YYERROR; 934 $$->cmd = &parser_file_define; 935 }| FSC_DEFINE FSE_FILESET 936 { 937 if (($$ = alloc_cmd()) == NULL) 938 YYERROR; 939 $$->cmd = &parser_fileset_define; 940 } 941 | files_define_command files_attr_ops 942 { 943 $1->cmd_attr_list = $2; 944 }; 945 946 randvar_define_command: FSC_DEFINE FSE_RAND randvar_attr_ops 947 { 948 if (($$ = alloc_cmd()) == NULL) 949 YYERROR; 950 $$->cmd = &parser_randvar_define; 951 $$->cmd_attr_list = $3; 952 }; 953 954 create_command: FSC_CREATE entity 955 { 956 if (($$ = alloc_cmd()) == NULL) 957 YYERROR; 958 switch ($2) { 959 case FSE_PROC: 960 $$->cmd = &parser_proc_create; 961 break; 962 case FSE_FILESET: 963 case FSE_FILE: 964 $$->cmd = &parser_fileset_create; 965 break; 966 default: 967 filebench_log(LOG_ERROR, "unknown entity", $2); 968 YYERROR; 969 } 970 971 }; 972 973 shutdown_command: FSC_SHUTDOWN entity 974 { 975 if (($$ = alloc_cmd()) == NULL) 976 YYERROR; 977 switch ($2) { 978 case FSE_PROC: 979 $$->cmd = &parser_proc_shutdown; 980 break; 981 default: 982 filebench_log(LOG_ERROR, "unknown entity", $2); 983 YYERROR; 984 } 985 986 }; 987 988 sleep_command: FSC_SLEEP FSV_VAL_INT 989 { 990 if (($$ = alloc_cmd()) == NULL) 991 YYERROR; 992 $$->cmd = parser_sleep; 993 $$->cmd_qty = $2; 994 } 995 | FSC_SLEEP FSV_VARIABLE 996 { 997 fbint_t *integer; 998 999 if (($$ = alloc_cmd()) == NULL) 1000 YYERROR; 1001 $$->cmd = parser_sleep_variable; 1002 $$->cmd_tgt1 = fb_stralloc($2); 1003 }; 1004 1005 run_command: FSC_RUN FSV_VAL_INT 1006 { 1007 if (($$ = alloc_cmd()) == NULL) 1008 YYERROR; 1009 $$->cmd = parser_run; 1010 $$->cmd_qty = $2; 1011 } 1012 | FSC_RUN FSV_VARIABLE 1013 { 1014 fbint_t *integer; 1015 1016 if (($$ = alloc_cmd()) == NULL) 1017 YYERROR; 1018 $$->cmd = parser_run_variable; 1019 $$->cmd_tgt1 = fb_stralloc($2); 1020 } 1021 | FSC_RUN 1022 { 1023 fbint_t *integer; 1024 1025 if (($$ = alloc_cmd()) == NULL) 1026 YYERROR; 1027 $$->cmd = parser_run; 1028 $$->cmd_qty = 60UL; 1029 }; 1030 1031 help_command: FSC_HELP 1032 { 1033 if (($$ = alloc_cmd()) == NULL) 1034 YYERROR; 1035 $$->cmd = parser_help; 1036 }; 1037 1038 flowop_command: FSC_FLOWOP name 1039 { 1040 if (($$ = alloc_cmd()) == NULL) 1041 YYERROR; 1042 $$->cmd_name = fb_stralloc($2); 1043 } 1044 | flowop_command fo_attr_ops 1045 { 1046 $1->cmd_attr_list = $2; 1047 }; 1048 1049 load_command: FSC_LOAD FSV_STRING 1050 { 1051 FILE *newfile; 1052 char loadfile[128]; 1053 1054 if (($$ = alloc_cmd()) == NULL) 1055 YYERROR; 1056 1057 (void) strcpy(loadfile, $2); 1058 (void) strcat(loadfile, ".f"); 1059 1060 if ((newfile = fopen(loadfile, "r")) == NULL) { 1061 (void) strcpy(loadfile, FILEBENCHDIR); 1062 (void) strcat(loadfile, "/workloads/"); 1063 (void) strcat(loadfile, $2); 1064 (void) strcat(loadfile, ".f"); 1065 if ((newfile = fopen(loadfile, "r")) == NULL) { 1066 filebench_log(LOG_ERROR, "Cannot open %s", loadfile); 1067 YYERROR; 1068 } 1069 } 1070 1071 parentscript = yyin; 1072 yyin = newfile; 1073 yy_switchfileparent(yyin); 1074 }; 1075 1076 1077 entity: FSE_PROC {$$ = FSE_PROC;} 1078 | FSE_THREAD {$$ = FSE_THREAD;} 1079 | FSE_FILESET {$$ = FSE_FILESET;} 1080 | FSE_FILE {$$ = FSE_FILE;}; 1081 1082 value: FSV_VAL_INT { $$.i = $1;} 1083 | FSV_STRING { $$.s = $1;} 1084 | FSV_VAL_BOOLEAN { $$.b = $1;}; 1085 1086 name: FSV_STRING; 1087 1088 /* attribute parsing for define file and define fileset */ 1089 files_attr_ops: files_attr_op 1090 { 1091 $$ = $1; 1092 } 1093 | files_attr_ops FSK_SEPLST files_attr_op 1094 { 1095 attr_t *attr = NULL; 1096 attr_t *list_end = NULL; 1097 1098 for (attr = $1; attr != NULL; 1099 attr = attr->attr_next) 1100 list_end = attr; /* Find end of list */ 1101 1102 list_end->attr_next = $3; 1103 1104 $$ = $1; 1105 }; 1106 1107 files_attr_op: files_attr_name FSK_ASSIGN attr_list_value 1108 { 1109 $$ = $3; 1110 $$->attr_name = $1; 1111 } 1112 | files_attr_name 1113 { 1114 if (($$ = alloc_attr()) == NULL) 1115 YYERROR; 1116 $$->attr_name = $1; 1117 }; 1118 1119 /* attribute parsing for random variables */ 1120 randvar_attr_ops: randvar_attr_op 1121 { 1122 $$ = $1; 1123 } 1124 | randvar_attr_ops FSK_SEPLST randvar_attr_op 1125 { 1126 attr_t *attr = NULL; 1127 attr_t *list_end = NULL; 1128 1129 for (attr = $1; attr != NULL; 1130 attr = attr->attr_next) 1131 list_end = attr; /* Find end of list */ 1132 1133 list_end->attr_next = $3; 1134 1135 $$ = $1; 1136 } 1137 | randvar_attr_ops FSK_SEPLST FSA_RANDTABLE FSK_ASSIGN FSK_OPENLST probtabentry_list FSK_CLOSELST 1138 { 1139 attr_t *attr = NULL; 1140 attr_t *list_end = NULL; 1141 1142 for (attr = $1; attr != NULL; 1143 attr = attr->attr_next) 1144 list_end = attr; /* Find end of list */ 1145 1146 1147 if ((attr = alloc_attr()) == NULL) 1148 YYERROR; 1149 1150 attr->attr_name = FSA_RANDTABLE; 1151 attr->attr_obj = (void *)$6; 1152 list_end->attr_next = attr; 1153 $$ = $1; 1154 }; 1155 1156 randvar_attr_op: randvar_attr_name FSK_ASSIGN attr_list_value 1157 { 1158 $$ = $3; 1159 $$->attr_name = $1; 1160 } 1161 | randvar_attr_name 1162 { 1163 if (($$ = alloc_attr()) == NULL) 1164 YYERROR; 1165 $$->attr_name = $1; 1166 } 1167 | FSA_TYPE FSK_ASSIGN randvar_attr_typop 1168 { 1169 $$ = $3; 1170 $$->attr_name = FSA_TYPE; 1171 } 1172 | FSA_RANDSRC FSK_ASSIGN randvar_attr_srcop 1173 { 1174 $$ = $3; 1175 $$->attr_name = FSA_RANDSRC; 1176 }; 1177 1178 probtabentry: FSK_OPENLST var_int_val FSK_SEPLST var_int_val FSK_SEPLST var_int_val FSK_CLOSELST 1179 { 1180 if (($$ = alloc_probtabent()) == NULL) 1181 YYERROR; 1182 $$->pte_percent = $2; 1183 $$->pte_segmin = $4; 1184 $$->pte_segmax = $6; 1185 }; 1186 1187 /* attribute parsing for prob density function table */ 1188 probtabentry_list: probtabentry 1189 { 1190 $$ = $1; 1191 } 1192 | probtabentry_list FSK_SEPLST probtabentry 1193 { 1194 probtabent_t *pte = NULL; 1195 probtabent_t *ptelist_end = NULL; 1196 1197 for (pte = $1; pte != NULL; 1198 pte = pte->pte_next) 1199 ptelist_end = pte; /* Find end of prob table entry list */ 1200 1201 ptelist_end->pte_next = $3; 1202 1203 $$ = $1; 1204 }; 1205 1206 /* attribute parsing for define thread and process */ 1207 pt_attr_ops: pt_attr_op 1208 { 1209 $$ = $1; 1210 } 1211 | pt_attr_ops FSK_SEPLST pt_attr_op 1212 { 1213 attr_t *attr = NULL; 1214 attr_t *list_end = NULL; 1215 1216 for (attr = $1; attr != NULL; 1217 attr = attr->attr_next) 1218 list_end = attr; /* Find end of list */ 1219 1220 list_end->attr_next = $3; 1221 1222 $$ = $1; 1223 }; 1224 1225 pt_attr_op: pt_attr_name FSK_ASSIGN attr_value 1226 { 1227 $$ = $3; 1228 $$->attr_name = $1; 1229 } 1230 | pt_attr_name 1231 { 1232 if (($$ = alloc_attr()) == NULL) 1233 YYERROR; 1234 $$->attr_name = $1; 1235 }; 1236 1237 /* attribute parsing for flowops */ 1238 fo_attr_ops: fo_attr_op 1239 { 1240 $$ = $1; 1241 } 1242 | fo_attr_ops FSK_SEPLST fo_attr_op 1243 { 1244 attr_t *attr = NULL; 1245 attr_t *list_end = NULL; 1246 1247 for (attr = $1; attr != NULL; 1248 attr = attr->attr_next) 1249 list_end = attr; /* Find end of list */ 1250 1251 list_end->attr_next = $3; 1252 1253 $$ = $1; 1254 }; 1255 1256 fo_attr_op: fo_attr_name FSK_ASSIGN attr_value 1257 { 1258 $$ = $3; 1259 $$->attr_name = $1; 1260 } 1261 | fo_attr_name 1262 { 1263 if (($$ = alloc_attr()) == NULL) 1264 YYERROR; 1265 $$->attr_name = $1; 1266 }; 1267 1268 /* attribute parsing for Event Generator */ 1269 ev_attr_ops: ev_attr_op 1270 { 1271 $$ = $1; 1272 } 1273 | ev_attr_ops FSK_SEPLST ev_attr_op 1274 { 1275 attr_t *attr = NULL; 1276 attr_t *list_end = NULL; 1277 1278 for (attr = $1; attr != NULL; 1279 attr = attr->attr_next) 1280 list_end = attr; /* Find end of list */ 1281 1282 list_end->attr_next = $3; 1283 1284 $$ = $1; 1285 }; 1286 1287 ev_attr_op: ev_attr_name FSK_ASSIGN attr_value 1288 { 1289 $$ = $3; 1290 $$->attr_name = $1; 1291 } 1292 | ev_attr_name 1293 { 1294 if (($$ = alloc_attr()) == NULL) 1295 YYERROR; 1296 $$->attr_name = $1; 1297 }; 1298 1299 1300 files_attr_name: attrs_define_file 1301 |attrs_define_fileset; 1302 1303 pt_attr_name: attrs_define_thread 1304 |attrs_define_proc; 1305 1306 fo_attr_name: attrs_flowop; 1307 1308 ev_attr_name: attrs_eventgen; 1309 1310 attrs_define_proc: 1311 FSA_NICE { $$ = FSA_NICE;} 1312 | FSA_NAME { $$ = FSA_NAME;} 1313 | FSA_INSTANCES { $$ = FSA_INSTANCES;}; 1314 1315 attrs_define_file: 1316 FSA_SIZE { $$ = FSA_SIZE;} 1317 | FSA_NAME { $$ = FSA_NAME;} 1318 | FSA_PATH { $$ = FSA_PATH;} 1319 | FSA_REUSE { $$ = FSA_REUSE;} 1320 | FSA_PREALLOC { $$ = FSA_PREALLOC;} 1321 | FSA_PARALLOC { $$ = FSA_PARALLOC;}; 1322 1323 attrs_define_fileset: 1324 FSA_SIZE { $$ = FSA_SIZE;} 1325 | FSA_NAME { $$ = FSA_NAME;} 1326 | FSA_PATH { $$ = FSA_PATH;} 1327 | FSA_DIRWIDTH { $$ = FSA_DIRWIDTH;} 1328 | FSA_DIRDEPTHRV { $$ = FSA_DIRDEPTHRV;} 1329 | FSA_PREALLOC { $$ = FSA_PREALLOC;} 1330 | FSA_FILESIZEGAMMA { $$ = FSA_FILESIZEGAMMA;} 1331 | FSA_DIRGAMMA { $$ = FSA_DIRGAMMA;} 1332 | FSA_CACHED { $$ = FSA_CACHED;} 1333 | FSA_ENTRIES { $$ = FSA_ENTRIES;}; 1334 1335 randvar_attr_name: 1336 FSA_NAME { $$ = FSA_NAME;} 1337 | FSA_RANDSEED { $$ = FSA_RANDSEED;} 1338 | FSA_RANDGAMMA { $$ = FSA_RANDGAMMA;} 1339 | FSA_RANDMEAN { $$ = FSA_RANDMEAN;} 1340 | FSA_RANDMIN { $$ = FSA_RANDMIN;} 1341 | FSA_RANDROUND { $$ = FSA_RANDROUND;}; 1342 1343 randvar_attr_tsp: 1344 FSS_TYPE { $$ = FSS_TYPE;} 1345 | FSS_SRC { $$ = FSS_SRC;} 1346 | FSS_SEED { $$ = FSS_SEED;} 1347 | FSS_GAMMA { $$ = FSS_GAMMA;} 1348 | FSS_MEAN { $$ = FSS_MEAN;} 1349 | FSS_MIN { $$ = FSS_MIN;} 1350 | FSS_ROUND { $$ = FSS_ROUND;}; 1351 1352 1353 randvar_attr_param: 1354 FSS_SEED { $$ = FSS_SEED;} 1355 | FSS_GAMMA { $$ = FSS_GAMMA;} 1356 | FSS_MEAN { $$ = FSS_MEAN;} 1357 | FSS_MIN { $$ = FSS_MIN;} 1358 | FSS_ROUND { $$ = FSS_ROUND;}; 1359 1360 randvar_attr_typop: randtype_name 1361 { 1362 if (($$ = alloc_attr()) == NULL) 1363 YYERROR; 1364 $$->attr_avd = avd_int_alloc($1); 1365 }; 1366 1367 randtype_name: 1368 FSV_RANDUNI { $$ = FSV_RANDUNI;} 1369 | FSV_RANDTAB { $$ = FSV_RANDTAB;} 1370 | FSA_RANDGAMMA { $$ = FSA_RANDGAMMA;}; 1371 1372 randvar_attr_srcop: randsrc_name 1373 { 1374 if (($$ = alloc_attr()) == NULL) 1375 YYERROR; 1376 $$->attr_avd = avd_int_alloc($1); 1377 }; 1378 1379 randsrc_name: 1380 FSV_URAND { $$ = FSV_URAND;} 1381 | FSV_RAND48 { $$ = FSV_RAND48;}; 1382 1383 attrs_define_thread: 1384 FSA_PROCESS { $$ = FSA_PROCESS;} 1385 | FSA_NAME { $$ = FSA_NAME;} 1386 | FSA_MEMSIZE { $$ = FSA_MEMSIZE;} 1387 | FSA_USEISM { $$ = FSA_USEISM;} 1388 | FSA_INSTANCES { $$ = FSA_INSTANCES;}; 1389 1390 attrs_flowop: 1391 FSA_WSS { $$ = FSA_WSS;} 1392 | FSA_FILE { $$ = FSA_FILE;} 1393 | FSA_NAME { $$ = FSA_NAME;} 1394 | FSA_RANDOM { $$ = FSA_RANDOM;} 1395 | FSA_FD { $$ = FSA_FD;} 1396 | FSA_SRCFD { $$ = FSA_SRCFD;} 1397 | FSA_ROTATEFD { $$ = FSA_ROTATEFD;} 1398 | FSA_DSYNC { $$ = FSA_DSYNC;} 1399 | FSA_DIRECTIO { $$ = FSA_DIRECTIO;} 1400 | FSA_TARGET { $$ = FSA_TARGET;} 1401 | FSA_ITERS { $$ = FSA_ITERS;} 1402 | FSA_VALUE { $$ = FSA_VALUE;} 1403 | FSA_BLOCKING { $$ = FSA_BLOCKING;} 1404 | FSA_HIGHWATER { $$ = FSA_HIGHWATER;} 1405 | FSA_IOSIZE { $$ = FSA_IOSIZE;}; 1406 1407 attrs_eventgen: 1408 FSA_RATE { $$ = FSA_RATE;}; 1409 1410 attr_value: FSV_STRING 1411 { 1412 if (($$ = alloc_attr()) == NULL) 1413 YYERROR; 1414 $$->attr_avd = avd_str_alloc($1); 1415 } | FSV_VAL_INT { 1416 if (($$ = alloc_attr()) == NULL) 1417 YYERROR; 1418 $$->attr_avd = avd_int_alloc($1); 1419 } | FSV_VAL_BOOLEAN { 1420 if (($$ = alloc_attr()) == NULL) 1421 YYERROR; 1422 $$->attr_avd = avd_bool_alloc($1); 1423 } | FSV_VARIABLE { 1424 if (($$ = alloc_attr()) == NULL) 1425 YYERROR; 1426 $$->attr_avd = var_ref_attr($1); 1427 }; 1428 1429 attr_list_value: var_string_list { 1430 if (($$ = alloc_attr()) == NULL) 1431 YYERROR; 1432 $$->attr_param_list = $1; 1433 } | FSV_STRING 1434 { 1435 if (($$ = alloc_attr()) == NULL) 1436 YYERROR; 1437 $$->attr_avd = avd_str_alloc($1); 1438 } | FSV_VAL_INT { 1439 if (($$ = alloc_attr()) == NULL) 1440 YYERROR; 1441 $$->attr_avd = avd_int_alloc($1); 1442 } | FSV_VAL_BOOLEAN { 1443 if (($$ = alloc_attr()) == NULL) 1444 YYERROR; 1445 $$->attr_avd = avd_bool_alloc($1); 1446 } | FSV_VARIABLE { 1447 if (($$ = alloc_attr()) == NULL) 1448 YYERROR; 1449 $$->attr_avd = var_ref_attr($1); 1450 }; 1451 1452 var_int_val: FSV_VAL_INT 1453 { 1454 $$ = avd_int_alloc($1); 1455 } | FSV_VARIABLE 1456 { 1457 $$ = var_ref_attr($1); 1458 }; 1459 1460 %% 1461 1462 /* 1463 * The following 'c' routines implement the various commands defined in the 1464 * above yacc parser code. The yacc portion checks the syntax of the commands 1465 * found in a workload file, or typed on interactive command lines, parsing 1466 * the commands' parameters into lists. The lists are then passed in a cmd_t 1467 * struct for each command to its related routine in the following section 1468 * for actual execution. This section also includes a few utility routines 1469 * and the main entry point for the program. 1470 */ 1471 1472 /* 1473 * Entry point for filebench. Processes command line arguements. The -f 1474 * option will read in a workload file (the full name and extension must 1475 * must be given). The -a, -s, -m and -i options are used by worker process 1476 * to receive their name, the base address of shared memory, its path, and 1477 * the process' instance number, respectively. This information is supplied 1478 * by the master process when it execs worker processes under the process 1479 * model of execution. If the worker process arguments are passed then main 1480 * will call the procflow_exec routine which creates worker threadflows and 1481 * flowops and executes the procflow's portion of the workload model until 1482 * completion. If worker process arguments are not passed to the process, 1483 * then it becomes the master process for a filebench run. It initializes 1484 * the various filebench components and either executes the supplied workload 1485 * file, or enters interactive mode. 1486 */ 1487 1488 int 1489 main(int argc, char *argv[]) 1490 { 1491 int opt; 1492 int docmd = FS_FALSE; 1493 int instance; 1494 char procname[128]; 1495 caddr_t shmaddr; 1496 char dir[MAXPATHLEN]; 1497 #ifdef HAVE_SETRLIMIT 1498 struct rlimit rlp; 1499 #endif 1500 #ifdef HAVE_LIBTECLA 1501 char *line; 1502 #else 1503 char line[1024]; 1504 #endif 1505 char shmpathtmp[1024]; 1506 1507 #ifdef HAVE_SETRLIMIT 1508 /* Set resource limits */ 1509 (void) getrlimit(RLIMIT_NOFILE, &rlp); 1510 rlp.rlim_cur = rlp.rlim_max; 1511 setrlimit(RLIMIT_NOFILE, &rlp); 1512 #endif 1513 1514 yydebug = 0; 1515 execname = argv[0]; 1516 *procname = 0; 1517 cwd = getcwd(dir, MAXPATHLEN); 1518 1519 while ((opt = getopt(argc, argv, cmd_options)) != (int)EOF) { 1520 1521 switch (opt) { 1522 case 'h': 1523 usage(2); 1524 break; 1525 1526 case 'p': 1527 noproc = 1; 1528 break; 1529 1530 case 'f': 1531 if (optarg == NULL) 1532 usage(1); 1533 if ((yyin = fopen(optarg, "r")) == NULL) { 1534 (void) fprintf(stderr, 1535 "Cannot open file %s", optarg); 1536 exit(1); 1537 } 1538 dofile = FS_TRUE; 1539 fscriptname = optarg; 1540 1541 break; 1542 1543 case 'a': 1544 if (optarg == NULL) 1545 usage(1); 1546 sscanf(optarg, "%s", &procname[0]); 1547 break; 1548 1549 case 's': 1550 if (optarg == NULL) 1551 usage(1); 1552 #if defined(_LP64) || (__WORDSIZE == 64) 1553 sscanf(optarg, "%llx", &shmaddr); 1554 #else 1555 sscanf(optarg, "%x", &shmaddr); 1556 #endif 1557 break; 1558 1559 case 'm': 1560 if (optarg == NULL) 1561 usage(1); 1562 sscanf(optarg, "%s", shmpathtmp); 1563 shmpath = shmpathtmp; 1564 break; 1565 1566 case 'i': 1567 if (optarg == NULL) 1568 usage(1); 1569 sscanf(optarg, "%d", &instance); 1570 break; 1571 1572 case '?': 1573 default: 1574 usage(1); 1575 break; 1576 } 1577 } 1578 1579 #ifdef USE_PROCESS_MODEL 1580 if (!(*procname)) 1581 #endif 1582 printf("FileBench Version %s\n", FILEBENCH_VERSION); 1583 filebench_init(); 1584 1585 /* get process pid for use with message logging */ 1586 my_pid = getpid(); 1587 1588 #ifdef USE_PROCESS_MODEL 1589 if (*procname) { 1590 /* A child FileBench instance */ 1591 if (ipc_attach(shmaddr) < 0) { 1592 filebench_log(LOG_ERROR, "Cannot attach shm for %s", 1593 procname); 1594 exit(1); 1595 } 1596 1597 if (procflow_exec(procname, instance) < 0) { 1598 filebench_log(LOG_ERROR, "Cannot startup process %s", 1599 procname); 1600 exit(1); 1601 } 1602 1603 exit(0); 1604 } 1605 #endif 1606 1607 /* master (or only) process */ 1608 ipc_init(); 1609 1610 if (fscriptname) 1611 (void) strcpy(filebench_shm->fscriptname, fscriptname); 1612 1613 flowop_init(); 1614 stats_init(); 1615 eventgen_init(); 1616 1617 signal(SIGINT, parser_abort); 1618 1619 if (dofile) 1620 yyparse(); 1621 else { 1622 #ifdef HAVE_LIBTECLA 1623 if ((gl = new_GetLine(MAX_LINE_LEN, MAX_CMD_HIST)) == NULL) { 1624 filebench_log(LOG_ERROR, 1625 "Failed to create GetLine object"); 1626 filebench_shutdown(1); 1627 } 1628 1629 if (gl_customize_completion(gl, NULL, command_complete)) { 1630 filebench_log(LOG_ERROR, 1631 "Failed to register auto-completion function"); 1632 filebench_shutdown(1); 1633 } 1634 1635 while (line = gl_get_line(gl, FILEBENCH_PROMPT, NULL, -1)) { 1636 arg_parse(line); 1637 yyparse(); 1638 } 1639 1640 del_GetLine(gl); 1641 #else 1642 while (!feof(stdin)) { 1643 printf(FILEBENCH_PROMPT); 1644 fflush(stdout); 1645 if (fgets(line, sizeof (line), stdin) == NULL) { 1646 if (errno == EINTR) 1647 continue; 1648 else 1649 break; 1650 } 1651 arg_parse(line); 1652 yyparse(); 1653 } 1654 printf("\n"); 1655 #endif /* HAVE_LIBTECLA */ 1656 } 1657 1658 parser_filebench_shutdown((cmd_t *)0); 1659 1660 return (0); 1661 } 1662 1663 /* 1664 * arg_parse() puts the parser into command parsing mode. Create a tmpfile 1665 * and instruct the parser to read instructions from this location by setting 1666 * yyin to the value returned by tmpfile. Write the command into the file. 1667 * Then seek back to to the start of the file so that the parser can read 1668 * the instructions. 1669 */ 1670 static void 1671 arg_parse(const char *command) 1672 { 1673 if ((yyin = tmpfile()) == NULL) 1674 filebench_log(LOG_FATAL, 1675 "Cannot create tmpfile: %s", strerror(errno)); 1676 1677 if (fwrite(command, strlen(command), 1, yyin) != 1) 1678 filebench_log(LOG_FATAL, 1679 "Cannot write tmpfile: %s", strerror(errno)); 1680 1681 if (fseek(yyin, 0, SEEK_SET) != 0) 1682 filebench_log(LOG_FATAL, 1683 "Cannot seek tmpfile: %s", strerror(errno)); 1684 } 1685 1686 /* 1687 * Converts a list of var_strings or ordinary strings to a single ordinary 1688 * string. It returns a pointer to the string (in malloc'd memory) if found, 1689 * or NULL otherwise. 1690 */ 1691 char * 1692 parser_list2string(list_t *list) 1693 { 1694 list_t *l; 1695 char *string; 1696 char *tmp; 1697 fbint_t *integer; 1698 if ((string = malloc(MAXPATHLEN)) == NULL) { 1699 filebench_log(LOG_ERROR, "Failed to allocate memory"); 1700 return (NULL); 1701 } 1702 1703 *string = 0; 1704 1705 1706 /* Format args */ 1707 for (l = list; l != NULL; l = l->list_next) { 1708 char *lstr = avd_get_str(l->list_string); 1709 1710 filebench_log(LOG_DEBUG_SCRIPT, 1711 "converting string '%s'", lstr); 1712 1713 /* see if it is a random variable */ 1714 if (l->list_integer) { 1715 fbint_t param_name; 1716 1717 tmp = NULL; 1718 param_name = avd_get_int(l->list_integer); 1719 switch (param_name) { 1720 case FSS_TYPE: 1721 tmp = var_randvar_to_string(lstr, 1722 RAND_PARAM_TYPE); 1723 break; 1724 1725 case FSS_SRC: 1726 tmp = var_randvar_to_string(lstr, 1727 RAND_PARAM_SRC); 1728 break; 1729 1730 case FSS_SEED: 1731 tmp = var_randvar_to_string(lstr, 1732 RAND_PARAM_SEED); 1733 break; 1734 1735 case FSS_MIN: 1736 tmp = var_randvar_to_string(lstr, 1737 RAND_PARAM_MIN); 1738 break; 1739 1740 case FSS_MEAN: 1741 tmp = var_randvar_to_string(lstr, 1742 RAND_PARAM_MEAN); 1743 break; 1744 1745 case FSS_GAMMA: 1746 tmp = var_randvar_to_string(lstr, 1747 RAND_PARAM_GAMMA); 1748 break; 1749 1750 case FSS_ROUND: 1751 tmp = var_randvar_to_string(lstr, 1752 RAND_PARAM_ROUND); 1753 break; 1754 } 1755 1756 if (tmp) { 1757 (void) strcat(string, tmp); 1758 free(tmp); 1759 } else { 1760 (void) strcat(string, lstr); 1761 } 1762 } else { 1763 /* perhaps a normal variable? */ 1764 if ((tmp = var_to_string(lstr)) != NULL) { 1765 (void) strcat(string, tmp); 1766 free(tmp); 1767 } else { 1768 (void) strcat(string, lstr); 1769 } 1770 } 1771 } 1772 return (string); 1773 } 1774 1775 /* 1776 * If the list just contains a single string starting with '$', then find 1777 * or create the named var and return the var's var_string component. 1778 * Otherwise, convert the list to a string, and allocate a var_string 1779 * containing a copy of that string. On failure either returns NULL 1780 * or shuts down the run. 1781 */ 1782 avd_t 1783 parser_list2varstring(list_t *list) 1784 { 1785 char *lstr = avd_get_str(list->list_string); 1786 1787 /* Special case - variable name */ 1788 if ((list->list_next == NULL) && (*lstr == '$')) 1789 return (var_ref_attr(lstr)); 1790 1791 return (avd_str_alloc(parser_list2string(list))); 1792 } 1793 1794 /* 1795 * Looks for the var named in list_string of the first element of the 1796 * supplied list. If found, returns the var_val portion of the var in 1797 * an attribute value descriptor. If the var is not found, cannot be 1798 * allocated, the supplied list is NULL, or the list_string filed is 1799 * empty, returns NULL. 1800 */ 1801 avd_t 1802 parser_list2avd(list_t *list) 1803 { 1804 avd_t avd; 1805 char *lstr; 1806 1807 if (list && ((lstr = avd_get_str(list->list_string)) != NULL)) { 1808 avd = var_ref_attr(lstr); 1809 return (avd); 1810 } 1811 1812 return (NULL); 1813 } 1814 1815 /* 1816 * Sets the event generator rate from the attribute supplied with the 1817 * command. If the attribute doesn't exist the routine does nothing. 1818 */ 1819 static void 1820 parser_eventgen(cmd_t *cmd) 1821 { 1822 attr_t *attr; 1823 fbint_t rate; 1824 1825 /* Get the rate from attribute */ 1826 if (attr = get_attr_integer(cmd, FSA_RATE)) { 1827 if (attr->attr_avd) { 1828 rate = avd_get_int(attr->attr_avd); 1829 filebench_log(LOG_VERBOSE, 1830 "Eventgen: %llu per second", 1831 (u_longlong_t)rate); 1832 eventgen_setrate(rate); 1833 } 1834 } 1835 } 1836 1837 /* 1838 * Assigns the designated integer variable successive values from the 1839 * supplied comma seperated integer list. After each successive integer 1840 * assignment, it executes the bracket enclosed list of commands. For 1841 * example, repeated runs of a workload with increasing io sizes can 1842 * be done using the following command line: 1843 * foreach $iosize in 2k, 4k, 8k {run 60} 1844 */ 1845 static void 1846 parser_foreach_integer(cmd_t *cmd) 1847 { 1848 list_t *list = cmd->cmd_param_list; 1849 cmd_t *inner_cmd; 1850 1851 for (; list != NULL; list = list->list_next) { 1852 fbint_t list_int = avd_get_int(list->list_integer); 1853 1854 var_assign_integer(cmd->cmd_tgt1, list_int); 1855 filebench_log(LOG_VERBOSE, "Iterating %s=%llu", 1856 cmd->cmd_tgt1, (u_longlong_t)list_int); 1857 for (inner_cmd = cmd->cmd_list; inner_cmd != NULL; 1858 inner_cmd = inner_cmd->cmd_next) { 1859 inner_cmd->cmd(inner_cmd); 1860 } 1861 } 1862 } 1863 1864 /* 1865 * Similar to parser_foreach_integer(), except takes a list of strings after 1866 * the "in" token. For example, to run twice using a different directory, 1867 * perhaps using a different filesystem, the following command line 1868 * could be used: 1869 * foreach $dir in "/ufs_top/fbt", "/zfs_top/fbt" {run 60) 1870 */ 1871 static void 1872 parser_foreach_string(cmd_t *cmd) 1873 { 1874 list_t *list = cmd->cmd_param_list; 1875 1876 for (; list != NULL; list = list->list_next) { 1877 cmd_t *inner_cmd; 1878 char *lstr = avd_get_str(list->list_string); 1879 var_assign_string(cmd->cmd_tgt1, lstr); 1880 filebench_log(LOG_VERBOSE, "Iterating %s=%s", 1881 cmd->cmd_tgt1, lstr); 1882 for (inner_cmd = cmd->cmd_list; inner_cmd != NULL; 1883 inner_cmd = inner_cmd->cmd_next) { 1884 inner_cmd->cmd(inner_cmd); 1885 } 1886 } 1887 } 1888 1889 /* 1890 * Lists the fileset name, path name and average size for all defined 1891 * filesets. 1892 */ 1893 static void 1894 parser_list(cmd_t *cmd) 1895 { 1896 (void) fileset_iter(fileset_print); 1897 } 1898 1899 /* 1900 * Lists the flowop name and instance number for all flowops. 1901 */ 1902 static void 1903 parser_flowop_list(cmd_t *cmd) 1904 { 1905 flowop_printall(); 1906 } 1907 1908 /* 1909 * Calls procflow_define() to allocate "instances" number of procflow(s) 1910 * (processes) with the supplied name. The default number of instances is 1911 * one. An optional priority level attribute can be supplied and is stored in 1912 * pf_nice. Finally the routine loops through the list of inner commands, if 1913 * any, which are defines for threadflows, and passes them one at a time to 1914 * parser_thread_define() to allocate threadflow entities for the process(es). 1915 */ 1916 static void 1917 parser_proc_define(cmd_t *cmd) 1918 { 1919 procflow_t *procflow, template; 1920 char *name; 1921 attr_t *attr; 1922 avd_t var_instances; 1923 fbint_t instances; 1924 cmd_t *inner_cmd; 1925 1926 /* Get the name of the process */ 1927 if (attr = get_attr(cmd, FSA_NAME)) { 1928 name = avd_get_str(attr->attr_avd); 1929 } else { 1930 filebench_log(LOG_ERROR, 1931 "define proc: proc specifies no name"); 1932 filebench_shutdown(1); 1933 } 1934 1935 /* Get the memory size from attribute */ 1936 if (attr = get_attr_integer(cmd, FSA_INSTANCES)) { 1937 if (AVD_IS_RANDOM(attr->attr_avd)) { 1938 filebench_log(LOG_ERROR, 1939 "proc_define: Instances attr cannot be random"); 1940 filebench_shutdown(1); 1941 } 1942 var_instances = attr->attr_avd; 1943 instances = avd_get_int(var_instances); 1944 filebench_log(LOG_DEBUG_IMPL, 1945 "Setting instances = %llu", (u_longlong_t)instances); 1946 } else { 1947 filebench_log(LOG_DEBUG_IMPL, 1948 "Defaulting to instances = 1"); 1949 var_instances = avd_int_alloc(1); 1950 instances = 1; 1951 } 1952 1953 if ((procflow = procflow_define(name, NULL, var_instances)) == NULL) { 1954 filebench_log(LOG_ERROR, 1955 "Failed to instantiate %d %s process(es)\n", 1956 instances, name); 1957 filebench_shutdown(1); 1958 } 1959 1960 /* Get the pri from attribute */ 1961 if (attr = get_attr_integer(cmd, FSA_NICE)) { 1962 if (AVD_IS_RANDOM(attr->attr_avd)) { 1963 filebench_log(LOG_ERROR, 1964 "proc_define: priority cannot be random"); 1965 filebench_shutdown(1); 1966 } 1967 filebench_log(LOG_DEBUG_IMPL, "Setting pri = %llu", 1968 (u_longlong_t)avd_get_int(attr->attr_avd)); 1969 procflow->pf_nice = attr->attr_avd; 1970 } else 1971 procflow->pf_nice = avd_int_alloc(0); 1972 1973 1974 /* Create the list of threads for this process */ 1975 for (inner_cmd = cmd->cmd_list; inner_cmd != NULL; 1976 inner_cmd = inner_cmd->cmd_next) { 1977 parser_thread_define(inner_cmd, procflow, instances); 1978 } 1979 } 1980 1981 /* 1982 * Calls threadflow_define() to allocate "instances" number of threadflow(s) 1983 * (threads) with the supplied name. The default number of instances is 1984 * one. Two other optional attributes may be supplied, one to set the memory 1985 * size, stored in tf_memsize, and to select the use of Interprocess Shared 1986 * Memory, which sets the THREADFLOW_USEISM flag in tf_attrs. Finally 1987 * the routine loops through the list of inner commands, if any, which are 1988 * defines for flowops, and passes them one at a time to 1989 * parser_flowop_define() to allocate flowop entities for the threadflows. 1990 */ 1991 static void 1992 parser_thread_define(cmd_t *cmd, procflow_t *procflow, int procinstances) 1993 { 1994 threadflow_t *threadflow, template; 1995 attr_t *attr; 1996 avd_t instances; 1997 cmd_t *inner_cmd; 1998 char *name; 1999 2000 memset(&template, 0, sizeof (threadflow_t)); 2001 2002 /* Get the name of the thread */ 2003 if (attr = get_attr(cmd, FSA_NAME)) { 2004 name = avd_get_str(attr->attr_avd); 2005 } else { 2006 filebench_log(LOG_ERROR, 2007 "define thread: thread in process %s specifies no name", 2008 procflow->pf_name); 2009 filebench_shutdown(1); 2010 } 2011 2012 /* Get the number of instances from attribute */ 2013 if (attr = get_attr_integer(cmd, FSA_INSTANCES)) { 2014 if (AVD_IS_RANDOM(attr->attr_avd)) { 2015 filebench_log(LOG_ERROR, 2016 "define thread: Instances attr cannot be random"); 2017 filebench_shutdown(1); 2018 } 2019 filebench_log(LOG_DEBUG_IMPL, 2020 "define thread: Setting instances = %llu", 2021 (u_longlong_t)avd_get_int(attr->attr_avd)); 2022 instances = attr->attr_avd; 2023 } else 2024 instances = avd_int_alloc(1); 2025 2026 /* Get the memory size from attribute */ 2027 if (attr = get_attr_integer(cmd, FSA_MEMSIZE)) { 2028 if (AVD_IS_RANDOM(attr->attr_avd)) { 2029 filebench_log(LOG_ERROR, 2030 "define thread: Memory size cannot be random"); 2031 filebench_shutdown(1); 2032 } 2033 filebench_log(LOG_DEBUG_IMPL, 2034 "define thread: Setting memsize = %llu", 2035 (u_longlong_t)avd_get_int(attr->attr_avd)); 2036 template.tf_memsize = attr->attr_avd; 2037 } else 2038 template.tf_memsize = avd_int_alloc(0); 2039 2040 if ((threadflow = threadflow_define(procflow, name, 2041 &template, instances)) == NULL) { 2042 filebench_log(LOG_ERROR, 2043 "define thread: Failed to instantiate thread\n"); 2044 filebench_shutdown(1); 2045 } 2046 2047 /* Use ISM Memory? */ 2048 if (attr = get_attr(cmd, FSA_USEISM)) { 2049 threadflow->tf_attrs |= THREADFLOW_USEISM; 2050 } 2051 2052 /* Create the list of flowops */ 2053 for (inner_cmd = cmd->cmd_list; inner_cmd != NULL; 2054 inner_cmd = inner_cmd->cmd_next) { 2055 parser_flowop_define(inner_cmd, threadflow, 2056 &threadflow->tf_ops, FLOW_MASTER); 2057 } 2058 } 2059 2060 /* 2061 * Files in the attributes for a newly allocated flowop 2062 */ 2063 static void 2064 parser_flowop_get_attrs(cmd_t *cmd, flowop_t *flowop) 2065 { 2066 attr_t *attr; 2067 2068 /* Get the filename from attribute */ 2069 if (attr = get_attr(cmd, FSA_FILE)) { 2070 flowop->fo_filename = attr->attr_avd; 2071 if (flowop->fo_filename == NULL) { 2072 filebench_log(LOG_ERROR, 2073 "define flowop: no filename specfied"); 2074 filebench_shutdown(1); 2075 } 2076 2077 if ((flowop->fo_filename->avd_type == AVD_VAL_STR) || 2078 (flowop->fo_filename->avd_type == AVD_VARVAL_STR)) { 2079 char *name; 2080 2081 name = avd_get_str(flowop->fo_filename); 2082 flowop->fo_fileset = fileset_find(name); 2083 2084 if (flowop->fo_fileset == NULL) { 2085 filebench_log(LOG_ERROR, 2086 "flowop %s: file %s not found", 2087 flowop->fo_name, name); 2088 filebench_shutdown(1); 2089 } 2090 } 2091 } 2092 2093 /* Get the iosize of the op */ 2094 if (attr = get_attr_integer(cmd, FSA_IOSIZE)) 2095 flowop->fo_iosize = attr->attr_avd; 2096 else 2097 flowop->fo_iosize = avd_int_alloc(0); 2098 2099 /* Get the working set size of the op */ 2100 if (attr = get_attr_integer(cmd, FSA_WSS)) 2101 flowop->fo_wss = attr->attr_avd; 2102 else 2103 flowop->fo_wss = avd_int_alloc(0); 2104 2105 /* Random I/O? */ 2106 if (attr = get_attr_bool(cmd, FSA_RANDOM)) 2107 flowop->fo_random = attr->attr_avd; 2108 else 2109 flowop->fo_random = avd_bool_alloc(FALSE); 2110 2111 /* Sync I/O? */ 2112 if (attr = get_attr_bool(cmd, FSA_DSYNC)) 2113 flowop->fo_dsync = attr->attr_avd; 2114 else 2115 flowop->fo_dsync = avd_bool_alloc(FALSE); 2116 2117 /* Target, for wakeup etc */ 2118 if (attr = get_attr(cmd, FSA_TARGET)) 2119 (void) strcpy(flowop->fo_targetname, 2120 avd_get_str(attr->attr_avd)); 2121 2122 /* Value */ 2123 if (attr = get_attr_integer(cmd, FSA_VALUE)) 2124 flowop->fo_value = attr->attr_avd; 2125 else 2126 flowop->fo_value = avd_int_alloc(0); 2127 2128 /* FD */ 2129 if (attr = get_attr_integer(cmd, FSA_FD)) 2130 flowop->fo_fdnumber = avd_get_int(attr->attr_avd); 2131 2132 /* Rotatefd? */ 2133 if (attr = get_attr_bool(cmd, FSA_ROTATEFD)) 2134 flowop->fo_rotatefd = attr->attr_avd; 2135 else 2136 flowop->fo_rotatefd = avd_bool_alloc(FALSE); 2137 2138 /* SRC FD, for copies etc... */ 2139 if (attr = get_attr_integer(cmd, FSA_SRCFD)) 2140 flowop->fo_srcfdnumber = avd_get_int(attr->attr_avd); 2141 2142 /* Blocking operation? */ 2143 if (attr = get_attr_bool(cmd, FSA_BLOCKING)) 2144 flowop->fo_blocking = attr->attr_avd; 2145 else 2146 flowop->fo_blocking = avd_bool_alloc(FALSE); 2147 2148 /* Direct I/O Operation */ 2149 if (attr = get_attr_bool(cmd, FSA_DIRECTIO)) 2150 flowop->fo_directio = attr->attr_avd; 2151 else 2152 flowop->fo_directio = avd_bool_alloc(FALSE); 2153 2154 /* Highwater mark */ 2155 if (attr = get_attr_integer(cmd, FSA_HIGHWATER)) { 2156 flowop->fo_highwater = attr->attr_avd; 2157 if (AVD_IS_RANDOM(attr->attr_avd)) { 2158 filebench_log(LOG_ERROR, 2159 "define flowop: Highwater attr cannot be random"); 2160 filebench_shutdown(1); 2161 } 2162 } else { 2163 flowop->fo_highwater = avd_int_alloc(1); 2164 } 2165 } 2166 2167 2168 /* 2169 * Calls flowop_define() to allocate a flowop with the supplied name. 2170 * The allocated flowop inherits attributes from a base flowop of the 2171 * same type. If the new flowop has a file or fileset attribute specified, 2172 * it must specify a defined fileobj or fileset or an error will be logged. 2173 * The new flowop may also have the following attributes set by 2174 * the program: 2175 * - file size (fo_iosize) 2176 * - working set size (fo_wss) 2177 * - do random io (fo_random) 2178 * - do synchronous io (fo_dsync) 2179 * - perform each operation multiple times before advancing (fo_iter) 2180 * - target name (fo_targetname) 2181 * - An integer value (fo_value) 2182 * - a file descriptor (fo_fd) 2183 * - specify to rotate file descriptors (fo_rotatefd) 2184 * - a source fd (fo_srcfdnumber) 2185 * - specify a blocking operation (fo_blocking) 2186 * - specify a highwater mark (fo_highwater) 2187 * 2188 * After all the supplied attributes are stored in their respective locations 2189 * in the flowop object, the flowop's init function is called. No errors are 2190 * returned, but the filebench run will be terminated if the flowtype is not 2191 * specified, a name for the new flowop is not supplied, the flowop_define 2192 * call fails, or a file or fileset name is supplied but the corresponding 2193 * fileobj or fileset cannot be located. 2194 */ 2195 static void 2196 parser_flowop_define(cmd_t *cmd, threadflow_t *thread, 2197 flowop_t **flowoplist_hdp, int category) 2198 { 2199 flowop_t *flowop, *flowop_type; 2200 char *type = (char *)cmd->cmd_name; 2201 char *name; 2202 attr_t *attr; 2203 2204 /* Get the inherited flowop */ 2205 flowop_type = flowop_find(type); 2206 if (flowop_type == NULL) { 2207 filebench_log(LOG_ERROR, 2208 "define flowop: flowop type %s not found", 2209 type); 2210 filebench_shutdown(1); 2211 } 2212 2213 /* Get the name of the flowop */ 2214 if (attr = get_attr(cmd, FSA_NAME)) { 2215 name = avd_get_str(attr->attr_avd); 2216 } else { 2217 filebench_log(LOG_ERROR, 2218 "define flowop: flowop %s specifies no name", 2219 flowop_type->fo_name); 2220 filebench_shutdown(1); 2221 } 2222 2223 if ((flowop = flowop_define(thread, name, 2224 flowop_type, category, 0)) == NULL) { 2225 filebench_log(LOG_ERROR, 2226 "define flowop: Failed to instantiate flowop %s\n", 2227 cmd->cmd_name); 2228 filebench_shutdown(1); 2229 } 2230 2231 /* Iterations */ 2232 if (attr = get_attr_integer(cmd, FSA_ITERS)) 2233 flowop->fo_iters = attr->attr_avd; 2234 else 2235 flowop->fo_iters = avd_int_alloc(1); 2236 2237 parser_flowop_get_attrs(cmd, flowop); 2238 } 2239 2240 /* 2241 * Calls fileset_define() to allocate a fileset with the supplied name and 2242 * initializes the fileset's pathname attribute, and optionally the 2243 * fileset_cached, fileset_reuse, fileset_prealloc and fileset_size attributes. 2244 * 2245 */ 2246 static fileset_t * 2247 parser_fileset_define_common(cmd_t *cmd) 2248 { 2249 fileset_t *fileset; 2250 avd_t name; 2251 attr_t *attr; 2252 avd_t pathname; 2253 2254 /* Get the name of the file */ 2255 if (attr = get_attr(cmd, FSA_NAME)) { 2256 name = attr->attr_avd; 2257 } else { 2258 filebench_log(LOG_ERROR, 2259 "define fileset: file or fileset specifies no name"); 2260 return (NULL); 2261 } 2262 2263 if ((fileset = fileset_define(name)) == NULL) { 2264 filebench_log(LOG_ERROR, 2265 "define file: failed to instantiate file %s\n", 2266 avd_get_str(name)); 2267 return (NULL); 2268 } 2269 2270 /* Get the pathname from attribute */ 2271 if ((attr = get_attr(cmd, FSA_PATH)) == NULL) { 2272 filebench_log(LOG_ERROR, "define file: no pathname specified"); 2273 return (NULL); 2274 } 2275 2276 /* Expand variables in pathname */ 2277 if ((pathname = parser_list2varstring(attr->attr_param_list)) 2278 == NULL) { 2279 filebench_log(LOG_ERROR, "Cannot interpret path"); 2280 return (NULL); 2281 } 2282 2283 fileset->fs_path = pathname; 2284 2285 /* Should we prealloc in parallel? */ 2286 if (attr = get_attr_bool(cmd, FSA_PARALLOC)) 2287 fileset->fs_paralloc = attr->attr_avd; 2288 else 2289 fileset->fs_paralloc = avd_bool_alloc(FALSE); 2290 2291 /* Should we reuse the existing file? */ 2292 if (attr = get_attr_bool(cmd, FSA_REUSE)) { 2293 fileset->fs_reuse = attr->attr_avd; 2294 } else 2295 fileset->fs_reuse = avd_bool_alloc(FALSE); 2296 2297 /* Should we leave in cache? */ 2298 if (attr = get_attr_bool(cmd, FSA_CACHED)) { 2299 fileset->fs_cached = attr->attr_avd; 2300 } else 2301 fileset->fs_cached = avd_bool_alloc(FALSE); 2302 2303 /* Get the mean or absolute size of the file */ 2304 if (attr = get_attr_integer(cmd, FSA_SIZE)) { 2305 fileset->fs_size = attr->attr_avd; 2306 } else 2307 fileset->fs_size = avd_int_alloc(0); 2308 2309 return (fileset); 2310 } 2311 2312 /* 2313 * Calls parser_fileset_define_common() to allocate a fileset with 2314 * one entry and optionally the fileset_prealloc. Sets the 2315 * fileset_preallocpercent, fileset_entries, fileset_dirwidth, 2316 * fileset_dirgamma, and fileset_sizegamma attributes 2317 * to appropriate values for emulating the old "fileobj" entity 2318 */ 2319 static void 2320 parser_file_define(cmd_t *cmd) 2321 { 2322 fileset_t *fileset; 2323 attr_t *attr; 2324 2325 if ((fileset = parser_fileset_define_common(cmd)) == NULL) { 2326 filebench_log(LOG_ERROR, 2327 "define file: failed to instantiate file"); 2328 filebench_shutdown(1); 2329 return; 2330 } 2331 2332 /* fileset is emulating a single file */ 2333 fileset->fs_attrs = FILESET_IS_FILE; 2334 2335 /* Set the size of the fileset to 1 */ 2336 fileset->fs_entries = avd_int_alloc(1); 2337 2338 /* Set the mean dir width to more than 1 */ 2339 fileset->fs_dirwidth = avd_int_alloc(10); 2340 2341 /* Set the dir and size gammas to 0 */ 2342 fileset->fs_dirgamma = avd_int_alloc(0); 2343 fileset->fs_sizegamma = avd_int_alloc(0); 2344 2345 /* Does file need to be preallocated? */ 2346 if (attr = get_attr_bool(cmd, FSA_PREALLOC)) { 2347 /* yes */ 2348 fileset->fs_prealloc = attr->attr_avd; 2349 fileset->fs_preallocpercent = avd_int_alloc(100); 2350 } else { 2351 /* no */ 2352 fileset->fs_prealloc = avd_bool_alloc(FALSE); 2353 fileset->fs_preallocpercent = avd_int_alloc(0); 2354 } 2355 } 2356 2357 /* 2358 * Calls parser_fileset_define_common() to allocate a fileset with the 2359 * supplied name and initializes the fileset's fileset_preallocpercent, 2360 * fileset_prealloc, fileset_entries, fileset_dirwidth, fileset_dirgamma, 2361 * and fileset_sizegamma attributes. 2362 */ 2363 static void 2364 parser_fileset_define(cmd_t *cmd) 2365 { 2366 fileset_t *fileset; 2367 attr_t *attr; 2368 2369 if ((fileset = parser_fileset_define_common(cmd)) == NULL) { 2370 filebench_log(LOG_ERROR, 2371 "define fileset: failed to instantiate fileset"); 2372 filebench_shutdown(1); 2373 return; 2374 } 2375 2376 /* How much should we preallocate? */ 2377 if ((attr = get_attr_integer(cmd, FSA_PREALLOC)) && 2378 attr->attr_avd) { 2379 if (AVD_IS_RANDOM(attr->attr_avd)) { 2380 filebench_log(LOG_ERROR, 2381 "define fileset: Prealloc attr cannot be random"); 2382 filebench_shutdown(1); 2383 } 2384 fileset->fs_preallocpercent = attr->attr_avd; 2385 } else if (attr && !attr->attr_avd) { 2386 fileset->fs_preallocpercent = avd_int_alloc(100); 2387 } else { 2388 fileset->fs_preallocpercent = avd_int_alloc(0); 2389 } 2390 2391 /* Should we preallocate? */ 2392 if (attr = get_attr_bool(cmd, FSA_PREALLOC)) { 2393 fileset->fs_prealloc = attr->attr_avd; 2394 } else 2395 fileset->fs_prealloc = avd_bool_alloc(FALSE); 2396 2397 /* Get the number of files in the fileset */ 2398 if (attr = get_attr_integer(cmd, FSA_ENTRIES)) { 2399 fileset->fs_entries = attr->attr_avd; 2400 } else { 2401 filebench_log(LOG_ERROR, "Fileset has zero entries"); 2402 fileset->fs_entries = avd_int_alloc(0); 2403 } 2404 2405 /* Get the mean dir width of the fileset */ 2406 if (attr = get_attr_integer(cmd, FSA_DIRWIDTH)) { 2407 fileset->fs_dirwidth = attr->attr_avd; 2408 } else { 2409 filebench_log(LOG_ERROR, "Fileset has zero directory width"); 2410 fileset->fs_dirwidth = avd_int_alloc(0); 2411 } 2412 2413 /* Get the random variable for dir depth, if supplied */ 2414 if (attr = get_attr_integer(cmd, FSA_DIRDEPTHRV)) { 2415 if (!AVD_IS_RANDOM(attr->attr_avd)) { 2416 filebench_log(LOG_ERROR, 2417 "Define fileset: dirdepthrv must be random var"); 2418 filebench_shutdown(1); 2419 } 2420 fileset->fs_dirdepthrv = attr->attr_avd; 2421 } else { 2422 fileset->fs_dirdepthrv = NULL; 2423 } 2424 2425 /* Get the gamma value for dir depth distributions */ 2426 if (attr = get_attr_integer(cmd, FSA_DIRGAMMA)) { 2427 if (AVD_IS_RANDOM(attr->attr_avd)) { 2428 filebench_log(LOG_ERROR, 2429 "Define fileset: dirgamma attr cannot be random"); 2430 filebench_shutdown(1); 2431 } 2432 fileset->fs_dirgamma = attr->attr_avd; 2433 } else 2434 fileset->fs_dirgamma = avd_int_alloc(1500); 2435 2436 /* Get the gamma value for dir width distributions */ 2437 if (attr = get_attr_integer(cmd, FSA_FILESIZEGAMMA)) { 2438 if (AVD_IS_RANDOM(attr->attr_avd)) { 2439 filebench_log(LOG_ERROR, 2440 "Define fileset: filesizegamma cannot be random"); 2441 filebench_shutdown(1); 2442 } 2443 fileset->fs_sizegamma = attr->attr_avd; 2444 } else 2445 fileset->fs_sizegamma = avd_int_alloc(1500); 2446 } 2447 2448 /* 2449 * Creates and starts all defined procflow processes. The call to 2450 * procflow_init() results in creation of the requested number of 2451 * process instances for each previously defined procflow. The 2452 * child processes exec() a new instance of filebench, passing it 2453 * the instance number and address of the shared memory region. 2454 * The child processes will then create their threads and flowops. 2455 * The routine then unlocks the run_lock to allow all the processes' 2456 * threads to start and waits for all of them to begin execution. 2457 * Finally, it records the start time and resets the event generation 2458 * system. 2459 */ 2460 static void 2461 parser_proc_create(cmd_t *cmd) 2462 { 2463 filebench_shm->shm_1st_err = 0; 2464 if (procflow_init() != 0) { 2465 filebench_log(LOG_ERROR, "Failed to create processes\n"); 2466 filebench_shutdown(1); 2467 } 2468 2469 /* Release the read lock, allowing threads to start */ 2470 (void) pthread_rwlock_unlock(&filebench_shm->run_lock); 2471 2472 /* Wait for all threads to start */ 2473 if (procflow_allstarted() != 0) { 2474 filebench_log(LOG_ERROR, "Could not start run"); 2475 return; 2476 } 2477 2478 2479 if (filebench_shm->shm_required && 2480 (ipc_ismcreate(filebench_shm->shm_required) < 0)) { 2481 filebench_log(LOG_ERROR, "Could not allocate shared memory"); 2482 return; 2483 } 2484 2485 filebench_shm->shm_starttime = gethrtime(); 2486 eventgen_reset(); 2487 } 2488 2489 /* 2490 * Calls fileset_createset() to populate all files and filesets and 2491 * create all associated, initially existant, files and subdirectories. 2492 * If errors are encountered, calls filebench_shutdown() 2493 * to exit filebench. 2494 */ 2495 static void 2496 parser_fileset_create(cmd_t *cmd) 2497 { 2498 if (!filecreate_done) { 2499 filecreate_done = 1; 2500 2501 /* initialize the random number system first */ 2502 randdist_init(); 2503 2504 /* create all the filesets */ 2505 if (fileset_createset(NULL) != 0) { 2506 filebench_log(LOG_ERROR, "Failed to create filesets"); 2507 filebench_shutdown(1); 2508 } 2509 } else { 2510 filebench_log(LOG_INFO, 2511 "Attempting to create fileset more than once, ignoring"); 2512 } 2513 2514 } 2515 2516 /* 2517 * Shuts down all processes and their associated threads. When finished 2518 * it deletes interprocess shared memory and resets the event generator. 2519 * It does not exit the filebench program though. 2520 */ 2521 static void 2522 parser_proc_shutdown(cmd_t *cmd) 2523 { 2524 filebench_log(LOG_INFO, "Shutting down processes"); 2525 filecreate_done = 0; 2526 procflow_shutdown(); 2527 if (filebench_shm->shm_required) 2528 ipc_ismdelete(); 2529 eventgen_reset(); 2530 } 2531 2532 /* 2533 * Ends filebench run after first destoring any interprocess 2534 * shared memory. The call to filebench_shutdown() 2535 * also causes filebench to exit. 2536 */ 2537 static void 2538 parser_filebench_shutdown(cmd_t *cmd) 2539 { 2540 ipc_cleanup(); 2541 filebench_shutdown(0); 2542 } 2543 2544 /* 2545 * This is Used for timing runs.Pauses the master thread in one second 2546 * intervals until the supplied ptime runs out or the f_abort flag 2547 * is raised. If given a time of zero or less, or the mode is stop on 2548 * lack of resources, it will pause until f_abort is raised. 2549 */ 2550 static void 2551 parser_pause(int ptime) 2552 { 2553 int timeslept = 0; 2554 2555 if ((filebench_shm->shm_rmode == FILEBENCH_MODE_TIMEOUT) && 2556 (ptime > 0)) { 2557 while (timeslept < ptime) { 2558 (void) sleep(1); 2559 timeslept++; 2560 if (filebench_shm->f_abort) 2561 break; 2562 } 2563 } else { 2564 /* initial runtime of 0 means run till abort */ 2565 /* CONSTCOND */ 2566 while (1) { 2567 (void) sleep(1); 2568 timeslept++; 2569 if (filebench_shm->f_abort) 2570 break; 2571 } 2572 } 2573 2574 filebench_log(LOG_INFO, "Run took %d seconds...", timeslept); 2575 } 2576 2577 /* 2578 * Do a file bench run. Calls routines to create file sets, files, and 2579 * processes. It resets the statistics counters, then sleeps for the runtime 2580 * passed as an argument to it on the command line in 1 second increments. 2581 * When it is finished sleeping, it collects a snapshot of the statistics 2582 * and ends the run. 2583 */ 2584 static void 2585 parser_run(cmd_t *cmd) 2586 { 2587 int runtime; 2588 2589 runtime = cmd->cmd_qty; 2590 2591 parser_fileset_create(cmd); 2592 parser_proc_create(cmd); 2593 2594 /* check for startup errors */ 2595 if (filebench_shm->f_abort) 2596 return; 2597 2598 filebench_log(LOG_INFO, "Running..."); 2599 stats_clear(); 2600 2601 parser_pause(runtime); 2602 2603 parser_statssnap(cmd); 2604 parser_proc_shutdown(cmd); 2605 } 2606 2607 /* 2608 * Similar to parser_run, but gets the sleep time from a variable 2609 * whose name is supplied as an argument to the command. 2610 */ 2611 static void 2612 parser_run_variable(cmd_t *cmd) 2613 { 2614 avd_t integer = var_ref_attr(cmd->cmd_tgt1); 2615 int runtime; 2616 2617 if (integer == NULL) { 2618 filebench_log(LOG_ERROR, "Unknown variable %s", 2619 cmd->cmd_tgt1); 2620 return; 2621 } 2622 2623 runtime = avd_get_int(integer); 2624 2625 /* check for startup errors */ 2626 if (filebench_shm->f_abort) 2627 return; 2628 2629 filebench_log(LOG_INFO, "Running..."); 2630 stats_clear(); 2631 2632 parser_pause(runtime); 2633 2634 parser_statssnap(cmd); 2635 parser_proc_shutdown(cmd); 2636 } 2637 2638 char *usagestr = NULL; 2639 2640 /* 2641 * Prints usage string if defined, else just a message requesting load of a 2642 * personality. 2643 */ 2644 static void 2645 parser_help(cmd_t *cmd) 2646 { 2647 int runtime; 2648 2649 if (usagestr) { 2650 filebench_log(LOG_INFO, "%s", usagestr); 2651 } else { 2652 filebench_log(LOG_INFO, 2653 "load <personality> (ls " 2654 "/usr/benchmarks/filebench/workloads for list)"); 2655 } 2656 } 2657 2658 char *varstr = NULL; 2659 2660 /* 2661 * Prints the string of all var definitions, if there is one. 2662 */ 2663 static void 2664 parser_printvars(cmd_t *cmd) 2665 { 2666 int runtime; 2667 char *str, *c; 2668 2669 if (varstr) { 2670 str = strdup(varstr); 2671 for (c = str; *c != '\0'; c++) { 2672 if ((char)*c == '$') 2673 *c = ' '; 2674 } 2675 filebench_log(LOG_INFO, "%s", str); 2676 free(str); 2677 } 2678 } 2679 2680 /* 2681 * Used by the SET command to add a var and default value string to the 2682 * varstr string. It allocates a new, larger varstr string, copies the 2683 * old contents of varstr into it, then adds the new var string on the end. 2684 */ 2685 static void 2686 parser_vars(cmd_t *cmd) 2687 { 2688 char *string = cmd->cmd_tgt1; 2689 char *newvars; 2690 2691 if (string == NULL) 2692 return; 2693 2694 if (dofile) 2695 return; 2696 2697 if (varstr == NULL) { 2698 newvars = malloc(strlen(string) + 2); 2699 *newvars = 0; 2700 } else { 2701 newvars = malloc(strlen(varstr) + strlen(string) + 2); 2702 (void) strcpy(newvars, varstr); 2703 } 2704 (void) strcat(newvars, string); 2705 (void) strcat(newvars, " "); 2706 2707 if (varstr) 2708 free(varstr); 2709 2710 varstr = newvars; 2711 } 2712 2713 /* 2714 * Sleeps for cmd->cmd_qty seconds, one second at a time. 2715 */ 2716 static void 2717 parser_sleep(cmd_t *cmd) 2718 { 2719 int sleeptime; 2720 2721 /* check for startup errors */ 2722 if (filebench_shm->f_abort) 2723 return; 2724 2725 sleeptime = cmd->cmd_qty; 2726 filebench_log(LOG_INFO, "Running..."); 2727 2728 parser_pause(sleeptime); 2729 } 2730 2731 /* 2732 * used by the set command to set the integer part of a regular 2733 * variable, or the appropriate field of a random variable 2734 */ 2735 static void 2736 parser_set_integer(char *name, fbint_t integer) 2737 { 2738 var_assign_integer(name, integer); 2739 } 2740 2741 /* 2742 * used by the set command to set the integer part of a regular 2743 * variable from another variable, or the appropriate field of a 2744 * random variable from another variable 2745 */ 2746 static void 2747 parser_set_var(char *dst_name, char *src_name) 2748 { 2749 var_assign_var(dst_name, src_name); 2750 } 2751 2752 2753 /* 2754 * Same as parser_sleep, except the sleep time is obtained from a variable 2755 * whose name is passed to it as an argument on the command line. 2756 */ 2757 static void 2758 parser_sleep_variable(cmd_t *cmd) 2759 { 2760 avd_t integer = var_ref_attr(cmd->cmd_tgt1); 2761 int sleeptime; 2762 2763 if (integer == NULL) { 2764 filebench_log(LOG_ERROR, "Unknown variable %s", 2765 cmd->cmd_tgt1); 2766 return; 2767 } 2768 2769 sleeptime = avd_get_int(integer); 2770 2771 /* check for startup errors */ 2772 if (filebench_shm->f_abort) 2773 return; 2774 2775 filebench_log(LOG_INFO, "Running..."); 2776 2777 parser_pause(sleeptime); 2778 } 2779 2780 /* 2781 * Parser log prints the values of a list of variables to the log file. 2782 * The list of variables is placed on the command line, separated 2783 * by comas and the entire list is enclosed in quotes. 2784 * For example, if $dir contains "/export/home/tmp" and $filesize = 1048576, 2785 * then typing: log "$dir, $filesize" prints: log /export/home/tmp, 1048576 2786 */ 2787 static void 2788 parser_log(cmd_t *cmd) 2789 { 2790 char *string; 2791 2792 if (cmd->cmd_param_list == NULL) 2793 return; 2794 2795 string = parser_list2string(cmd->cmd_param_list); 2796 2797 if (string == NULL) 2798 return; 2799 2800 filebench_log(LOG_VERBOSE, "log %s", string); 2801 filebench_log(LOG_LOG, "%s", string); 2802 } 2803 2804 /* 2805 * Implements the stats directory command. changes the directory for 2806 * dumping statistics to supplied directory path. For example: 2807 * stats directory /tmp 2808 * changes the stats directory to "/tmp". 2809 */ 2810 static void 2811 parser_directory(cmd_t *cmd) 2812 { 2813 char newdir[MAXPATHLEN]; 2814 char *dir; 2815 2816 if ((dir = parser_list2string(cmd->cmd_param_list)) == NULL) { 2817 filebench_log(LOG_ERROR, "Cannot interpret directory"); 2818 return; 2819 } 2820 2821 *newdir = 0; 2822 /* Change dir relative to cwd if path not fully qualified */ 2823 if (*dir != '/') { 2824 (void) strcat(newdir, cwd); 2825 (void) strcat(newdir, "/"); 2826 } 2827 (void) strcat(newdir, dir); 2828 (void) mkdir(newdir, 0755); 2829 filebench_log(LOG_VERBOSE, "Change dir to %s", newdir); 2830 chdir(newdir); 2831 free(dir); 2832 } 2833 2834 #define PIPE_PARENT 1 2835 #define PIPE_CHILD 0 2836 2837 /* 2838 * Runs the quoted unix command as a background process. Intended for 2839 * running statistics gathering utilities such as mpstat while the filebench 2840 * workload is running. Also records the pid's of the background processes 2841 * so that parser_statssnap() can terminate them when the run completes. 2842 */ 2843 static void 2844 parser_statscmd(cmd_t *cmd) 2845 { 2846 char *string; 2847 pid_t pid; 2848 pidlist_t *pidlistent; 2849 int pipe_fd[2]; 2850 int newstdout; 2851 2852 if (cmd->cmd_param_list == NULL) 2853 return; 2854 2855 string = parser_list2string(cmd->cmd_param_list); 2856 2857 if (string == NULL) 2858 return; 2859 2860 if ((pipe(pipe_fd)) < 0) { 2861 filebench_log(LOG_ERROR, "statscmd pipe failed"); 2862 return; 2863 } 2864 2865 #ifdef HAVE_FORK1 2866 if ((pid = fork1()) < 0) { 2867 filebench_log(LOG_ERROR, "statscmd fork failed"); 2868 return; 2869 } 2870 #elif HAVE_FORK 2871 if ((pid = fork()) < 0) { 2872 filebench_log(LOG_ERROR, "statscmd fork failed"); 2873 return; 2874 } 2875 #else 2876 Crash! - Need code to deal with no fork1! 2877 #endif /* HAVE_FORK1 */ 2878 2879 if (pid == 0) { 2880 2881 setsid(); 2882 2883 filebench_log(LOG_VERBOSE, 2884 "Backgrounding %s", string); 2885 /* 2886 * Child 2887 * - close stdout 2888 * - dup to create new stdout 2889 * - close pipe fds 2890 */ 2891 (void) close(1); 2892 2893 if ((newstdout = dup(pipe_fd[PIPE_CHILD])) < 0) { 2894 filebench_log(LOG_ERROR, 2895 "statscmd dup failed: %s", 2896 strerror(errno)); 2897 } 2898 2899 (void) close(pipe_fd[PIPE_PARENT]); 2900 (void) close(pipe_fd[PIPE_CHILD]); 2901 2902 if (system(string) < 0) { 2903 filebench_log(LOG_ERROR, 2904 "statscmd exec failed: %s", 2905 strerror(errno)); 2906 } 2907 /* Failed! */ 2908 exit(1); 2909 2910 } else { 2911 2912 /* Record pid in pidlist for subsequent reaping by stats snap */ 2913 if ((pidlistent = (pidlist_t *)malloc(sizeof (pidlist_t))) 2914 == NULL) { 2915 filebench_log(LOG_ERROR, "pidlistent malloc failed"); 2916 return; 2917 } 2918 2919 pidlistent->pl_pid = pid; 2920 pidlistent->pl_fd = pipe_fd[PIPE_PARENT]; 2921 (void) close(pipe_fd[PIPE_CHILD]); 2922 2923 /* Add fileobj to global list */ 2924 if (pidlist == NULL) { 2925 pidlist = pidlistent; 2926 pidlistent->pl_next = NULL; 2927 } else { 2928 pidlistent->pl_next = pidlist; 2929 pidlist = pidlistent; 2930 } 2931 } 2932 } 2933 2934 /* 2935 * Launches a shell to run the unix command supplied in the argument. 2936 * The command should be enclosed in quotes, as in: 2937 * system "rm xyz" 2938 * which would run the "rm" utility to delete the file "xyz". 2939 */ 2940 static void 2941 parser_system(cmd_t *cmd) 2942 { 2943 char *string; 2944 2945 if (cmd->cmd_param_list == NULL) 2946 return; 2947 2948 string = parser_list2string(cmd->cmd_param_list); 2949 2950 if (string == NULL) 2951 return; 2952 2953 filebench_log(LOG_VERBOSE, 2954 "Running '%s'", string); 2955 2956 if (system(string) < 0) { 2957 filebench_log(LOG_ERROR, 2958 "system exec failed: %s", 2959 strerror(errno)); 2960 } 2961 free(string); 2962 } 2963 2964 /* 2965 * Echos string supplied with command to the log. 2966 */ 2967 static void 2968 parser_echo(cmd_t *cmd) 2969 { 2970 char *string; 2971 2972 if (cmd->cmd_param_list == NULL) 2973 return; 2974 2975 string = parser_list2string(cmd->cmd_param_list); 2976 2977 if (string == NULL) 2978 return; 2979 2980 filebench_log(LOG_INFO, "%s", string); 2981 } 2982 2983 2984 /* 2985 * Adds the string supplied as the argument to the usage command 2986 * to the end of the string printed by the help command. 2987 */ 2988 static void 2989 parser_usage(cmd_t *cmd) 2990 { 2991 char *string; 2992 char *newusage; 2993 2994 if (cmd->cmd_param_list == NULL) 2995 return; 2996 2997 string = parser_list2string(cmd->cmd_param_list); 2998 2999 if (string == NULL) 3000 return; 3001 3002 if (dofile) 3003 return; 3004 3005 if (usagestr == NULL) { 3006 newusage = malloc(strlen(string) + 2); 3007 *newusage = 0; 3008 } else { 3009 newusage = malloc(strlen(usagestr) + strlen(string) + 2); 3010 (void) strcpy(newusage, usagestr); 3011 } 3012 (void) strcat(newusage, "\n"); 3013 (void) strcat(newusage, string); 3014 3015 if (usagestr) 3016 free(usagestr); 3017 3018 usagestr = newusage; 3019 3020 filebench_log(LOG_INFO, "%s", string); 3021 } 3022 3023 /* 3024 * Updates the global dump filename with the filename supplied 3025 * as the command's argument. Then dumps the statistics of each 3026 * worker flowop into the dump file, followed by a summary of 3027 * overall totals. 3028 */ 3029 static void 3030 parser_statsdump(cmd_t *cmd) 3031 { 3032 char *string; 3033 3034 if (cmd->cmd_param_list == NULL) 3035 return; 3036 3037 string = parser_list2string(cmd->cmd_param_list); 3038 3039 if (string == NULL) 3040 return; 3041 3042 filebench_log(LOG_VERBOSE, 3043 "Stats dump to file '%s'", string); 3044 3045 stats_dump(string); 3046 3047 free(string); 3048 } 3049 3050 /* 3051 * Same as parser_statsdump, but in xml format. 3052 */ 3053 static void 3054 parser_statsxmldump(cmd_t *cmd) 3055 { 3056 char *string; 3057 3058 if (cmd->cmd_param_list == NULL) 3059 return; 3060 3061 string = parser_list2string(cmd->cmd_param_list); 3062 3063 if (string == NULL) 3064 return; 3065 3066 filebench_log(LOG_VERBOSE, 3067 "Stats dump to file '%s'", string); 3068 3069 stats_xmldump(string); 3070 3071 free(string); 3072 } 3073 3074 /* 3075 * Kills off background statistics collection processes, then takes a snapshot 3076 * of the filebench run's collected statistics using stats_snap() from 3077 * stats.c. 3078 */ 3079 static void 3080 parser_statssnap(cmd_t *cmd) 3081 { 3082 pidlist_t *pidlistent; 3083 int stat; 3084 pid_t pid; 3085 3086 for (pidlistent = pidlist; pidlistent != NULL; 3087 pidlistent = pidlistent->pl_next) { 3088 filebench_log(LOG_VERBOSE, "Killing session %d for pid %d", 3089 getsid(pidlistent->pl_pid), 3090 pidlistent->pl_pid); 3091 if (pidlistent->pl_fd) 3092 (void) close(pidlistent->pl_fd); 3093 #ifdef HAVE_SIGSEND 3094 sigsend(P_SID, getsid(pidlistent->pl_pid), SIGTERM); 3095 #else 3096 (void) kill(-1, SIGTERM); 3097 #endif 3098 3099 /* Close pipe */ 3100 if (pidlistent->pl_fd) 3101 (void) close(pidlistent->pl_fd); 3102 3103 /* Wait for cmd and all its children */ 3104 while ((pid = waitpid(pidlistent->pl_pid * -1, &stat, 0)) > 0) 3105 filebench_log(LOG_DEBUG_IMPL, 3106 "Waited for pid %d", (int)pid); 3107 } 3108 3109 for (pidlistent = pidlist; pidlistent != NULL; 3110 pidlistent = pidlistent->pl_next) { 3111 free(pidlistent); 3112 } 3113 3114 pidlist = NULL; 3115 stats_snap(); 3116 } 3117 3118 /* 3119 * Shutdown filebench. 3120 */ 3121 static void 3122 parser_abort(int arg) 3123 { 3124 (void) sigignore(SIGINT); 3125 filebench_log(LOG_INFO, "Aborting..."); 3126 filebench_shutdown(1); 3127 } 3128 3129 /* 3130 * define a random variable and initialize the distribution parameters 3131 */ 3132 static void 3133 parser_randvar_define(cmd_t *cmd) 3134 { 3135 var_t *var; 3136 randdist_t *rndp; 3137 attr_t *attr; 3138 char *name; 3139 3140 /* Get the name for the random variable */ 3141 if (attr = get_attr(cmd, FSA_NAME)) { 3142 name = avd_get_str(attr->attr_avd); 3143 } else { 3144 filebench_log(LOG_ERROR, 3145 "define randvar: no name specified"); 3146 return; 3147 } 3148 3149 if ((var = var_define_randvar(name)) == NULL) { 3150 filebench_log(LOG_ERROR, 3151 "define randvar: failed for random variable %s", 3152 name); 3153 return; 3154 } 3155 3156 rndp = var->var_val.randptr; 3157 rndp->rnd_type = 0; 3158 3159 /* Get the source of the random numbers */ 3160 if (attr = get_attr_integer(cmd, FSA_RANDSRC)) { 3161 int randsrc = (int)avd_get_int(attr->attr_avd); 3162 3163 switch (randsrc) { 3164 case FSV_URAND: 3165 rndp->rnd_type |= RAND_SRC_URANDOM; 3166 break; 3167 case FSV_RAND48: 3168 rndp->rnd_type |= RAND_SRC_GENERATOR; 3169 break; 3170 } 3171 } else { 3172 /* default to rand48 random number generator */ 3173 rndp->rnd_type |= RAND_SRC_GENERATOR; 3174 } 3175 3176 /* Get the min value of the random distribution */ 3177 if (attr = get_attr_integer(cmd, FSA_RANDMIN)) 3178 rndp->rnd_min = attr->attr_avd; 3179 else 3180 rndp->rnd_min = avd_int_alloc(0); 3181 3182 /* Get the mean value of the random distribution */ 3183 if (attr = get_attr_integer(cmd, FSA_RANDMEAN)) 3184 rndp->rnd_mean = attr->attr_avd; 3185 else 3186 rndp->rnd_mean = avd_int_alloc(0); 3187 3188 /* Get the roundoff value for the random distribution */ 3189 if (attr = get_attr_integer(cmd, FSA_RANDROUND)) 3190 rndp->rnd_round = attr->attr_avd; 3191 else 3192 rndp->rnd_round = avd_int_alloc(0); 3193 3194 /* Get a tablular probablility distribution if there is one */ 3195 if (attr = get_attr(cmd, FSA_RANDTABLE)) { 3196 rndp->rnd_probtabs = (probtabent_t *)(attr->attr_obj); 3197 rndp->rnd_type |= RAND_TYPE_TABLE; 3198 3199 /* no need for the rest of the attributes */ 3200 return; 3201 } else { 3202 rndp->rnd_probtabs = NULL; 3203 } 3204 3205 /* Get the type for the random variable */ 3206 if (attr = get_attr(cmd, FSA_TYPE)) { 3207 int disttype = (int)avd_get_int(attr->attr_avd); 3208 3209 switch (disttype) { 3210 case FSV_RANDUNI: 3211 rndp->rnd_type |= RAND_TYPE_UNIFORM; 3212 break; 3213 case FSA_RANDGAMMA: 3214 rndp->rnd_type |= RAND_TYPE_GAMMA; 3215 break; 3216 case FSV_RANDTAB: 3217 filebench_log(LOG_ERROR, 3218 "Table distribution type without prob table"); 3219 break; 3220 } 3221 } else { 3222 /* default to gamma distribution type */ 3223 rndp->rnd_type |= RAND_TYPE_GAMMA; 3224 } 3225 3226 /* Get the seed for the random variable */ 3227 if (attr = get_attr_integer(cmd, FSA_RANDSEED)) 3228 rndp->rnd_seed = attr->attr_avd; 3229 else 3230 rndp->rnd_seed = avd_int_alloc(0); 3231 3232 /* Get the gamma value of the random distribution */ 3233 if (attr = get_attr_integer(cmd, FSA_RANDGAMMA)) 3234 rndp->rnd_gamma = attr->attr_avd; 3235 else 3236 rndp->rnd_gamma = avd_int_alloc(1500); 3237 } 3238 3239 /* 3240 * Set a specified random distribution parameter in a random variable. 3241 */ 3242 static void 3243 parser_randvar_set(cmd_t *cmd) 3244 { 3245 var_t *src_var, *randvar; 3246 randdist_t *rndp; 3247 avd_t value; 3248 3249 if ((randvar = var_find_randvar(cmd->cmd_tgt1)) == NULL) { 3250 filebench_log(LOG_ERROR, 3251 "set randvar: failed", 3252 cmd->cmd_tgt1); 3253 return; 3254 } 3255 3256 rndp = randvar->var_val.randptr; 3257 value = cmd->cmd_attr_list->attr_avd; 3258 3259 switch (cmd->cmd_qty) { 3260 case FSS_TYPE: 3261 { 3262 int disttype = (int)avd_get_int(value); 3263 3264 printf("parser_randvar_set: changing type to %d\n", 3265 disttype); 3266 rndp->rnd_type &= (~RAND_TYPE_MASK); 3267 3268 switch (disttype) { 3269 case FSV_RANDUNI: 3270 rndp->rnd_type |= RAND_TYPE_UNIFORM; 3271 break; 3272 case FSA_RANDGAMMA: 3273 rndp->rnd_type |= RAND_TYPE_GAMMA; 3274 break; 3275 case FSV_RANDTAB: 3276 rndp->rnd_type |= RAND_TYPE_TABLE; 3277 break; 3278 } 3279 break; 3280 } 3281 3282 case FSS_SRC: 3283 { 3284 int randsrc = (int)avd_get_int(value); 3285 3286 printf("parser_randvar_set: changing source to %d\n", 3287 randsrc); 3288 3289 rndp->rnd_type &= 3290 (~(RAND_SRC_URANDOM | RAND_SRC_GENERATOR)); 3291 3292 switch (randsrc) { 3293 case FSV_URAND: 3294 rndp->rnd_type |= RAND_SRC_URANDOM; 3295 break; 3296 case FSV_RAND48: 3297 rndp->rnd_type |= RAND_SRC_GENERATOR; 3298 break; 3299 } 3300 break; 3301 } 3302 3303 case FSS_SEED: 3304 rndp->rnd_seed = value; 3305 break; 3306 3307 case FSS_GAMMA: 3308 rndp->rnd_gamma = value; 3309 break; 3310 3311 case FSS_MEAN: 3312 rndp->rnd_mean = value; 3313 break; 3314 3315 case FSS_MIN: 3316 rndp->rnd_min = value; 3317 break; 3318 3319 case FSS_ROUND: 3320 rndp->rnd_round = value; 3321 break; 3322 3323 default: 3324 filebench_log(LOG_ERROR, "setrandvar: undefined attribute"); 3325 } 3326 } 3327 3328 /* 3329 * alloc_cmd() allocates the required resources for a cmd_t. On failure, a 3330 * filebench_log is issued and NULL is returned. 3331 */ 3332 static cmd_t * 3333 alloc_cmd(void) 3334 { 3335 cmd_t *cmd; 3336 3337 if ((cmd = malloc(sizeof (cmd_t))) == NULL) { 3338 filebench_log(LOG_ERROR, "Alloc cmd failed"); 3339 return (NULL); 3340 } 3341 3342 (void) memset(cmd, 0, sizeof (cmd_t)); 3343 3344 return (cmd); 3345 } 3346 3347 /* 3348 * Frees the resources of a cmd_t and then the cmd_t "cmd" itself. 3349 */ 3350 static void 3351 free_cmd(cmd_t *cmd) 3352 { 3353 free((void *)cmd->cmd_tgt1); 3354 free((void *)cmd->cmd_tgt2); 3355 free(cmd); 3356 } 3357 3358 /* 3359 * Allocates an attr_t structure and zeros it. Returns NULL on failure, or 3360 * a pointer to the attr_t. 3361 */ 3362 static attr_t * 3363 alloc_attr() 3364 { 3365 attr_t *attr; 3366 3367 if ((attr = malloc(sizeof (attr_t))) == NULL) { 3368 return (NULL); 3369 } 3370 3371 (void) memset(attr, 0, sizeof (attr_t)); 3372 return (attr); 3373 } 3374 3375 /* 3376 * Allocates a probtabent_t structure and zeros it. Returns NULL on failure, or 3377 * a pointer to the probtabent_t. 3378 */ 3379 static probtabent_t * 3380 alloc_probtabent(void) 3381 { 3382 probtabent_t *rte; 3383 3384 if ((rte = malloc(sizeof (probtabent_t))) == NULL) { 3385 return (NULL); 3386 } 3387 3388 (void) memset(rte, 0, sizeof (probtabent_t)); 3389 return (rte); 3390 } 3391 3392 /* 3393 * Searches the attribute list for the command for the named attribute type. 3394 * The attribute list is created by the parser from the list of attributes 3395 * supplied with certain commands, such as the define and flowop commands. 3396 * Returns a pointer to the attribute structure if the named attribute is 3397 * found, otherwise returns NULL. If the attribute includes a parameter list, 3398 * the list is converted to a string and stored in the attr_avd field of 3399 * the returned attr_t struct. 3400 */ 3401 static attr_t * 3402 get_attr(cmd_t *cmd, int64_t name) 3403 { 3404 attr_t *attr; 3405 attr_t *rtn = NULL; 3406 char *string; 3407 3408 for (attr = cmd->cmd_attr_list; attr != NULL; 3409 attr = attr->attr_next) { 3410 filebench_log(LOG_DEBUG_IMPL, 3411 "attr %d = %d %llx?", 3412 attr->attr_name, 3413 name, 3414 attr->attr_avd); 3415 3416 if (attr->attr_name == name) 3417 rtn = attr; 3418 } 3419 3420 if (rtn == NULL) 3421 return (NULL); 3422 3423 if (rtn->attr_param_list) { 3424 filebench_log(LOG_DEBUG_SCRIPT, "attr is param list"); 3425 string = parser_list2string(rtn->attr_param_list); 3426 if (string != NULL) { 3427 rtn->attr_avd = avd_str_alloc(string); 3428 filebench_log(LOG_DEBUG_SCRIPT, 3429 "attr string %s", string); 3430 } 3431 } 3432 3433 return (rtn); 3434 } 3435 3436 /* 3437 * Similar to get_attr, but converts the parameter string supplied with the 3438 * named attribute to an integer and stores the integer in the attr_avd 3439 * portion of the returned attr_t struct. 3440 */ 3441 static attr_t * 3442 get_attr_integer(cmd_t *cmd, int64_t name) 3443 { 3444 attr_t *attr; 3445 attr_t *rtn = NULL; 3446 3447 for (attr = cmd->cmd_attr_list; attr != NULL; 3448 attr = attr->attr_next) { 3449 if (attr->attr_name == name) 3450 rtn = attr; 3451 } 3452 3453 if (rtn == NULL) 3454 return (NULL); 3455 3456 if (rtn->attr_param_list) 3457 rtn->attr_avd = parser_list2avd(rtn->attr_param_list); 3458 3459 return (rtn); 3460 } 3461 3462 /* 3463 * Similar to get_attr, but converts the parameter string supplied with the 3464 * named attribute to an integer and stores the integer in the attr_avd 3465 * portion of the returned attr_t struct. If no parameter string is supplied 3466 * then it defaults to TRUE (1). 3467 */ 3468 static attr_t * 3469 get_attr_bool(cmd_t *cmd, int64_t name) 3470 { 3471 attr_t *attr; 3472 attr_t *rtn = NULL; 3473 3474 for (attr = cmd->cmd_attr_list; attr != NULL; 3475 attr = attr->attr_next) { 3476 if (attr->attr_name == name) 3477 rtn = attr; 3478 } 3479 3480 if (rtn == NULL) 3481 return (NULL); 3482 3483 if (rtn->attr_param_list) { 3484 rtn->attr_avd = parser_list2avd(rtn->attr_param_list); 3485 3486 } else if (rtn->attr_avd == NULL) { 3487 rtn->attr_avd = avd_bool_alloc(TRUE); 3488 } 3489 3490 /* boolean attributes cannot point to random variables */ 3491 if (AVD_IS_RANDOM(rtn->attr_avd)) { 3492 filebench_log(LOG_ERROR, 3493 "define flowop: Boolean attr %s cannot be random", name); 3494 filebench_shutdown(1); 3495 return (NULL); 3496 } 3497 3498 return (rtn); 3499 } 3500 3501 /* 3502 * Allocates memory for a list_t structure, initializes it to zero, and 3503 * returns a pointer to it. On failure, returns NULL. 3504 */ 3505 static list_t * 3506 alloc_list() 3507 { 3508 list_t *list; 3509 3510 if ((list = malloc(sizeof (list_t))) == NULL) { 3511 return (NULL); 3512 } 3513 3514 (void) memset(list, 0, sizeof (list_t)); 3515 return (list); 3516 } 3517 3518 3519 #define USAGE1 \ 3520 "Usage:\n" \ 3521 "%s: interpret f script and generate file workload\n" \ 3522 "Options:\n" \ 3523 " [-h] Display verbose help\n" \ 3524 " [-p] Disable opening /proc to set uacct to enable truss\n" 3525 3526 #define PARSER_CMDS \ 3527 "create [files|filesets|processes]\n" \ 3528 "stats [clear|snap]\n" \ 3529 "stats command \"shell command $var1,$var2...\"\n" \ 3530 "stats directory <directory>\n" \ 3531 "sleep <sleep-value>\n" \ 3532 "quit\n\n" \ 3533 "Variables:\n" \ 3534 "set $var = value\n" \ 3535 " $var - regular variables\n" \ 3536 " ${var} - internal special variables\n" \ 3537 " $(var) - environment variables\n\n" 3538 3539 #define PARSER_EXAMPLE \ 3540 "Example:\n\n" \ 3541 "#!/usr/bin/filebench -f\n" \ 3542 "\n" \ 3543 "define file name=bigfile,path=bigfile,size=1g,prealloc,reuse\n" \ 3544 "define process name=randomizer\n" \ 3545 "{\n" \ 3546 " thread random-thread procname=randomizer\n" \ 3547 " {\n" \ 3548 " flowop read name=random-read,filename=bigfile,iosize=16k,random\n" \ 3549 " }\n" \ 3550 "}\n" \ 3551 "create files\n" \ 3552 "create processes\n" \ 3553 "stats clear\n" \ 3554 "sleep 30\n" \ 3555 "stats snap\n" 3556 3557 /* 3558 * usage() display brief or verbose help for the filebench(1) command. 3559 */ 3560 static void 3561 usage(int help) 3562 { 3563 if (help >= 1) 3564 (void) fprintf(stderr, USAGE1, cmdname); 3565 if (help >= 2) { 3566 3567 (void) fprintf(stderr, 3568 "\n'f' language definition:\n\n"); 3569 fileset_usage(); 3570 procflow_usage(); 3571 threadflow_usage(); 3572 flowoplib_usage(); 3573 eventgen_usage(); 3574 (void) fprintf(stderr, PARSER_CMDS); 3575 (void) fprintf(stderr, PARSER_EXAMPLE); 3576 } 3577 exit(E_USAGE); 3578 } 3579 3580 int 3581 yywrap() 3582 { 3583 char buf[1024]; 3584 3585 if (parentscript) { 3586 yyin = parentscript; 3587 yy_switchfilescript(yyin); 3588 parentscript = NULL; 3589 return (0); 3590 } else 3591 return (1); 3592 } 3593