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