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 /* if a raw device, all done */ 2346 if (fileset_checkraw(fileset)) { 2347 filebench_log(LOG_VERBOSE, "File %s/%s is RAW device", 2348 avd_get_str(fileset->fs_path), 2349 avd_get_str(fileset->fs_name)); 2350 return; 2351 } 2352 2353 /* Does file need to be preallocated? */ 2354 if (attr = get_attr_bool(cmd, FSA_PREALLOC)) { 2355 /* yes */ 2356 fileset->fs_prealloc = attr->attr_avd; 2357 fileset->fs_preallocpercent = avd_int_alloc(100); 2358 } else { 2359 /* no */ 2360 fileset->fs_prealloc = avd_bool_alloc(FALSE); 2361 fileset->fs_preallocpercent = avd_int_alloc(0); 2362 } 2363 } 2364 2365 /* 2366 * Calls parser_fileset_define_common() to allocate a fileset with the 2367 * supplied name and initializes the fileset's fileset_preallocpercent, 2368 * fileset_prealloc, fileset_entries, fileset_dirwidth, fileset_dirgamma, 2369 * and fileset_sizegamma attributes. 2370 */ 2371 static void 2372 parser_fileset_define(cmd_t *cmd) 2373 { 2374 fileset_t *fileset; 2375 attr_t *attr; 2376 2377 if ((fileset = parser_fileset_define_common(cmd)) == NULL) { 2378 filebench_log(LOG_ERROR, 2379 "define fileset: failed to instantiate fileset"); 2380 filebench_shutdown(1); 2381 return; 2382 } 2383 2384 /* if a raw device, Error */ 2385 if (fileset_checkraw(fileset)) { 2386 filebench_log(LOG_ERROR, 2387 "Fileset %s/%s: Cannot create a fileset on a RAW device", 2388 avd_get_str(fileset->fs_path), 2389 avd_get_str(fileset->fs_name)); 2390 filebench_shutdown(0); 2391 return; 2392 } 2393 2394 /* How much should we preallocate? */ 2395 if ((attr = get_attr_integer(cmd, FSA_PREALLOC)) && 2396 attr->attr_avd) { 2397 if (AVD_IS_RANDOM(attr->attr_avd)) { 2398 filebench_log(LOG_ERROR, 2399 "define fileset: Prealloc attr cannot be random"); 2400 filebench_shutdown(1); 2401 } 2402 fileset->fs_preallocpercent = attr->attr_avd; 2403 } else if (attr && !attr->attr_avd) { 2404 fileset->fs_preallocpercent = avd_int_alloc(100); 2405 } else { 2406 fileset->fs_preallocpercent = avd_int_alloc(0); 2407 } 2408 2409 /* Should we preallocate? */ 2410 if (attr = get_attr_bool(cmd, FSA_PREALLOC)) { 2411 fileset->fs_prealloc = attr->attr_avd; 2412 } else 2413 fileset->fs_prealloc = avd_bool_alloc(FALSE); 2414 2415 /* Get the number of files in the fileset */ 2416 if (attr = get_attr_integer(cmd, FSA_ENTRIES)) { 2417 fileset->fs_entries = attr->attr_avd; 2418 } else { 2419 filebench_log(LOG_ERROR, "Fileset has zero entries"); 2420 fileset->fs_entries = avd_int_alloc(0); 2421 } 2422 2423 /* Get the mean dir width of the fileset */ 2424 if (attr = get_attr_integer(cmd, FSA_DIRWIDTH)) { 2425 fileset->fs_dirwidth = attr->attr_avd; 2426 } else { 2427 filebench_log(LOG_ERROR, "Fileset has zero directory width"); 2428 fileset->fs_dirwidth = avd_int_alloc(0); 2429 } 2430 2431 /* Get the random variable for dir depth, if supplied */ 2432 if (attr = get_attr_integer(cmd, FSA_DIRDEPTHRV)) { 2433 if (!AVD_IS_RANDOM(attr->attr_avd)) { 2434 filebench_log(LOG_ERROR, 2435 "Define fileset: dirdepthrv must be random var"); 2436 filebench_shutdown(1); 2437 } 2438 fileset->fs_dirdepthrv = attr->attr_avd; 2439 } else { 2440 fileset->fs_dirdepthrv = NULL; 2441 } 2442 2443 /* Get the gamma value for dir depth distributions */ 2444 if (attr = get_attr_integer(cmd, FSA_DIRGAMMA)) { 2445 if (AVD_IS_RANDOM(attr->attr_avd)) { 2446 filebench_log(LOG_ERROR, 2447 "Define fileset: dirgamma attr cannot be random"); 2448 filebench_shutdown(1); 2449 } 2450 fileset->fs_dirgamma = attr->attr_avd; 2451 } else 2452 fileset->fs_dirgamma = avd_int_alloc(1500); 2453 2454 /* Get the gamma value for dir width distributions */ 2455 if (attr = get_attr_integer(cmd, FSA_FILESIZEGAMMA)) { 2456 if (AVD_IS_RANDOM(attr->attr_avd)) { 2457 filebench_log(LOG_ERROR, 2458 "Define fileset: filesizegamma cannot be random"); 2459 filebench_shutdown(1); 2460 } 2461 fileset->fs_sizegamma = attr->attr_avd; 2462 } else 2463 fileset->fs_sizegamma = avd_int_alloc(1500); 2464 } 2465 2466 /* 2467 * Creates and starts all defined procflow processes. The call to 2468 * procflow_init() results in creation of the requested number of 2469 * process instances for each previously defined procflow. The 2470 * child processes exec() a new instance of filebench, passing it 2471 * the instance number and address of the shared memory region. 2472 * The child processes will then create their threads and flowops. 2473 * The routine then unlocks the run_lock to allow all the processes' 2474 * threads to start and waits for all of them to begin execution. 2475 * Finally, it records the start time and resets the event generation 2476 * system. 2477 */ 2478 static void 2479 parser_proc_create(cmd_t *cmd) 2480 { 2481 filebench_shm->shm_1st_err = 0; 2482 if (procflow_init() != 0) { 2483 filebench_log(LOG_ERROR, "Failed to create processes\n"); 2484 filebench_shutdown(1); 2485 } 2486 2487 /* Release the read lock, allowing threads to start */ 2488 (void) pthread_rwlock_unlock(&filebench_shm->run_lock); 2489 2490 /* Wait for all threads to start */ 2491 if (procflow_allstarted() != 0) { 2492 filebench_log(LOG_ERROR, "Could not start run"); 2493 return; 2494 } 2495 2496 2497 if (filebench_shm->shm_required && 2498 (ipc_ismcreate(filebench_shm->shm_required) < 0)) { 2499 filebench_log(LOG_ERROR, "Could not allocate shared memory"); 2500 return; 2501 } 2502 2503 filebench_shm->starttime = gethrtime(); 2504 eventgen_reset(); 2505 } 2506 2507 /* 2508 * Calls fileset_createset() to populate all files and filesets and 2509 * create all associated, initially existant, files and subdirectories. 2510 * If errors are encountered, calls filebench_shutdown() 2511 * to exit filebench. 2512 */ 2513 static void 2514 parser_fileset_create(cmd_t *cmd) 2515 { 2516 if (!filecreate_done) { 2517 filecreate_done = 1; 2518 2519 /* initialize the random number system first */ 2520 randdist_init(); 2521 2522 /* create all the filesets */ 2523 if (fileset_createset(NULL) != 0) { 2524 filebench_log(LOG_ERROR, "Failed to create filesets"); 2525 filebench_shutdown(1); 2526 } 2527 } else { 2528 filebench_log(LOG_INFO, 2529 "Attempting to create fileset more than once, ignoring"); 2530 } 2531 2532 } 2533 2534 /* 2535 * Shuts down all processes and their associated threads. When finished 2536 * it deletes interprocess shared memory and resets the event generator. 2537 * It does not exit the filebench program though. 2538 */ 2539 static void 2540 parser_proc_shutdown(cmd_t *cmd) 2541 { 2542 filebench_log(LOG_INFO, "Shutting down processes"); 2543 filecreate_done = 0; 2544 procflow_shutdown(); 2545 if (filebench_shm->shm_required) 2546 ipc_ismdelete(); 2547 eventgen_reset(); 2548 } 2549 2550 /* 2551 * Ends filebench run after first destoring any interprocess 2552 * shared memory. The call to filebench_shutdown() 2553 * also causes filebench to exit. 2554 */ 2555 static void 2556 parser_filebench_shutdown(cmd_t *cmd) 2557 { 2558 ipc_cleanup(); 2559 filebench_shutdown(1); 2560 } 2561 2562 /* 2563 * This is Used for timing runs.Pauses the master thread in one second 2564 * intervals until the supplied ptime runs out or the f_abort flag 2565 * is raised. If given a time of zero or less, or the mode is stop on 2566 * lack of resources, it will pause until f_abort is raised. 2567 */ 2568 static void 2569 parser_pause(int ptime) 2570 { 2571 int timeslept = 0; 2572 2573 if ((filebench_shm->shm_rmode == FILEBENCH_MODE_TIMEOUT) && 2574 (ptime > 0)) { 2575 while (timeslept < ptime) { 2576 (void) sleep(1); 2577 timeslept++; 2578 if (filebench_shm->f_abort) 2579 break; 2580 } 2581 } else { 2582 /* initial runtime of 0 means run till abort */ 2583 /* CONSTCOND */ 2584 while (1) { 2585 (void) sleep(1); 2586 timeslept++; 2587 if (filebench_shm->f_abort) 2588 break; 2589 } 2590 } 2591 2592 filebench_log(LOG_INFO, "Run took %d seconds...", timeslept); 2593 } 2594 2595 /* 2596 * Do a file bench run. Calls routines to create file sets, files, and 2597 * processes. It resets the statistics counters, then sleeps for the runtime 2598 * passed as an argument to it on the command line in 1 second increments. 2599 * When it is finished sleeping, it collects a snapshot of the statistics 2600 * and ends the run. 2601 */ 2602 static void 2603 parser_run(cmd_t *cmd) 2604 { 2605 int runtime; 2606 2607 runtime = cmd->cmd_qty; 2608 2609 parser_fileset_create(cmd); 2610 parser_proc_create(cmd); 2611 2612 /* check for startup errors */ 2613 if (filebench_shm->f_abort) 2614 return; 2615 2616 filebench_log(LOG_INFO, "Running..."); 2617 stats_clear(); 2618 2619 parser_pause(runtime); 2620 2621 parser_statssnap(cmd); 2622 parser_proc_shutdown(cmd); 2623 } 2624 2625 /* 2626 * Similar to parser_run, but gets the sleep time from a variable 2627 * whose name is supplied as an argument to the command. 2628 */ 2629 static void 2630 parser_run_variable(cmd_t *cmd) 2631 { 2632 avd_t integer = var_ref_attr(cmd->cmd_tgt1); 2633 int runtime; 2634 2635 if (integer == NULL) { 2636 filebench_log(LOG_ERROR, "Unknown variable %s", 2637 cmd->cmd_tgt1); 2638 return; 2639 } 2640 2641 runtime = avd_get_int(integer); 2642 2643 /* check for startup errors */ 2644 if (filebench_shm->f_abort) 2645 return; 2646 2647 filebench_log(LOG_INFO, "Running..."); 2648 stats_clear(); 2649 2650 parser_pause(runtime); 2651 2652 parser_statssnap(cmd); 2653 parser_proc_shutdown(cmd); 2654 } 2655 2656 char *usagestr = NULL; 2657 2658 /* 2659 * Prints usage string if defined, else just a message requesting load of a 2660 * personality. 2661 */ 2662 static void 2663 parser_help(cmd_t *cmd) 2664 { 2665 int runtime; 2666 2667 if (usagestr) { 2668 filebench_log(LOG_INFO, "%s", usagestr); 2669 } else { 2670 filebench_log(LOG_INFO, 2671 "load <personality> (ls " 2672 "/usr/benchmarks/filebench/workloads for list)"); 2673 } 2674 } 2675 2676 char *varstr = NULL; 2677 2678 /* 2679 * Prints the string of all var definitions, if there is one. 2680 */ 2681 static void 2682 parser_printvars(cmd_t *cmd) 2683 { 2684 int runtime; 2685 char *str, *c; 2686 2687 if (varstr) { 2688 str = strdup(varstr); 2689 for (c = str; *c != '\0'; c++) { 2690 if ((char)*c == '$') 2691 *c = ' '; 2692 } 2693 filebench_log(LOG_INFO, "%s", str); 2694 free(str); 2695 } 2696 } 2697 2698 /* 2699 * Used by the SET command to add a var and default value string to the 2700 * varstr string. It allocates a new, larger varstr string, copies the 2701 * old contents of varstr into it, then adds the new var string on the end. 2702 */ 2703 static void 2704 parser_vars(cmd_t *cmd) 2705 { 2706 char *string = cmd->cmd_tgt1; 2707 char *newvars; 2708 2709 if (string == NULL) 2710 return; 2711 2712 if (dofile) 2713 return; 2714 2715 if (varstr == NULL) { 2716 newvars = malloc(strlen(string) + 2); 2717 *newvars = 0; 2718 } else { 2719 newvars = malloc(strlen(varstr) + strlen(string) + 2); 2720 (void) strcpy(newvars, varstr); 2721 } 2722 (void) strcat(newvars, string); 2723 (void) strcat(newvars, " "); 2724 2725 if (varstr) 2726 free(varstr); 2727 2728 varstr = newvars; 2729 } 2730 2731 /* 2732 * Sleeps for cmd->cmd_qty seconds, one second at a time. 2733 */ 2734 static void 2735 parser_sleep(cmd_t *cmd) 2736 { 2737 int sleeptime; 2738 2739 /* check for startup errors */ 2740 if (filebench_shm->f_abort) 2741 return; 2742 2743 sleeptime = cmd->cmd_qty; 2744 filebench_log(LOG_INFO, "Running..."); 2745 2746 parser_pause(sleeptime); 2747 } 2748 2749 /* 2750 * used by the set command to set the integer part of a regular 2751 * variable, or the appropriate field of a random variable 2752 */ 2753 static void 2754 parser_set_integer(char *name, fbint_t integer) 2755 { 2756 var_assign_integer(name, integer); 2757 } 2758 2759 /* 2760 * used by the set command to set the integer part of a regular 2761 * variable from another variable, or the appropriate field of a 2762 * random variable from another variable 2763 */ 2764 static void 2765 parser_set_var(char *dst_name, char *src_name) 2766 { 2767 var_assign_var(dst_name, src_name); 2768 } 2769 2770 2771 /* 2772 * Same as parser_sleep, except the sleep time is obtained from a variable 2773 * whose name is passed to it as an argument on the command line. 2774 */ 2775 static void 2776 parser_sleep_variable(cmd_t *cmd) 2777 { 2778 avd_t integer = var_ref_attr(cmd->cmd_tgt1); 2779 int sleeptime; 2780 2781 if (integer == NULL) { 2782 filebench_log(LOG_ERROR, "Unknown variable %s", 2783 cmd->cmd_tgt1); 2784 return; 2785 } 2786 2787 sleeptime = avd_get_int(integer); 2788 2789 /* check for startup errors */ 2790 if (filebench_shm->f_abort) 2791 return; 2792 2793 filebench_log(LOG_INFO, "Running..."); 2794 2795 parser_pause(sleeptime); 2796 } 2797 2798 /* 2799 * Parser log prints the values of a list of variables to the log file. 2800 * The list of variables is placed on the command line, separated 2801 * by comas and the entire list is enclosed in quotes. 2802 * For example, if $dir contains "/export/home/tmp" and $filesize = 1048576, 2803 * then typing: log "$dir, $filesize" prints: log /export/home/tmp, 1048576 2804 */ 2805 static void 2806 parser_log(cmd_t *cmd) 2807 { 2808 char *string; 2809 2810 if (cmd->cmd_param_list == NULL) 2811 return; 2812 2813 string = parser_list2string(cmd->cmd_param_list); 2814 2815 if (string == NULL) 2816 return; 2817 2818 filebench_log(LOG_VERBOSE, "log %s", string); 2819 filebench_log(LOG_LOG, "%s", string); 2820 } 2821 2822 /* 2823 * Implements the stats directory command. changes the directory for 2824 * dumping statistics to supplied directory path. For example: 2825 * stats directory /tmp 2826 * changes the stats directory to "/tmp". 2827 */ 2828 static void 2829 parser_directory(cmd_t *cmd) 2830 { 2831 char newdir[MAXPATHLEN]; 2832 char *dir; 2833 2834 if ((dir = parser_list2string(cmd->cmd_param_list)) == NULL) { 2835 filebench_log(LOG_ERROR, "Cannot interpret directory"); 2836 return; 2837 } 2838 2839 *newdir = 0; 2840 /* Change dir relative to cwd if path not fully qualified */ 2841 if (*dir != '/') { 2842 (void) strcat(newdir, cwd); 2843 (void) strcat(newdir, "/"); 2844 } 2845 (void) strcat(newdir, dir); 2846 (void) mkdir(newdir, 0755); 2847 filebench_log(LOG_VERBOSE, "Change dir to %s", newdir); 2848 chdir(newdir); 2849 free(dir); 2850 } 2851 2852 #define PIPE_PARENT 1 2853 #define PIPE_CHILD 0 2854 2855 /* 2856 * Runs the quoted unix command as a background process. Intended for 2857 * running statistics gathering utilities such as mpstat while the filebench 2858 * workload is running. Also records the pid's of the background processes 2859 * so that parser_statssnap() can terminate them when the run completes. 2860 */ 2861 static void 2862 parser_statscmd(cmd_t *cmd) 2863 { 2864 char *string; 2865 pid_t pid; 2866 pidlist_t *pidlistent; 2867 int pipe_fd[2]; 2868 int newstdout; 2869 2870 if (cmd->cmd_param_list == NULL) 2871 return; 2872 2873 string = parser_list2string(cmd->cmd_param_list); 2874 2875 if (string == NULL) 2876 return; 2877 2878 if ((pipe(pipe_fd)) < 0) { 2879 filebench_log(LOG_ERROR, "statscmd pipe failed"); 2880 return; 2881 } 2882 2883 #ifdef HAVE_FORK1 2884 if ((pid = fork1()) < 0) { 2885 filebench_log(LOG_ERROR, "statscmd fork failed"); 2886 return; 2887 } 2888 #elif HAVE_FORK 2889 if ((pid = fork()) < 0) { 2890 filebench_log(LOG_ERROR, "statscmd fork failed"); 2891 return; 2892 } 2893 #else 2894 Crash! - Need code to deal with no fork1! 2895 #endif /* HAVE_FORK1 */ 2896 2897 if (pid == 0) { 2898 2899 setsid(); 2900 2901 filebench_log(LOG_VERBOSE, 2902 "Backgrounding %s", string); 2903 /* 2904 * Child 2905 * - close stdout 2906 * - dup to create new stdout 2907 * - close pipe fds 2908 */ 2909 (void) close(1); 2910 2911 if ((newstdout = dup(pipe_fd[PIPE_CHILD])) < 0) { 2912 filebench_log(LOG_ERROR, 2913 "statscmd dup failed: %s", 2914 strerror(errno)); 2915 } 2916 2917 (void) close(pipe_fd[PIPE_PARENT]); 2918 (void) close(pipe_fd[PIPE_CHILD]); 2919 2920 if (system(string) < 0) { 2921 filebench_log(LOG_ERROR, 2922 "statscmd exec failed: %s", 2923 strerror(errno)); 2924 } 2925 /* Failed! */ 2926 exit(1); 2927 2928 } else { 2929 2930 /* Record pid in pidlist for subsequent reaping by stats snap */ 2931 if ((pidlistent = (pidlist_t *)malloc(sizeof (pidlist_t))) 2932 == NULL) { 2933 filebench_log(LOG_ERROR, "pidlistent malloc failed"); 2934 return; 2935 } 2936 2937 pidlistent->pl_pid = pid; 2938 pidlistent->pl_fd = pipe_fd[PIPE_PARENT]; 2939 (void) close(pipe_fd[PIPE_CHILD]); 2940 2941 /* Add fileobj to global list */ 2942 if (pidlist == NULL) { 2943 pidlist = pidlistent; 2944 pidlistent->pl_next = NULL; 2945 } else { 2946 pidlistent->pl_next = pidlist; 2947 pidlist = pidlistent; 2948 } 2949 } 2950 } 2951 2952 /* 2953 * Launches a shell to run the unix command supplied in the argument. 2954 * The command should be enclosed in quotes, as in: 2955 * system "rm xyz" 2956 * which would run the "rm" utility to delete the file "xyz". 2957 */ 2958 static void 2959 parser_system(cmd_t *cmd) 2960 { 2961 char *string; 2962 2963 if (cmd->cmd_param_list == NULL) 2964 return; 2965 2966 string = parser_list2string(cmd->cmd_param_list); 2967 2968 if (string == NULL) 2969 return; 2970 2971 filebench_log(LOG_VERBOSE, 2972 "Running '%s'", string); 2973 2974 if (system(string) < 0) { 2975 filebench_log(LOG_ERROR, 2976 "system exec failed: %s", 2977 strerror(errno)); 2978 } 2979 free(string); 2980 } 2981 2982 /* 2983 * Echos string supplied with command to the log. 2984 */ 2985 static void 2986 parser_echo(cmd_t *cmd) 2987 { 2988 char *string; 2989 2990 if (cmd->cmd_param_list == NULL) 2991 return; 2992 2993 string = parser_list2string(cmd->cmd_param_list); 2994 2995 if (string == NULL) 2996 return; 2997 2998 filebench_log(LOG_INFO, "%s", string); 2999 } 3000 3001 3002 /* 3003 * Adds the string supplied as the argument to the usage command 3004 * to the end of the string printed by the help command. 3005 */ 3006 static void 3007 parser_usage(cmd_t *cmd) 3008 { 3009 char *string; 3010 char *newusage; 3011 3012 if (cmd->cmd_param_list == NULL) 3013 return; 3014 3015 string = parser_list2string(cmd->cmd_param_list); 3016 3017 if (string == NULL) 3018 return; 3019 3020 if (dofile) 3021 return; 3022 3023 if (usagestr == NULL) { 3024 newusage = malloc(strlen(string) + 2); 3025 *newusage = 0; 3026 } else { 3027 newusage = malloc(strlen(usagestr) + strlen(string) + 2); 3028 (void) strcpy(newusage, usagestr); 3029 } 3030 (void) strcat(newusage, "\n"); 3031 (void) strcat(newusage, string); 3032 3033 if (usagestr) 3034 free(usagestr); 3035 3036 usagestr = newusage; 3037 3038 filebench_log(LOG_INFO, "%s", string); 3039 } 3040 3041 /* 3042 * Updates the global dump filename with the filename supplied 3043 * as the command's argument. Then dumps the statistics of each 3044 * worker flowop into the dump file, followed by a summary of 3045 * overall totals. 3046 */ 3047 static void 3048 parser_statsdump(cmd_t *cmd) 3049 { 3050 char *string; 3051 3052 if (cmd->cmd_param_list == NULL) 3053 return; 3054 3055 string = parser_list2string(cmd->cmd_param_list); 3056 3057 if (string == NULL) 3058 return; 3059 3060 filebench_log(LOG_VERBOSE, 3061 "Stats dump to file '%s'", string); 3062 3063 stats_dump(string); 3064 3065 free(string); 3066 } 3067 3068 /* 3069 * Same as parser_statsdump, but in xml format. 3070 */ 3071 static void 3072 parser_statsxmldump(cmd_t *cmd) 3073 { 3074 char *string; 3075 3076 if (cmd->cmd_param_list == NULL) 3077 return; 3078 3079 string = parser_list2string(cmd->cmd_param_list); 3080 3081 if (string == NULL) 3082 return; 3083 3084 filebench_log(LOG_VERBOSE, 3085 "Stats dump to file '%s'", string); 3086 3087 stats_xmldump(string); 3088 3089 free(string); 3090 } 3091 3092 /* 3093 * Kills off background statistics collection processes, then takes a snapshot 3094 * of the filebench run's collected statistics using stats_snap() from 3095 * stats.c. 3096 */ 3097 static void 3098 parser_statssnap(cmd_t *cmd) 3099 { 3100 pidlist_t *pidlistent; 3101 int stat; 3102 pid_t pid; 3103 3104 for (pidlistent = pidlist; pidlistent != NULL; 3105 pidlistent = pidlistent->pl_next) { 3106 filebench_log(LOG_VERBOSE, "Killing session %d for pid %d", 3107 getsid(pidlistent->pl_pid), 3108 pidlistent->pl_pid); 3109 if (pidlistent->pl_fd) 3110 (void) close(pidlistent->pl_fd); 3111 #ifdef HAVE_SIGSEND 3112 sigsend(P_SID, getsid(pidlistent->pl_pid), SIGTERM); 3113 #else 3114 (void) kill(-1, SIGTERM); 3115 #endif 3116 3117 /* Close pipe */ 3118 if (pidlistent->pl_fd) 3119 (void) close(pidlistent->pl_fd); 3120 3121 /* Wait for cmd and all its children */ 3122 while ((pid = waitpid(pidlistent->pl_pid * -1, &stat, 0)) > 0) 3123 filebench_log(LOG_DEBUG_IMPL, 3124 "Waited for pid %d", (int)pid); 3125 } 3126 3127 for (pidlistent = pidlist; pidlistent != NULL; 3128 pidlistent = pidlistent->pl_next) { 3129 free(pidlistent); 3130 } 3131 3132 pidlist = NULL; 3133 stats_snap(); 3134 } 3135 3136 /* 3137 * Shutdown filebench. 3138 */ 3139 static void 3140 parser_abort(int arg) 3141 { 3142 (void) sigignore(SIGINT); 3143 filebench_log(LOG_INFO, "Aborting..."); 3144 filebench_shutdown(1); 3145 } 3146 3147 /* 3148 * define a random variable and initialize the distribution parameters 3149 */ 3150 static void 3151 parser_randvar_define(cmd_t *cmd) 3152 { 3153 var_t *var; 3154 randdist_t *rndp; 3155 attr_t *attr; 3156 char *name; 3157 3158 /* Get the name for the random variable */ 3159 if (attr = get_attr(cmd, FSA_NAME)) { 3160 name = avd_get_str(attr->attr_avd); 3161 } else { 3162 filebench_log(LOG_ERROR, 3163 "define randvar: no name specified"); 3164 return; 3165 } 3166 3167 if ((var = var_define_randvar(name)) == NULL) { 3168 filebench_log(LOG_ERROR, 3169 "define randvar: failed for random variable %s", 3170 name); 3171 return; 3172 } 3173 3174 rndp = var->var_val.randptr; 3175 rndp->rnd_type = 0; 3176 3177 /* Get the source of the random numbers */ 3178 if (attr = get_attr_integer(cmd, FSA_RANDSRC)) { 3179 int randsrc = (int)avd_get_int(attr->attr_avd); 3180 3181 switch (randsrc) { 3182 case FSV_URAND: 3183 rndp->rnd_type |= RAND_SRC_URANDOM; 3184 break; 3185 case FSV_RAND48: 3186 rndp->rnd_type |= RAND_SRC_GENERATOR; 3187 break; 3188 } 3189 } else { 3190 /* default to rand48 random number generator */ 3191 rndp->rnd_type |= RAND_SRC_GENERATOR; 3192 } 3193 3194 /* Get the min value of the random distribution */ 3195 if (attr = get_attr_integer(cmd, FSA_RANDMIN)) 3196 rndp->rnd_min = attr->attr_avd; 3197 else 3198 rndp->rnd_min = avd_int_alloc(0); 3199 3200 /* Get the mean value of the random distribution */ 3201 if (attr = get_attr_integer(cmd, FSA_RANDMEAN)) 3202 rndp->rnd_mean = attr->attr_avd; 3203 else 3204 rndp->rnd_mean = avd_int_alloc(0); 3205 3206 /* Get the roundoff value for the random distribution */ 3207 if (attr = get_attr_integer(cmd, FSA_RANDROUND)) 3208 rndp->rnd_round = attr->attr_avd; 3209 else 3210 rndp->rnd_round = avd_int_alloc(0); 3211 3212 /* Get a tablular probablility distribution if there is one */ 3213 if (attr = get_attr(cmd, FSA_RANDTABLE)) { 3214 rndp->rnd_probtabs = (probtabent_t *)(attr->attr_obj); 3215 rndp->rnd_type |= RAND_TYPE_TABLE; 3216 3217 /* no need for the rest of the attributes */ 3218 return; 3219 } else { 3220 rndp->rnd_probtabs = NULL; 3221 } 3222 3223 /* Get the type for the random variable */ 3224 if (attr = get_attr(cmd, FSA_TYPE)) { 3225 int disttype = (int)avd_get_int(attr->attr_avd); 3226 3227 switch (disttype) { 3228 case FSV_RANDUNI: 3229 rndp->rnd_type |= RAND_TYPE_UNIFORM; 3230 break; 3231 case FSA_RANDGAMMA: 3232 rndp->rnd_type |= RAND_TYPE_GAMMA; 3233 break; 3234 case FSV_RANDTAB: 3235 filebench_log(LOG_ERROR, 3236 "Table distribution type without prob table"); 3237 break; 3238 } 3239 } else { 3240 /* default to gamma distribution type */ 3241 rndp->rnd_type |= RAND_TYPE_GAMMA; 3242 } 3243 3244 /* Get the seed for the random variable */ 3245 if (attr = get_attr_integer(cmd, FSA_RANDSEED)) 3246 rndp->rnd_seed = attr->attr_avd; 3247 else 3248 rndp->rnd_seed = avd_int_alloc(0); 3249 3250 /* Get the gamma value of the random distribution */ 3251 if (attr = get_attr_integer(cmd, FSA_RANDGAMMA)) 3252 rndp->rnd_gamma = attr->attr_avd; 3253 else 3254 rndp->rnd_gamma = avd_int_alloc(1500); 3255 } 3256 3257 /* 3258 * Set a specified random distribution parameter in a random variable. 3259 */ 3260 static void 3261 parser_randvar_set(cmd_t *cmd) 3262 { 3263 var_t *src_var, *randvar; 3264 randdist_t *rndp; 3265 avd_t value; 3266 3267 if ((randvar = var_find_randvar(cmd->cmd_tgt1)) == NULL) { 3268 filebench_log(LOG_ERROR, 3269 "set randvar: failed", 3270 cmd->cmd_tgt1); 3271 return; 3272 } 3273 3274 rndp = randvar->var_val.randptr; 3275 value = cmd->cmd_attr_list->attr_avd; 3276 3277 switch (cmd->cmd_qty) { 3278 case FSS_TYPE: 3279 { 3280 int disttype = (int)avd_get_int(value); 3281 3282 printf("parser_randvar_set: changing type to %d\n", 3283 disttype); 3284 rndp->rnd_type &= (~RAND_TYPE_MASK); 3285 3286 switch (disttype) { 3287 case FSV_RANDUNI: 3288 rndp->rnd_type |= RAND_TYPE_UNIFORM; 3289 break; 3290 case FSA_RANDGAMMA: 3291 rndp->rnd_type |= RAND_TYPE_GAMMA; 3292 break; 3293 case FSV_RANDTAB: 3294 rndp->rnd_type |= RAND_TYPE_TABLE; 3295 break; 3296 } 3297 break; 3298 } 3299 3300 case FSS_SRC: 3301 { 3302 int randsrc = (int)avd_get_int(value); 3303 3304 printf("parser_randvar_set: changing source to %d\n", 3305 randsrc); 3306 3307 rndp->rnd_type &= 3308 (~(RAND_SRC_URANDOM | RAND_SRC_GENERATOR)); 3309 3310 switch (randsrc) { 3311 case FSV_URAND: 3312 rndp->rnd_type |= RAND_SRC_URANDOM; 3313 break; 3314 case FSV_RAND48: 3315 rndp->rnd_type |= RAND_SRC_GENERATOR; 3316 break; 3317 } 3318 break; 3319 } 3320 3321 case FSS_SEED: 3322 rndp->rnd_seed = value; 3323 break; 3324 3325 case FSS_GAMMA: 3326 rndp->rnd_gamma = value; 3327 break; 3328 3329 case FSS_MEAN: 3330 rndp->rnd_mean = value; 3331 break; 3332 3333 case FSS_MIN: 3334 rndp->rnd_min = value; 3335 break; 3336 3337 case FSS_ROUND: 3338 rndp->rnd_round = value; 3339 break; 3340 3341 default: 3342 filebench_log(LOG_ERROR, "setrandvar: undefined attribute"); 3343 } 3344 } 3345 3346 /* 3347 * alloc_cmd() allocates the required resources for a cmd_t. On failure, a 3348 * filebench_log is issued and NULL is returned. 3349 */ 3350 static cmd_t * 3351 alloc_cmd(void) 3352 { 3353 cmd_t *cmd; 3354 3355 if ((cmd = malloc(sizeof (cmd_t))) == NULL) { 3356 filebench_log(LOG_ERROR, "Alloc cmd failed"); 3357 return (NULL); 3358 } 3359 3360 (void) memset(cmd, 0, sizeof (cmd_t)); 3361 3362 return (cmd); 3363 } 3364 3365 /* 3366 * Frees the resources of a cmd_t and then the cmd_t "cmd" itself. 3367 */ 3368 static void 3369 free_cmd(cmd_t *cmd) 3370 { 3371 free((void *)cmd->cmd_tgt1); 3372 free((void *)cmd->cmd_tgt2); 3373 free(cmd); 3374 } 3375 3376 /* 3377 * Allocates an attr_t structure and zeros it. Returns NULL on failure, or 3378 * a pointer to the attr_t. 3379 */ 3380 static attr_t * 3381 alloc_attr() 3382 { 3383 attr_t *attr; 3384 3385 if ((attr = malloc(sizeof (attr_t))) == NULL) { 3386 return (NULL); 3387 } 3388 3389 (void) memset(attr, 0, sizeof (attr_t)); 3390 return (attr); 3391 } 3392 3393 /* 3394 * Allocates a probtabent_t structure and zeros it. Returns NULL on failure, or 3395 * a pointer to the probtabent_t. 3396 */ 3397 static probtabent_t * 3398 alloc_probtabent(void) 3399 { 3400 probtabent_t *rte; 3401 3402 if ((rte = malloc(sizeof (probtabent_t))) == NULL) { 3403 return (NULL); 3404 } 3405 3406 (void) memset(rte, 0, sizeof (probtabent_t)); 3407 return (rte); 3408 } 3409 3410 /* 3411 * Searches the attribute list for the command for the named attribute type. 3412 * The attribute list is created by the parser from the list of attributes 3413 * supplied with certain commands, such as the define and flowop commands. 3414 * Returns a pointer to the attribute structure if the named attribute is 3415 * found, otherwise returns NULL. If the attribute includes a parameter list, 3416 * the list is converted to a string and stored in the attr_avd field of 3417 * the returned attr_t struct. 3418 */ 3419 static attr_t * 3420 get_attr(cmd_t *cmd, int64_t name) 3421 { 3422 attr_t *attr; 3423 attr_t *rtn = NULL; 3424 char *string; 3425 3426 for (attr = cmd->cmd_attr_list; attr != NULL; 3427 attr = attr->attr_next) { 3428 filebench_log(LOG_DEBUG_IMPL, 3429 "attr %d = %d %llx?", 3430 attr->attr_name, 3431 name, 3432 attr->attr_avd); 3433 3434 if (attr->attr_name == name) 3435 rtn = attr; 3436 } 3437 3438 if (rtn == NULL) 3439 return (NULL); 3440 3441 if (rtn->attr_param_list) { 3442 filebench_log(LOG_DEBUG_SCRIPT, "attr is param list"); 3443 string = parser_list2string(rtn->attr_param_list); 3444 if (string != NULL) { 3445 rtn->attr_avd = avd_str_alloc(string); 3446 filebench_log(LOG_DEBUG_SCRIPT, 3447 "attr string %s", string); 3448 } 3449 } 3450 3451 return (rtn); 3452 } 3453 3454 /* 3455 * Similar to get_attr, but converts the parameter string supplied with the 3456 * named attribute to an integer and stores the integer in the attr_avd 3457 * portion of the returned attr_t struct. 3458 */ 3459 static attr_t * 3460 get_attr_integer(cmd_t *cmd, int64_t name) 3461 { 3462 attr_t *attr; 3463 attr_t *rtn = NULL; 3464 3465 for (attr = cmd->cmd_attr_list; attr != NULL; 3466 attr = attr->attr_next) { 3467 if (attr->attr_name == name) 3468 rtn = attr; 3469 } 3470 3471 if (rtn == NULL) 3472 return (NULL); 3473 3474 if (rtn->attr_param_list) 3475 rtn->attr_avd = parser_list2avd(rtn->attr_param_list); 3476 3477 return (rtn); 3478 } 3479 3480 /* 3481 * Similar to get_attr, but converts the parameter string supplied with the 3482 * named attribute to an integer and stores the integer in the attr_avd 3483 * portion of the returned attr_t struct. If no parameter string is supplied 3484 * then it defaults to TRUE (1). 3485 */ 3486 static attr_t * 3487 get_attr_bool(cmd_t *cmd, int64_t name) 3488 { 3489 attr_t *attr; 3490 attr_t *rtn = NULL; 3491 3492 for (attr = cmd->cmd_attr_list; attr != NULL; 3493 attr = attr->attr_next) { 3494 if (attr->attr_name == name) 3495 rtn = attr; 3496 } 3497 3498 if (rtn == NULL) 3499 return (NULL); 3500 3501 if (rtn->attr_param_list) { 3502 rtn->attr_avd = parser_list2avd(rtn->attr_param_list); 3503 3504 } else if (rtn->attr_avd == NULL) { 3505 rtn->attr_avd = avd_bool_alloc(TRUE); 3506 } 3507 3508 /* boolean attributes cannot point to random variables */ 3509 if (AVD_IS_RANDOM(rtn->attr_avd)) { 3510 filebench_log(LOG_ERROR, 3511 "define flowop: Boolean attr %s cannot be random", name); 3512 filebench_shutdown(1); 3513 return (NULL); 3514 } 3515 3516 return (rtn); 3517 } 3518 3519 /* 3520 * Allocates memory for a list_t structure, initializes it to zero, and 3521 * returns a pointer to it. On failure, returns NULL. 3522 */ 3523 static list_t * 3524 alloc_list() 3525 { 3526 list_t *list; 3527 3528 if ((list = malloc(sizeof (list_t))) == NULL) { 3529 return (NULL); 3530 } 3531 3532 (void) memset(list, 0, sizeof (list_t)); 3533 return (list); 3534 } 3535 3536 3537 #define USAGE1 \ 3538 "Usage:\n" \ 3539 "%s: interpret f script and generate file workload\n" \ 3540 "Options:\n" \ 3541 " [-h] Display verbose help\n" \ 3542 " [-p] Disable opening /proc to set uacct to enable truss\n" 3543 3544 #define PARSER_CMDS \ 3545 "create [files|filesets|processes]\n" \ 3546 "stats [clear|snap]\n" \ 3547 "stats command \"shell command $var1,$var2...\"\n" \ 3548 "stats directory <directory>\n" \ 3549 "sleep <sleep-value>\n" \ 3550 "quit\n\n" \ 3551 "Variables:\n" \ 3552 "set $var = value\n" \ 3553 " $var - regular variables\n" \ 3554 " ${var} - internal special variables\n" \ 3555 " $(var) - environment variables\n\n" 3556 3557 #define PARSER_EXAMPLE \ 3558 "Example:\n\n" \ 3559 "#!/usr/bin/filebench -f\n" \ 3560 "\n" \ 3561 "define file name=bigfile,path=bigfile,size=1g,prealloc,reuse\n" \ 3562 "define process name=randomizer\n" \ 3563 "{\n" \ 3564 " thread random-thread procname=randomizer\n" \ 3565 " {\n" \ 3566 " flowop read name=random-read,filename=bigfile,iosize=16k,random\n" \ 3567 " }\n" \ 3568 "}\n" \ 3569 "create files\n" \ 3570 "create processes\n" \ 3571 "stats clear\n" \ 3572 "sleep 30\n" \ 3573 "stats snap\n" 3574 3575 /* 3576 * usage() display brief or verbose help for the filebench(1) command. 3577 */ 3578 static void 3579 usage(int help) 3580 { 3581 if (help >= 1) 3582 (void) fprintf(stderr, USAGE1, cmdname); 3583 if (help >= 2) { 3584 3585 (void) fprintf(stderr, 3586 "\n'f' language definition:\n\n"); 3587 fileset_usage(); 3588 procflow_usage(); 3589 threadflow_usage(); 3590 flowoplib_usage(); 3591 eventgen_usage(); 3592 (void) fprintf(stderr, PARSER_CMDS); 3593 (void) fprintf(stderr, PARSER_EXAMPLE); 3594 } 3595 exit(E_USAGE); 3596 } 3597 3598 int 3599 yywrap() 3600 { 3601 char buf[1024]; 3602 3603 if (parentscript) { 3604 yyin = parentscript; 3605 yy_switchfilescript(yyin); 3606 parentscript = NULL; 3607 return (0); 3608 } else 3609 return (1); 3610 } 3611