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