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