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